Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
StandardStyledTextImager.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
7
8#include "StandardStyledTextImager.h"
9
10using namespace Stroika::Foundation;
11
12using Memory::MakeSharedPtr;
13
14using namespace Stroika::Frameworks;
15using namespace Stroika::Frameworks::Led;
16
17/*
18 ********************************************************************************
19 ************************** AbstractStyleDatabaseRep ****************************
20 ********************************************************************************
21 */
22#if qStroika_Foundation_Debug_AssertionsChecked
23void AbstractStyleDatabaseRep::Invariant_ () const
24{
25}
26#endif
27
28/*
29 ********************************************************************************
30 *************** StandardStyledTextImager::StandardStyleMarker ******************
31 ********************************************************************************
32 */
33#if qStroika_Frameworks_Led_SupportGDI
34void StandardStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, Tablet* tablet, size_t from,
35 size_t to, const TextLayoutBlock& text, const Led_Rect& drawInto, const Led_Rect& /*invalidRect*/,
36 CoordinateType useBaseLine, DistanceType* pixelsDrawn)
37{
38 RequireNotNull (imager);
39 imager->DrawSegment_ (tablet, fFontSpecification, from, to, text, drawInto, useBaseLine, pixelsDrawn);
40}
41
42void StandardStyleMarker::MeasureSegmentWidth (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from,
43 size_t to, const Led_tChar* text, DistanceType* distanceResults) const
44{
45 RequireNotNull (imager);
46 imager->MeasureSegmentWidth_ (fFontSpecification, from, to, text, distanceResults);
47}
48
49DistanceType StandardStyleMarker::MeasureSegmentHeight (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from, size_t to) const
50{
51 RequireNotNull (imager);
52 return (imager->MeasureSegmentHeight_ (fFontSpecification, from, to));
53}
54
55DistanceType StandardStyleMarker::MeasureSegmentBaseLine (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from, size_t to) const
56{
57 RequireNotNull (imager);
58 return (imager->MeasureSegmentBaseLine_ (fFontSpecification, from, to));
59}
60#endif
61
62/*
63 ********************************************************************************
64 **************** StandardStyledTextImager::StyleDatabaseRep ********************
65 ********************************************************************************
66 */
67StyleDatabaseRep::StyleDatabaseRep (TextStore& textStore)
68 : inheritedMC{textStore, GetStaticDefaultFont ()}
69{
70}
71
72vector<StyledInfoSummaryRecord> StyleDatabaseRep::GetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing) const
73{
74 MarkerVector standardStyleMarkers = GetInfoMarkers (charAfterPos, nTCharsFollowing);
75
76 vector<StyledInfoSummaryRecord> result;
77 size_t tCharsSoFar = 0;
78 size_t nStandardStyleMarkers = standardStyleMarkers.size ();
79 for (size_t i = 0; i < nStandardStyleMarkers; ++i) {
80 StandardStyleMarker* marker = standardStyleMarkers[i];
81 AssertNotNull (marker);
82 size_t markerStart;
83 size_t markerEnd;
84 marker->GetRange (&markerStart, &markerEnd);
85
86 // for i==START and END, we may have to include only partial lengths of the
87 // markers - for the INTERNAL markers, use their whole length
88 size_t length = markerEnd - markerStart;
89 if (i == 0) {
90 Assert (charAfterPos >= markerStart);
91 Assert (charAfterPos - markerStart < length);
92 length -= (charAfterPos - markerStart);
93 }
94 if (i == nStandardStyleMarkers - 1) {
95 Assert (length >= nTCharsFollowing - tCharsSoFar); // must be preserving, or shortening...
96 length = nTCharsFollowing - tCharsSoFar;
97 }
98 Assert (length > 0 or nTCharsFollowing == 0);
99 Assert (length <= nTCharsFollowing);
100 result.push_back (StyledInfoSummaryRecord (marker->fFontSpecification, length));
101 tCharsSoFar += length;
102 }
103 Assert (tCharsSoFar == nTCharsFollowing);
104 return result;
105}
106
107void StyleDatabaseRep::SetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing, const IncrementalFontSpecification& styleInfo)
108{
109 SetInfo (charAfterPos, nTCharsFollowing, styleInfo);
110}
111
112void StyleDatabaseRep::SetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing, size_t nStyleInfos, const StyledInfoSummaryRecord* styleInfos)
113{
114 size_t setAt = charAfterPos;
115 size_t lengthUsedSoFar = 0;
116 for (size_t i = 0; i < nStyleInfos and lengthUsedSoFar < nTCharsFollowing; ++i) {
117 StyledInfoSummaryRecord isr = styleInfos[i];
118 size_t length = isr.fLength;
119 Assert (nTCharsFollowing >= lengthUsedSoFar);
120 length = min (nTCharsFollowing - lengthUsedSoFar, length);
121 SetStyleInfo (setAt, length, IncrementalFontSpecification{isr});
122 setAt += length;
123 lengthUsedSoFar += length;
124 }
125}
126
127#if qStroika_Foundation_Debug_AssertionsChecked
128void StyleDatabaseRep::Invariant_ () const
129{
130 inheritedMC::Invariant_ ();
131}
132#endif
133
134#if qStroika_Frameworks_Led_SupportGDI
135/*
136 ********************************************************************************
137 ****************************** StandardStyledTextImager ************************
138 ********************************************************************************
139 */
140void StandardStyledTextImager::HookLosingTextStore ()
141{
142 inherited::HookLosingTextStore ();
143 HookLosingTextStore_ ();
144}
145
146void StandardStyledTextImager::HookLosingTextStore_ ()
147{
148 // Only if we created the styledb should we delete it. If it was set by SetStyleDatabase(), don't unset it here.
149 if (fICreatedDatabase) {
150 fICreatedDatabase = false;
151 if (fStyleDatabase.get () != nullptr) {
152 fStyleDatabase = nullptr;
153 HookStyleDatabaseChanged ();
154 }
155 }
156}
157
158void StandardStyledTextImager::HookGainedNewTextStore ()
159{
160 inherited::HookGainedNewTextStore ();
161 HookGainedNewTextStore_ ();
162}
163
164void StandardStyledTextImager::HookGainedNewTextStore_ ()
165{
166 if (fStyleDatabase == nullptr) {
167 fStyleDatabase = MakeSharedPtr<StyleDatabaseRep> (GetTextStore ());
168 fICreatedDatabase = true;
169 HookStyleDatabaseChanged ();
170 }
171}
172
173void StandardStyledTextImager::SetStyleDatabase (const shared_ptr<AbstractStyleDatabaseRep>& styleDatabase)
174{
175 fStyleDatabase = styleDatabase;
176 fICreatedDatabase = false;
177 if (fStyleDatabase == nullptr and PeekAtTextStore () != nullptr) {
178 fStyleDatabase = MakeSharedPtr<StyleDatabaseRep> (GetTextStore ());
179 fICreatedDatabase = true;
180 }
181 HookStyleDatabaseChanged ();
182}
183
184/*
185@METHOD: StandardStyledTextImager::HookStyleDatabaseChanged
186@DESCRIPTION: <p>Called whenever the @'StyleDatabasePtr' associated with this @'StandardStyledTextImager'
187 is changed. This means when a new one is provided, created, or disassociated. It does NOT mean that its called when any of the
188 data in the style database changes.</p>
189*/
190void StandardStyledTextImager::HookStyleDatabaseChanged ()
191{
192}
193
194FontMetrics StandardStyledTextImager::GetFontMetricsAt (size_t charAfterPos) const
195{
196 Tablet_Acquirer tablet (this);
197 AssertNotNull (static_cast<Tablet*> (tablet));
198
199 FontCacheInfoUpdater fontCacheUpdater (this, tablet, GetStyleInfo (charAfterPos));
200 return (fontCacheUpdater.GetMetrics ());
201}
202
203/*
204@METHOD: StandardStyledTextImager::GetDefaultSelectionFont
205@DESCRIPTION: <p>Override @'TextImager::GetDefaultSelectionFont'.</p>
206*/
207FontSpecification StandardStyledTextImager::GetDefaultSelectionFont () const
208{
209 vector<StyledInfoSummaryRecord> summaryInfo = GetStyleInfo (GetSelectionEnd (), 0);
210 Assert (summaryInfo.size () == 1);
211 return summaryInfo[0];
212}
213
214/*
215@METHOD: StandardStyledTextImager::GetContinuousStyleInfo
216@DESCRIPTION: <p>Create a @'IncrementalFontSpecification' with set as valid all attributes which apply to all of the text from
217 <code>'from'</code> for <code>'nTChars'</code>.</p>
218 <p>So for example - if all text in that range has the same face, but different font sizes, then the face attribute will be
219 valid (and set to that common face) and the font size attribute will be set invalid.</p>
220 <p>This is useful for setting menus checked or unchecked in a typical word processor font menu.</p>
221*/
222IncrementalFontSpecification StandardStyledTextImager::GetContinuousStyleInfo (size_t from, size_t nTChars) const
223{
224 vector<StyledInfoSummaryRecord> summaryInfo = GetStyleInfo (from, nTChars);
225 return (GetContinuousStyleInfo_ (summaryInfo));
226}
227
228IncrementalFontSpecification StandardStyledTextImager::GetContinuousStyleInfo_ (const vector<StyledInfoSummaryRecord>& summaryInfo) const
229{
230 IncrementalFontSpecification fontSpec;
231
232 // There are only a certain number of font attributes which can be shared among these InfoSummaryRecords.
233 // Each time we note one which cannot be shared - we decrement this count. That way - when we know there can be
234 // no shared values - we stop comparing.
235 //
236 // countOfValidThings is a hack to see if we can skip out of for-loop early without a lot of expensive, and
237 // redundant tests.
238 //
239 // Note - we COULD have simply checked at the end of each loop count a bunch of 'IsValid' booleans. That would have
240 // been simpler. But it would have been more costly (performance).
241 int countOfValidThings = 7 +
242#if qStroika_Platform_Windows
243 1
244#endif
245 ;
246
247 for (size_t i = 0; i < summaryInfo.size (); ++i) {
248 if (i == 0) {
249 fontSpec = IncrementalFontSpecification{summaryInfo[0]};
250 }
251 else {
252 // check each attribute (if not already different) and see if NOW different...
253
254 StyledInfoSummaryRecord isr = summaryInfo[i];
255
256 // Font ID
257 if (fontSpec.GetFontNameSpecifier_Valid () and fontSpec.GetFontNameSpecifier () != isr.GetFontNameSpecifier ()) {
258 fontSpec.InvalidateFontNameSpecifier ();
259 if (--countOfValidThings == 0) {
260 break;
261 }
262 }
263
264 // Style Info
265 if (fontSpec.GetStyle_Bold_Valid () and fontSpec.GetStyle_Bold () != isr.GetStyle_Bold ()) {
266 fontSpec.InvalidateStyle_Bold ();
267 if (--countOfValidThings == 0) {
268 break;
269 }
270 }
271 if (fontSpec.GetStyle_Italic_Valid () and fontSpec.GetStyle_Italic () != isr.GetStyle_Italic ()) {
272 fontSpec.InvalidateStyle_Italic ();
273 if (--countOfValidThings == 0) {
274 break;
275 }
276 }
277 if (fontSpec.GetStyle_Underline_Valid () and fontSpec.GetStyle_Underline () != isr.GetStyle_Underline ()) {
278 fontSpec.InvalidateStyle_Underline ();
279 if (--countOfValidThings == 0) {
280 break;
281 }
282 }
283 if (fontSpec.GetStyle_SubOrSuperScript_Valid () and fontSpec.GetStyle_SubOrSuperScript () != isr.GetStyle_SubOrSuperScript ()) {
284 fontSpec.InvalidateStyle_SubOrSuperScript ();
285 if (--countOfValidThings == 0) {
286 break;
287 }
288 }
289#if qStroika_Platform_Windows
290 if (fontSpec.GetStyle_Strikeout_Valid () and fontSpec.GetStyle_Strikeout () != isr.GetStyle_Strikeout ()) {
291 fontSpec.InvalidateStyle_Strikeout ();
292 if (--countOfValidThings == 0) {
293 break;
294 }
295 }
296#endif
297
298 // Font Size
299 if (fontSpec.GetPointSize_Valid () and fontSpec.GetPointSize () != isr.GetPointSize ()) {
300 fontSpec.InvalidatePointSize ();
301 if (--countOfValidThings == 0) {
302 break;
303 }
304 }
305
306 // Font Color
307 if (fontSpec.GetTextColor_Valid () and fontSpec.GetTextColor () != isr.GetTextColor ()) {
308 fontSpec.InvalidateTextColor ();
309 if (--countOfValidThings == 0) {
310 break;
311 }
312 }
313 }
314 }
315
316 return fontSpec;
317}
318
319#if qStroika_Foundation_Debug_AssertionsChecked
320void StandardStyledTextImager::Invariant_ () const
321{
322 StyledTextImager::Invariant_ ();
323 if (fStyleDatabase.get () != nullptr) {
324 fStyleDatabase->Invariant ();
325 }
326}
327#endif
328
329#endif
#define AssertNotNull(p)
Definition Assertions.h:336
#define RequireNotNull(p)
Definition Assertions.h:350