4#include "Stroika/Frameworks/StroikaPreComp.h"
8#include "StyledTextImager.h"
11using namespace Stroika::Frameworks;
12using namespace Stroika::Frameworks::Led;
30int StyleMarker::GetPriority ()
const
32 return eBaselinePriority;
40StyleMarkerSummarySink::StyleMarkerSummarySink (
size_t from,
size_t to)
49 fBuckets.push_back (StyleRunElement{
nullptr, to - from});
53StyleMarkerSummarySink::StyleMarkerSummarySink (
size_t from,
size_t to,
const TextLayoutBlock& text)
62 fBuckets.push_back (StyleRunElement{
nullptr, to - from});
64 using ScriptRunElt = TextLayoutBlock::ScriptRunElt;
65 vector<ScriptRunElt> scriptRuns = text.GetScriptRuns ();
66 for (
auto i = scriptRuns.begin (); i != scriptRuns.end (); ++i) {
67 Assert ((*i).fRealEnd <= (to - from));
68 SplitIfNeededAt (from + (*i).fRealEnd);
72void StyleMarkerSummarySink::Append (Marker* m)
75 StyleMarker* styleMarker =
dynamic_cast<StyleMarker*
> (m);
76 if (styleMarker !=
nullptr) {
77 size_t start = max (styleMarker->GetStart (), fFrom);
78 size_t end = min (styleMarker->GetEnd (), fTo);
83 SplitIfNeededAt (start);
84 SplitIfNeededAt (end);
90 for (
auto i = fBuckets.begin (); i != fBuckets.end (); ++i) {
91 if (start <= upTo and upTo + (*i).fLength <= end) {
92 CombineElements (Traversal::Iterator2Pointer (i), styleMarker);
107void StyleMarkerSummarySink::SplitIfNeededAt (
size_t markerPos)
109 Require (markerPos >= fFrom);
110 Require (markerPos <= fTo);
112 for (
auto i = fBuckets.begin (); i != fBuckets.end (); ++i) {
113 size_t eltStart = upTo;
114 size_t eltEnd = upTo + (*i).fLength;
115 if (markerPos >= eltStart and markerPos <= eltEnd and markerPos != eltStart and markerPos != eltEnd) {
116#if qStroika_Foundation_Debug_AssertionsChecked
117 size_t oldLength = (*i).fLength;
120 StyleRunElement newElt = *i;
121 (*i).fLength = markerPos - eltStart;
122 newElt.fLength = eltEnd - markerPos;
123#if qStroika_Foundation_Debug_AssertionsChecked
124 Assert (oldLength == (*i).fLength + newElt.fLength);
126 Assert ((*i).fLength != 0);
127 Assert (newElt.fLength != 0);
128 fBuckets.insert (i + 1, newElt);
131 upTo += (*i).fLength;
151void StyleMarkerSummarySink::CombineElements (StyleRunElement* runElement, StyleMarker* newStyleMarker)
156 if (runElement->fMarker ==
nullptr) {
157 runElement->fMarker = newStyleMarker;
160 bool newEltStronger = runElement->fMarker->GetPriority () < newStyleMarker->GetPriority ();
161#if qStroika_Frameworks_Led_AssertWarningForEqualPriorityMarkers
162 Assert (runElement->fMarker->GetPriority () != newStyleMarker->GetPriority ());
164 if (newEltStronger) {
165 runElement->fSupercededMarkers.push_back (runElement->fMarker);
166 runElement->fMarker = newStyleMarker;
169 runElement->fSupercededMarkers.push_back (newStyleMarker);
181vector<StyleRunElement> StyleMarkerSummarySink::ProduceOutputSummary ()
const
183 using ScriptRunElt = TextLayoutBlock::ScriptRunElt;
186 if (fText !=
nullptr) {
187 vector<StyleRunElement> runElements;
188 vector<ScriptRunElt> scriptRuns = fText->GetScriptRuns ();
189 if (scriptRuns.size () > 1) {
191 sort (scriptRuns.begin (), scriptRuns.end (), TextLayoutBlock::LessThanVirtualStart{});
193 for (
auto i = scriptRuns.begin (); i != scriptRuns.end (); ++i) {
195 const ScriptRunElt& se = *i;
196 size_t styleRunStart = 0;
197 size_t runEltsBucketStart = runElements.size ();
198 for (
auto j = fBuckets.begin (); j != fBuckets.end (); ++j) {
199 size_t styleRunEnd = styleRunStart + (*j).fLength;
200 if (se.fRealStart <= styleRunStart and styleRunEnd <= se.fRealEnd) {
201 if (se.fDirection == eLeftToRight) {
202 runElements.push_back (*j);
205 runElements.insert (runElements.begin () + runEltsBucketStart, *j);
208 styleRunStart = styleRunEnd;
212 Ensure (runElements.size () == fBuckets.size ());
223StyleMarkerSummarySinkForSingleOwner::StyleMarkerSummarySinkForSingleOwner (
const MarkerOwner& owner,
size_t from,
size_t to)
224 : inherited{from, to}
229StyleMarkerSummarySinkForSingleOwner::StyleMarkerSummarySinkForSingleOwner (
const MarkerOwner& owner,
size_t from,
size_t to,
const TextLayoutBlock& text)
230 : inherited{from, to, text}
240void StyleMarkerSummarySinkForSingleOwner::CombineElements (StyleRunElement* runElement, StyleMarker* newStyleMarker)
245 if (runElement->fMarker ==
nullptr) {
246 runElement->fMarker = newStyleMarker;
249 bool newEltStronger = runElement->fMarker->GetPriority () < newStyleMarker->GetPriority ();
250 bool newMatchesOwner = newStyleMarker->GetOwner () == &fOwner;
251 bool oldMatchesOwner = runElement->fMarker->GetOwner () == &fOwner;
252 if (newMatchesOwner != oldMatchesOwner) {
253 newEltStronger = newMatchesOwner;
255 if (newEltStronger) {
256 runElement->fSupercededMarkers.push_back (runElement->fMarker);
257 runElement->fMarker = newStyleMarker;
260 runElement->fSupercededMarkers.push_back (newStyleMarker);
270int TrivialFontSpecStyleMarker::GetPriority ()
const
272 return eBaselinePriority + 1;
275#if qStroika_Frameworks_Led_SupportGDI
287vector<StyleRunElement> StyledTextImager::SummarizeStyleMarkers (
size_t from,
size_t to)
const
290 StyleMarkerSummarySink summary (from, to);
291 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, summary);
292 return summary.ProduceOutputSummary ();
300vector<StyleRunElement> StyledTextImager::SummarizeStyleMarkers (
size_t from,
size_t to,
const TextLayoutBlock& text)
const
302 StyleMarkerSummarySink summary (from, to, text);
303 GetTextStore ().CollectAllMarkersInRangeInto (from, to, TextStore::kAnyMarkerOwner, summary);
304 return summary.ProduceOutputSummary ();
313void StyledTextImager::DrawSegment (Tablet* tablet,
size_t from,
size_t to,
const TextLayoutBlock& text,
const Led_Rect& drawInto,
314 const Led_Rect& invalidRect, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
320 vector<StyleRunElement> outputSummary = SummarizeStyleMarkers (from, to, text);
322 Led_Rect tmpDrawInto = drawInto;
323 size_t outputSummaryLength = outputSummary.size ();
324 size_t indexIntoText_VISUAL = 0;
325 if (pixelsDrawn !=
nullptr) {
329 for (
size_t i = 0; i < outputSummaryLength; ++i) {
330 const StyleRunElement& re = outputSummary[i];
331 size_t reLength = re.fLength;
332 size_t reFrom = text.MapVirtualOffsetToReal (indexIntoText_VISUAL) + from;
333 size_t reTo = reFrom + reLength;
334 Assert (indexIntoText_VISUAL <= to - from);
335 Assert (reLength > 0);
357 const CoordinateType kSluffToLeaveRoomForOverhangs = 20;
359 if (tmpDrawInto.left - GetHScrollPos () < invalidRect.right + kSluffToLeaveRoomForOverhangs) {
360 DistanceType pixelsDrawnHere = 0;
375 tmpDrawInto.right = drawInto.right + GetHScrollPos ();
376 if (tmpDrawInto.left < tmpDrawInto.right) {
377 if (re.fMarker ==
nullptr) {
378 DrawSegment_ (tablet, GetDefaultFont (), reFrom, reTo,
379 TextLayoutBlock_VirtualSubset (text, indexIntoText_VISUAL, indexIntoText_VISUAL + reLength), tmpDrawInto,
380 useBaseLine, &pixelsDrawnHere);
383 re.fMarker->DrawSegment (
this, re, tablet, reFrom, reTo,
384 TextLayoutBlock_VirtualSubset (text, indexIntoText_VISUAL, indexIntoText_VISUAL + reLength),
385 tmpDrawInto, invalidRect, useBaseLine, &pixelsDrawnHere);
388 if (pixelsDrawn !=
nullptr) {
389 *pixelsDrawn += pixelsDrawnHere;
391 tmpDrawInto.left += pixelsDrawnHere;
393 indexIntoText_VISUAL += reLength;
397void StyledTextImager::MeasureSegmentWidth (
size_t from,
size_t to,
const Led_tChar* text, DistanceType* distanceResults)
const
400 vector<StyleRunElement> outputSummary = SummarizeStyleMarkers (from, to);
402 size_t outputSummaryLength = outputSummary.size ();
403 size_t indexIntoText = 0;
404 for (
size_t i = 0; i < outputSummaryLength; ++i) {
405 const StyleRunElement& re = outputSummary[i];
406 size_t reFrom = indexIntoText + from;
407 size_t reLength = re.fLength;
408 size_t reTo = reFrom + reLength;
409 Assert (indexIntoText <= to - from);
410 if (re.fMarker ==
nullptr) {
411 MeasureSegmentWidth_ (GetDefaultFont (), reFrom, reTo, &text[indexIntoText], &distanceResults[indexIntoText]);
414 re.fMarker->MeasureSegmentWidth (
this, re, reFrom, reTo, &text[indexIntoText], &distanceResults[indexIntoText]);
416 if (indexIntoText != 0) {
417 DistanceType addX = distanceResults[indexIntoText - 1];
418 for (
size_t j = 0; j < reLength; ++j) {
419 distanceResults[indexIntoText + j] += addX;
422 indexIntoText += reLength;
426DistanceType StyledTextImager::MeasureSegmentHeight (
size_t from,
size_t to)
const
429 Require (from <= to);
434 vector<StyleRunElement> outputSummary = SummarizeStyleMarkers (from, to);
450 size_t outputSummaryLength = outputSummary.size ();
451 Assert (outputSummaryLength != 0);
452 DistanceType maxHeightAbove = 0;
453 DistanceType maxHeightBelow = 0;
454 size_t indexIntoText = 0;
455 for (
size_t i = 0; i < outputSummaryLength; ++i) {
456 const StyleRunElement& re = outputSummary[i];
457 size_t reFrom = indexIntoText + from;
458 size_t reLength = re.fLength;
459 size_t reTo = reFrom + reLength;
460 Assert (indexIntoText <= to - from);
461 DistanceType itsBaseline;
462 DistanceType itsHeight;
463 if (re.fMarker ==
nullptr) {
464 itsBaseline = MeasureSegmentBaseLine_ (GetDefaultFont (), reFrom, reTo);
465 itsHeight = MeasureSegmentHeight_ (GetDefaultFont (), reFrom, reTo);
468 itsBaseline = re.fMarker->MeasureSegmentBaseLine (
this, re, reFrom, reTo);
469 itsHeight = re.fMarker->MeasureSegmentHeight (
this, re, reFrom, reTo);
471 maxHeightAbove = max (maxHeightAbove, itsBaseline);
472 maxHeightBelow = max (maxHeightBelow, (itsHeight - itsBaseline));
473 indexIntoText += reLength;
475 return maxHeightAbove + maxHeightBelow;
478DistanceType StyledTextImager::MeasureSegmentBaseLine (
size_t from,
size_t to)
const
481 Require (from <= to);
486 vector<StyleRunElement> outputSummary = SummarizeStyleMarkers (from, to);
487 size_t outputSummaryLength = outputSummary.size ();
488 Assert (outputSummaryLength != 0);
489 DistanceType maxHeight = 0;
490 size_t indexIntoText = 0;
491 for (
size_t i = 0; i < outputSummaryLength; ++i) {
492 const StyleRunElement& re = outputSummary[i];
493 size_t reFrom = indexIntoText + from;
494 size_t reLength = re.fLength;
495 size_t reTo = reFrom + reLength;
496 Assert (indexIntoText <= to - from);
497 if (re.fMarker ==
nullptr) {
498 maxHeight = max (maxHeight, MeasureSegmentBaseLine_ (GetDefaultFont (), reFrom, reTo));
501 maxHeight = max (maxHeight, re.fMarker->MeasureSegmentBaseLine (
this, re, reFrom, reTo));
503 indexIntoText += reLength;
508#if qStroika_Foundation_Debug_AssertionsChecked
509void StyledTextImager::Invariant_ ()
const
#define RequireNotNull(p)