4#include "Stroika/Frameworks/StroikaPreComp.h"
10#include "WordWrappedTextImager.h"
14using namespace Stroika::Frameworks;
15using namespace Stroika::Frameworks::Led;
17#if qStroika_Frameworks_Led_SupportGDI
19inline DistanceType LookupLengthInVector (
const DistanceType* widthsVector,
size_t startSoFar,
size_t i)
25 DistanceType startPointCorrection = (startSoFar == 0) ? 0 : widthsVector[startSoFar - 1];
26 Assert (i + startSoFar >= 1);
27 return (widthsVector[i + startSoFar - 1] - startPointCorrection);
41void WordWrappedTextImager::FillCache (PartitionMarker* pm, PartitionElementCacheInfo& cacheInfo)
50 pm->GetRange (&start, &end);
51 size_t len = end - start;
53 Assert (end <= GetEnd () + 1);
54 if (end == GetEnd () + 1) {
58 Assert (end <= GetEnd ());
61 CopyOut (start, len, buf.data ());
63 Tablet_Acquirer tablet (
this);
70 MeasureSegmentWidth (start, end, buf.data (), distanceVector.data ());
73 size_t startSoFar = 0;
74 size_t leftToGo = len - startSoFar;
82 size_t lastTabIndex = startSoFar;
84 while (leftToGo != 0) {
85 cacheInfo.IncrementRowCountAndFixCacheBuffers (startSoFar, 0);
87 if (lastTabIndex >= startSoFar) {
88 lastTabIndex = ResetTabStops (start, buf.data (), leftToGo, distanceVector.data (), startSoFar);
91 DistanceType wrapWidth;
94 CoordinateType lhsMargin;
95 CoordinateType rhsMargin;
96 GetLayoutMargins (RowReference{pm, cacheInfo.GetRowCount () - 1}, &lhsMargin, &rhsMargin);
97 Assert (lhsMargin < rhsMargin);
98 wrapWidth = rhsMargin - lhsMargin;
100 size_t bestRowLength = FindWrapPointForMeasuredText (buf.data () + startSoFar, leftToGo, wrapWidth, start + startSoFar,
101 distanceVector.data (), startSoFar);
103 Assert (bestRowLength != 0);
108 Assert (bestRowLength > 0);
109 const Led_tChar* text = buf.data () + startSoFar;
110 const Led_tChar* textEnd = &text[min (bestRowLength + 1, leftToGo)];
111 AdjustBestRowLength (start + startSoFar, text, textEnd, &bestRowLength);
112 Assert (bestRowLength > 0);
115 DistanceType newRowHeight = MeasureSegmentHeight (start + startSoFar, start + startSoFar + bestRowLength);
116 cacheInfo.SetRowHeight (cacheInfo.GetRowCount () - 1, newRowHeight);
118 startSoFar += bestRowLength;
119 Assert (len >= startSoFar);
120 leftToGo = len - startSoFar;
124 Assert (len == 0 or cacheInfo.PeekRowCount () != 0);
125 if (cacheInfo.PeekRowCount () == 0) {
127 Assert (startSoFar == 0);
128 cacheInfo.IncrementRowCountAndFixCacheBuffers (0, MeasureSegmentHeight (start, end));
131 cacheInfo.SetInterLineSpace (CalculateInterLineSpace (pm));
132 Assert (cacheInfo.GetRowCount () >= 1);
141 if (cacheInfo.PeekRowCount () == 0) {
142 cacheInfo.IncrementRowCountAndFixCacheBuffers (0, 20);
154void WordWrappedTextImager::AdjustBestRowLength (
size_t ,
const Led_tChar* text,
const Led_tChar* end,
size_t* rowLength)
156 Require (*rowLength > 0);
157 for (
const Led_tChar* cur = &text[0]; cur < end; cur = Led_NextChar (cur)) {
158 if (*cur == kSoftLineBreakChar) {
159 size_t newBestRowLength = (cur - text) + 1;
160 Assert (newBestRowLength <= *rowLength + 1);
165 Assert (newBestRowLength >= 1);
166 *rowLength = newBestRowLength;
177bool WordWrappedTextImager::ContainsMappedDisplayCharacters (
const Led_tChar* text,
size_t nTChars)
const
179 return ContainsMappedDisplayCharacters_HelperForChar (text, nTChars, kSoftLineBreakChar) or
180 inherited::ContainsMappedDisplayCharacters (text, nTChars);
187size_t WordWrappedTextImager::RemoveMappedDisplayCharacters (Led_tChar* copyText,
size_t nTChars)
const
189 size_t newLen = inherited::RemoveMappedDisplayCharacters (copyText, nTChars);
190 Assert (newLen <= nTChars);
191 size_t newerLen = RemoveMappedDisplayCharacters_HelperForChar (copyText, newLen, kSoftLineBreakChar);
192 Assert (newerLen <= newLen);
193 Assert (newerLen <= nTChars);
201void WordWrappedTextImager::PatchWidthRemoveMappedDisplayCharacters (
const Led_tChar* srcText, DistanceType* distanceResults,
size_t nTChars)
const
203 inherited::PatchWidthRemoveMappedDisplayCharacters (srcText, distanceResults, nTChars);
204 PatchWidthRemoveMappedDisplayCharacters_HelperForChar (srcText, distanceResults, nTChars, kSoftLineBreakChar);
213size_t WordWrappedTextImager::FindWrapPointForMeasuredText (
const Led_tChar* text,
size_t length, DistanceType wrapWidth,
214 size_t offsetToMarkerCoords,
const DistanceType* widthsVector,
size_t startSoFar)
217 Require (wrapWidth >= 1);
218 size_t bestRowLength = 0;
243 if (startSoFar != 0) {
251 size_t guessIndex = 0;
253 const size_t kCharsFromEndToSearchFrom = 5;
254 size_t bestBreakPointIndex = 1;
255 for (; bestBreakPointIndex <= length; ++bestBreakPointIndex) {
256 DistanceType guessWidth = LookupLengthInVector (widthsVector, startSoFar, bestBreakPointIndex);
257 if (guessWidth > wrapWidth) {
258 if (bestBreakPointIndex > 1) {
259 --bestBreakPointIndex;
262 if (bestBreakPointIndex > (kCharsFromEndToSearchFrom + 5)) {
263 Assert (bestBreakPointIndex > kCharsFromEndToSearchFrom);
264 guessIndex = bestBreakPointIndex - kCharsFromEndToSearchFrom;
270 if (bestBreakPointIndex >= length) {
271 Assert (bestBreakPointIndex <= length + 1);
272 bestRowLength = length;
273 Assert (guessIndex == 0);
276 size_t wordWrapMax = (Led_NextChar (&text[bestBreakPointIndex]) - text);
277 Assert (wordWrapMax <= length);
280 if (guessIndex != 0) {
281 bestRowLength = TryToFindWrapPointForMeasuredText1 (text, length, wrapWidth, offsetToMarkerCoords, widthsVector, startSoFar,
282 guessIndex, wordWrapMax);
284 if (bestRowLength == 0) {
285 if (bestBreakPointIndex > (kCharsFromEndToSearchFrom * 3 + 5)) {
286 guessIndex = bestBreakPointIndex - kCharsFromEndToSearchFrom * 3;
287 bestRowLength = TryToFindWrapPointForMeasuredText1 (text, length, wrapWidth, offsetToMarkerCoords, widthsVector,
288 startSoFar, guessIndex, wordWrapMax);
292 if (bestRowLength == 0) {
293 bestRowLength = TryToFindWrapPointForMeasuredText1 (text, length, wrapWidth, offsetToMarkerCoords, widthsVector, startSoFar, 0, wordWrapMax);
295 if (bestRowLength == 0) {
300 Assert (bestBreakPointIndex ==
301 FindWrapPointForOneLongWordForMeasuredText (text, length, wrapWidth, offsetToMarkerCoords, widthsVector, startSoFar));
302 bestRowLength = bestBreakPointIndex;
307 Assert (bestRowLength > 0);
308 return (bestRowLength);
311size_t WordWrappedTextImager::TryToFindWrapPointForMeasuredText1 (
const Led_tChar* text,
size_t length, DistanceType wrapWidth,
312 size_t ,
const DistanceType* widthsVector,
313 size_t startSoFar,
size_t searchStart,
size_t wrapLength)
317 Assert (wrapLength <= length);
319 shared_ptr<TextBreaks> breaker = GetTextStore ().GetTextBreaker ();
326 size_t bestRowLength = 0;
327 DistanceType width = 0;
329 bool wordReal =
false;
330 size_t lastLineTest = 0;
331 for (
size_t i = searchStart; i < wrapLength;) {
334 breaker->FindLineBreaks (text, wrapLength, i, &wordEnd, &wordReal);
336 Assert (i < wordEnd);
337 width = LookupLengthInVector (widthsVector, startSoFar, wordReal ? wordEnd : i);
341 Assert (i <= wrapLength);
349 if (width > wrapWidth) {
357 if ((not wordReal) and (wrapLength < length) and (bestRowLength != 0)) {
359 breaker->FindLineBreaks (text, length, lastLineTest, &wordEnd, &wordReal);
360 Assert (not wordReal);
361 bestRowLength = wordEnd;
364 return bestRowLength;
367size_t WordWrappedTextImager::FindWrapPointForOneLongWordForMeasuredText (
const Led_tChar* ,
size_t length, DistanceType wrapWidth,
368 size_t offsetToMarkerCoords,
const DistanceType* widthsVector,
size_t startSoFar)
370 size_t bestRowLength = 0;
376 [[maybe_unused]]
size_t secondCharIdx = FindNextCharacter (offsetToMarkerCoords + 0);
377 Assert (secondCharIdx >= offsetToMarkerCoords);
378 DistanceType fullWordWidth = LookupLengthInVector (widthsVector, startSoFar, length);
380 Assert (length >= 1);
381 size_t guessIdx = size_t ((length - 1) * (
float (wrapWidth) /
float (fullWordWidth)));
382 Assert (guessIdx < length);
388 Assert (guessIdx < length);
390 DistanceType guessWidth = LookupLengthInVector (widthsVector, startSoFar, guessIdx);
391 bestRowLength = guessIdx;
393 if (guessWidth > wrapWidth) {
395 for (
size_t j = guessIdx; j >= 1; j = FindPreviousCharacter (offsetToMarkerCoords + j) - offsetToMarkerCoords) {
397 DistanceType smallerWidth = LookupLengthInVector (widthsVector, startSoFar, j);
399 if (smallerWidth <= wrapWidth) {
406 for (
size_t j = guessIdx; j < length; j = FindNextCharacter (offsetToMarkerCoords + j) - offsetToMarkerCoords) {
408 DistanceType smallerWidth = LookupLengthInVector (widthsVector, startSoFar, j);
409 if (smallerWidth > wrapWidth) {
417 if (bestRowLength == 0) {
421 return (bestRowLength);
#define RequireNotNull(p)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...