Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
StandardStyledTextImager.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "StandardStyledTextImager.h"
7
8using namespace Stroika::Foundation;
9using namespace Stroika::Frameworks;
10using namespace Stroika::Frameworks::Led;
11
12/*
13 ********************************************************************************
14 ************************** AbstractStyleDatabaseRep ****************************
15 ********************************************************************************
16 */
17#if qStroika_Foundation_Debug_AssertionsChecked
18void AbstractStyleDatabaseRep::Invariant_ () const
19{
20}
21#endif
22
23/*
24 ********************************************************************************
25 *************** StandardStyledTextImager::StandardStyleMarker ******************
26 ********************************************************************************
27 */
28#if qStroika_Frameworks_Led_SupportGDI
29void StandardStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, Tablet* tablet, size_t from,
30 size_t to, const TextLayoutBlock& text, const Led_Rect& drawInto, const Led_Rect& /*invalidRect*/,
31 CoordinateType useBaseLine, DistanceType* pixelsDrawn)
32{
33 RequireNotNull (imager);
34 imager->DrawSegment_ (tablet, fFontSpecification, from, to, text, drawInto, useBaseLine, pixelsDrawn);
35}
36
37void StandardStyleMarker::MeasureSegmentWidth (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from,
38 size_t to, const Led_tChar* text, DistanceType* distanceResults) const
39{
40 RequireNotNull (imager);
41 imager->MeasureSegmentWidth_ (fFontSpecification, from, to, text, distanceResults);
42}
43
44DistanceType StandardStyleMarker::MeasureSegmentHeight (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from, size_t to) const
45{
46 RequireNotNull (imager);
47 return (imager->MeasureSegmentHeight_ (fFontSpecification, from, to));
48}
49
50DistanceType StandardStyleMarker::MeasureSegmentBaseLine (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, size_t from, size_t to) const
51{
52 RequireNotNull (imager);
53 return (imager->MeasureSegmentBaseLine_ (fFontSpecification, from, to));
54}
55#endif
56
57/*
58 ********************************************************************************
59 **************** StandardStyledTextImager::StyleDatabaseRep ********************
60 ********************************************************************************
61 */
62StyleDatabaseRep::StyleDatabaseRep (TextStore& textStore)
63 : inheritedMC{textStore, GetStaticDefaultFont ()}
64{
65}
66
67vector<StyledInfoSummaryRecord> StyleDatabaseRep::GetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing) const
68{
69 MarkerVector standardStyleMarkers = GetInfoMarkers (charAfterPos, nTCharsFollowing);
70
71 vector<StyledInfoSummaryRecord> result;
72 size_t tCharsSoFar = 0;
73 size_t nStandardStyleMarkers = standardStyleMarkers.size ();
74 for (size_t i = 0; i < nStandardStyleMarkers; ++i) {
75 StandardStyleMarker* marker = standardStyleMarkers[i];
76 AssertNotNull (marker);
77 size_t markerStart;
78 size_t markerEnd;
79 marker->GetRange (&markerStart, &markerEnd);
80
81 // for i==START and END, we may have to include only partial lengths of the
82 // markers - for the INTERNAL markers, use their whole length
83 size_t length = markerEnd - markerStart;
84 if (i == 0) {
85 Assert (charAfterPos >= markerStart);
86 Assert (charAfterPos - markerStart < length);
87 length -= (charAfterPos - markerStart);
88 }
89 if (i == nStandardStyleMarkers - 1) {
90 Assert (length >= nTCharsFollowing - tCharsSoFar); // must be preserving, or shortening...
91 length = nTCharsFollowing - tCharsSoFar;
92 }
93 Assert (length > 0 or nTCharsFollowing == 0);
94 Assert (length <= nTCharsFollowing);
95 result.push_back (StyledInfoSummaryRecord (marker->fFontSpecification, length));
96 tCharsSoFar += length;
97 }
98 Assert (tCharsSoFar == nTCharsFollowing);
99 return result;
100}
101
102void StyleDatabaseRep::SetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing, const IncrementalFontSpecification& styleInfo)
103{
104 SetInfo (charAfterPos, nTCharsFollowing, styleInfo);
105}
106
107void StyleDatabaseRep::SetStyleInfo (size_t charAfterPos, size_t nTCharsFollowing, size_t nStyleInfos, const StyledInfoSummaryRecord* styleInfos)
108{
109 size_t setAt = charAfterPos;
110 size_t lengthUsedSoFar = 0;
111 for (size_t i = 0; i < nStyleInfos and lengthUsedSoFar < nTCharsFollowing; ++i) {
112 StyledInfoSummaryRecord isr = styleInfos[i];
113 size_t length = isr.fLength;
114 Assert (nTCharsFollowing >= lengthUsedSoFar);
115 length = min (nTCharsFollowing - lengthUsedSoFar, length);
116 SetStyleInfo (setAt, length, IncrementalFontSpecification{isr});
117 setAt += length;
118 lengthUsedSoFar += length;
119 }
120}
121
122#if qStroika_Foundation_Debug_AssertionsChecked
123void StyleDatabaseRep::Invariant_ () const
124{
125 inheritedMC::Invariant_ ();
126}
127#endif
128
129#if qStroika_Frameworks_Led_SupportGDI
130/*
131 ********************************************************************************
132 ****************************** StandardStyledTextImager ************************
133 ********************************************************************************
134 */
135void StandardStyledTextImager::HookLosingTextStore ()
136{
137 inherited::HookLosingTextStore ();
138 HookLosingTextStore_ ();
139}
140
141void StandardStyledTextImager::HookLosingTextStore_ ()
142{
143 // Only if we created the styledb should we delete it. If it was set by SetStyleDatabase(), don't unset it here.
144 if (fICreatedDatabase) {
145 fICreatedDatabase = false;
146 if (fStyleDatabase.get () != nullptr) {
147 fStyleDatabase = nullptr;
148 HookStyleDatabaseChanged ();
149 }
150 }
151}
152
153void StandardStyledTextImager::HookGainedNewTextStore ()
154{
155 inherited::HookGainedNewTextStore ();
156 HookGainedNewTextStore_ ();
157}
158
159void StandardStyledTextImager::HookGainedNewTextStore_ ()
160{
161 if (fStyleDatabase == nullptr) {
162 fStyleDatabase = make_shared<StyleDatabaseRep> (GetTextStore ());
163 fICreatedDatabase = true;
164 HookStyleDatabaseChanged ();
165 }
166}
167
168void StandardStyledTextImager::SetStyleDatabase (const shared_ptr<AbstractStyleDatabaseRep>& styleDatabase)
169{
170 fStyleDatabase = styleDatabase;
171 fICreatedDatabase = false;
172 if (fStyleDatabase == nullptr and PeekAtTextStore () != nullptr) {
173 fStyleDatabase = make_shared<StyleDatabaseRep> (GetTextStore ());
174 fICreatedDatabase = true;
175 }
176 HookStyleDatabaseChanged ();
177}
178
179/*
180@METHOD: StandardStyledTextImager::HookStyleDatabaseChanged
181@DESCRIPTION: <p>Called whenever the @'StyleDatabasePtr' associated with this @'StandardStyledTextImager'
182 is changed. This means when a new one is provided, created, or disassociated. It does NOT mean that its called when any of the
183 data in the style database changes.</p>
184*/
185void StandardStyledTextImager::HookStyleDatabaseChanged ()
186{
187}
188
189FontMetrics StandardStyledTextImager::GetFontMetricsAt (size_t charAfterPos) const
190{
191 Tablet_Acquirer tablet (this);
192 AssertNotNull (static_cast<Tablet*> (tablet));
193
194 FontCacheInfoUpdater fontCacheUpdater (this, tablet, GetStyleInfo (charAfterPos));
195 return (fontCacheUpdater.GetMetrics ());
196}
197
198/*
199@METHOD: StandardStyledTextImager::GetDefaultSelectionFont
200@DESCRIPTION: <p>Override @'TextImager::GetDefaultSelectionFont'.</p>
201*/
202FontSpecification StandardStyledTextImager::GetDefaultSelectionFont () const
203{
204 vector<StyledInfoSummaryRecord> summaryInfo = GetStyleInfo (GetSelectionEnd (), 0);
205 Assert (summaryInfo.size () == 1);
206 return summaryInfo[0];
207}
208
209/*
210@METHOD: StandardStyledTextImager::GetContinuousStyleInfo
211@DESCRIPTION: <p>Create a @'IncrementalFontSpecification' with set as valid all attributes which apply to all of the text from
212 <code>'from'</code> for <code>'nTChars'</code>.</p>
213 <p>So for example - if all text in that range has the same face, but different font sizes, then the face attribute will be
214 valid (and set to that common face) and the font size attribute will be set invalid.</p>
215 <p>This is useful for setting menus checked or unchecked in a typical word processor font menu.</p>
216*/
217IncrementalFontSpecification StandardStyledTextImager::GetContinuousStyleInfo (size_t from, size_t nTChars) const
218{
219 vector<StyledInfoSummaryRecord> summaryInfo = GetStyleInfo (from, nTChars);
220 return (GetContinuousStyleInfo_ (summaryInfo));
221}
222
223IncrementalFontSpecification StandardStyledTextImager::GetContinuousStyleInfo_ (const vector<StyledInfoSummaryRecord>& summaryInfo) const
224{
225 IncrementalFontSpecification fontSpec;
226
227 // There are only a certain number of font attributes which can be shared among these InfoSummaryRecords.
228 // Each time we note one which cannot be shared - we decrement this count. That way - when we know there can be
229 // no shared values - we stop comparing.
230 //
231 // countOfValidThings is a hack to see if we can skip out of for-loop early without a lot of expensive, and
232 // redundant tests.
233 //
234 // Note - we COULD have simply checked at the end of each loop count a bunch of 'IsValid' booleans. That would have
235 // been simpler. But it would have been more costly (performance).
236 int countOfValidThings = 7 +
237#if qStroika_Foundation_Common_Platform_MacOS
238 4
239#elif qStroika_Foundation_Common_Platform_Windows
240 1
241#elif qStroika_FeatureSupported_XWindows
242 0 // X-TMP-HACK-LGP991213 -- Not quite a hack - but revisit when we have REAL X-Font support
243#endif
244 ;
245
246 for (size_t i = 0; i < summaryInfo.size (); ++i) {
247 if (i == 0) {
248 fontSpec = IncrementalFontSpecification{summaryInfo[0]};
249 }
250 else {
251 // check each attribute (if not already different) and see if NOW different...
252
253 StyledInfoSummaryRecord isr = summaryInfo[i];
254
255 // Font ID
256 if (fontSpec.GetFontNameSpecifier_Valid () and fontSpec.GetFontNameSpecifier () != isr.GetFontNameSpecifier ()) {
257 fontSpec.InvalidateFontNameSpecifier ();
258 if (--countOfValidThings == 0) {
259 break;
260 }
261 }
262
263 // Style Info
264 if (fontSpec.GetStyle_Bold_Valid () and fontSpec.GetStyle_Bold () != isr.GetStyle_Bold ()) {
265 fontSpec.InvalidateStyle_Bold ();
266 if (--countOfValidThings == 0) {
267 break;
268 }
269 }
270 if (fontSpec.GetStyle_Italic_Valid () and fontSpec.GetStyle_Italic () != isr.GetStyle_Italic ()) {
271 fontSpec.InvalidateStyle_Italic ();
272 if (--countOfValidThings == 0) {
273 break;
274 }
275 }
276 if (fontSpec.GetStyle_Underline_Valid () and fontSpec.GetStyle_Underline () != isr.GetStyle_Underline ()) {
277 fontSpec.InvalidateStyle_Underline ();
278 if (--countOfValidThings == 0) {
279 break;
280 }
281 }
282 if (fontSpec.GetStyle_SubOrSuperScript_Valid () and fontSpec.GetStyle_SubOrSuperScript () != isr.GetStyle_SubOrSuperScript ()) {
283 fontSpec.InvalidateStyle_SubOrSuperScript ();
284 if (--countOfValidThings == 0) {
285 break;
286 }
287 }
288#if qStroika_Foundation_Common_Platform_MacOS
289 if (fontSpec.GetStyle_Outline_Valid () and fontSpec.GetStyle_Outline () != isr.GetStyle_Outline ()) {
290 fontSpec.InvalidateStyle_Outline ();
291 if (--countOfValidThings == 0) {
292 break;
293 }
294 }
295 if (fontSpec.GetStyle_Shadow_Valid () and fontSpec.GetStyle_Shadow () != isr.GetStyle_Shadow ()) {
296 fontSpec.InvalidateStyle_Shadow ();
297 if (--countOfValidThings == 0) {
298 break;
299 }
300 }
301 if (fontSpec.GetStyle_Condensed_Valid () and fontSpec.GetStyle_Condensed () != isr.GetStyle_Condensed ()) {
302 fontSpec.InvalidateStyle_Condensed ();
303 if (--countOfValidThings == 0) {
304 break;
305 }
306 }
307 if (fontSpec.GetStyle_Extended_Valid () and fontSpec.GetStyle_Extended () != isr.GetStyle_Extended ()) {
308 fontSpec.InvalidateStyle_Extended ();
309 if (--countOfValidThings == 0) {
310 break;
311 }
312 }
313#elif qStroika_Foundation_Common_Platform_Windows
314 if (fontSpec.GetStyle_Strikeout_Valid () and fontSpec.GetStyle_Strikeout () != isr.GetStyle_Strikeout ()) {
315 fontSpec.InvalidateStyle_Strikeout ();
316 if (--countOfValidThings == 0) {
317 break;
318 }
319 }
320#endif
321
322 // Font Size
323 if (fontSpec.GetPointSize_Valid () and fontSpec.GetPointSize () != isr.GetPointSize ()) {
324 fontSpec.InvalidatePointSize ();
325 if (--countOfValidThings == 0) {
326 break;
327 }
328 }
329
330 // Font Color
331 if (fontSpec.GetTextColor_Valid () and fontSpec.GetTextColor () != isr.GetTextColor ()) {
332 fontSpec.InvalidateTextColor ();
333 if (--countOfValidThings == 0) {
334 break;
335 }
336 }
337 }
338 }
339
340 return fontSpec;
341}
342
343#if qStroika_Foundation_Common_Platform_MacOS
344bool StandardStyledTextImager::DoContinuousStyle_Mac (size_t from, size_t nTChars, short* mode, TextStyle* theStyle)
345{
346 // Require ((*mode & doColor) == 0); // NB: we currently don't support doColor, doAll , addSize
347 // Just silently ignore doColor for now since done from TCL - and we just return NO for that style...
348 Require ((*mode & addSize) == 0);
349 RequireNotNull (theStyle);
350
351 unsigned int resultMode = *mode;
352 IncrementalFontSpecification resultSpec = GetContinuousStyleInfo (from, nTChars);
353 if (resultMode & doFont) {
354 resultSpec.GetOSRep (&theStyle->tsFont, nullptr, nullptr);
355 }
356 if (resultMode & doFace) {
357 resultSpec.GetOSRep (nullptr, nullptr, &theStyle->tsFace);
358 }
359 if (resultMode & doSize) {
360 resultSpec.GetOSRep (nullptr, &theStyle->tsSize, nullptr);
361 }
362
363 bool result = (resultMode != *mode);
364 *mode = resultMode;
365 return (result);
366}
367
368vector<StyledInfoSummaryRecord> StandardStyledTextImager::Convert (const ScrpSTElement* teScrapFmt, size_t nElts)
369{
370 vector<StyledInfoSummaryRecord> result;
371 for (size_t i = 0; i < nElts; ++i) {
372 IncrementalFontSpecification fsp;
373 fsp.SetOSRep (teScrapFmt[i].scrpFont, teScrapFmt[i].scrpSize, teScrapFmt[i].scrpFace);
374 size_t length = (i < (nElts - 1)) ? (teScrapFmt[i + 1].scrpStartChar - teScrapFmt[i].scrpStartChar) : 9999999;
375 StyledInfoSummaryRecord isr (fsp, length);
376 result.push_back (isr);
377 }
378 return (result);
379}
380
381void StandardStyledTextImager::Convert (const vector<StyledInfoSummaryRecord>& fromLedStyleRuns, ScrpSTElement* teScrapFmt)
382{
383 size_t nElts = fromLedStyleRuns.size ();
384 size_t startChar = 0;
385
386 GrafPtr oldPort = Led_GetCurrentGDIPort ();
387#if TARGET_CARBON
388 CGrafPtr tmpPort = ::CreateNewPort ();
389 ::SetPort (tmpPort);
390#else
391 CGrafPort tmpPort;
392 ::OpenCPort (&tmpPort);
393#endif
394
395 for (size_t i = 0; i < nElts; ++i) {
396 StyledInfoSummaryRecord isr = fromLedStyleRuns[i];
397
398 (void)::memset (&teScrapFmt[i], 0, sizeof (teScrapFmt[i]));
399 teScrapFmt[i].scrpStartChar = startChar;
400
401 isr.GetOSRep (&teScrapFmt[i].scrpFont, &teScrapFmt[i].scrpSize, &teScrapFmt[i].scrpFace);
402
403 ::TextFont (teScrapFmt[i].scrpFont);
404 ::TextFace (teScrapFmt[i].scrpFace);
405 ::TextSize (teScrapFmt[i].scrpSize);
406
407 FontInfo info;
408 ::GetFontInfo (&info);
409
410 teScrapFmt[i].scrpHeight = info.ascent + info.descent + info.leading;
411 teScrapFmt[i].scrpAscent = info.ascent;
412
413 startChar += isr.fLength;
414 }
415
416#if TARGET_CARBON
417 ::DisposePort (tmpPort);
418#else
419 ::CloseCPort (&tmpPort);
420#endif
421 ::SetPort (oldPort);
422}
423#endif
424
425#if qStroika_Foundation_Debug_AssertionsChecked
426void StandardStyledTextImager::Invariant_ () const
427{
428 StyledTextImager::Invariant_ ();
429 if (fStyleDatabase.get () != nullptr) {
430 fStyleDatabase->Invariant ();
431 }
432}
433#endif
434
435#endif
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347