Stroika Library 3.0d23x
 
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_Foundation_Common_Platform_MacOS
243 4
244#elif qStroika_Foundation_Common_Platform_Windows
245 1
246#elif qStroika_FeatureSupported_XWindows
247 0 // X-TMP-HACK-LGP991213 -- Not quite a hack - but revisit when we have REAL X-Font support
248#endif
249 ;
250
251 for (size_t i = 0; i < summaryInfo.size (); ++i) {
252 if (i == 0) {
253 fontSpec = IncrementalFontSpecification{summaryInfo[0]};
254 }
255 else {
256 // check each attribute (if not already different) and see if NOW different...
257
258 StyledInfoSummaryRecord isr = summaryInfo[i];
259
260 // Font ID
261 if (fontSpec.GetFontNameSpecifier_Valid () and fontSpec.GetFontNameSpecifier () != isr.GetFontNameSpecifier ()) {
262 fontSpec.InvalidateFontNameSpecifier ();
263 if (--countOfValidThings == 0) {
264 break;
265 }
266 }
267
268 // Style Info
269 if (fontSpec.GetStyle_Bold_Valid () and fontSpec.GetStyle_Bold () != isr.GetStyle_Bold ()) {
270 fontSpec.InvalidateStyle_Bold ();
271 if (--countOfValidThings == 0) {
272 break;
273 }
274 }
275 if (fontSpec.GetStyle_Italic_Valid () and fontSpec.GetStyle_Italic () != isr.GetStyle_Italic ()) {
276 fontSpec.InvalidateStyle_Italic ();
277 if (--countOfValidThings == 0) {
278 break;
279 }
280 }
281 if (fontSpec.GetStyle_Underline_Valid () and fontSpec.GetStyle_Underline () != isr.GetStyle_Underline ()) {
282 fontSpec.InvalidateStyle_Underline ();
283 if (--countOfValidThings == 0) {
284 break;
285 }
286 }
287 if (fontSpec.GetStyle_SubOrSuperScript_Valid () and fontSpec.GetStyle_SubOrSuperScript () != isr.GetStyle_SubOrSuperScript ()) {
288 fontSpec.InvalidateStyle_SubOrSuperScript ();
289 if (--countOfValidThings == 0) {
290 break;
291 }
292 }
293#if qStroika_Foundation_Common_Platform_MacOS
294 if (fontSpec.GetStyle_Outline_Valid () and fontSpec.GetStyle_Outline () != isr.GetStyle_Outline ()) {
295 fontSpec.InvalidateStyle_Outline ();
296 if (--countOfValidThings == 0) {
297 break;
298 }
299 }
300 if (fontSpec.GetStyle_Shadow_Valid () and fontSpec.GetStyle_Shadow () != isr.GetStyle_Shadow ()) {
301 fontSpec.InvalidateStyle_Shadow ();
302 if (--countOfValidThings == 0) {
303 break;
304 }
305 }
306 if (fontSpec.GetStyle_Condensed_Valid () and fontSpec.GetStyle_Condensed () != isr.GetStyle_Condensed ()) {
307 fontSpec.InvalidateStyle_Condensed ();
308 if (--countOfValidThings == 0) {
309 break;
310 }
311 }
312 if (fontSpec.GetStyle_Extended_Valid () and fontSpec.GetStyle_Extended () != isr.GetStyle_Extended ()) {
313 fontSpec.InvalidateStyle_Extended ();
314 if (--countOfValidThings == 0) {
315 break;
316 }
317 }
318#elif qStroika_Foundation_Common_Platform_Windows
319 if (fontSpec.GetStyle_Strikeout_Valid () and fontSpec.GetStyle_Strikeout () != isr.GetStyle_Strikeout ()) {
320 fontSpec.InvalidateStyle_Strikeout ();
321 if (--countOfValidThings == 0) {
322 break;
323 }
324 }
325#endif
326
327 // Font Size
328 if (fontSpec.GetPointSize_Valid () and fontSpec.GetPointSize () != isr.GetPointSize ()) {
329 fontSpec.InvalidatePointSize ();
330 if (--countOfValidThings == 0) {
331 break;
332 }
333 }
334
335 // Font Color
336 if (fontSpec.GetTextColor_Valid () and fontSpec.GetTextColor () != isr.GetTextColor ()) {
337 fontSpec.InvalidateTextColor ();
338 if (--countOfValidThings == 0) {
339 break;
340 }
341 }
342 }
343 }
344
345 return fontSpec;
346}
347
348#if qStroika_Foundation_Common_Platform_MacOS
349bool StandardStyledTextImager::DoContinuousStyle_Mac (size_t from, size_t nTChars, short* mode, TextStyle* theStyle)
350{
351 // Require ((*mode & doColor) == 0); // NB: we currently don't support doColor, doAll , addSize
352 // Just silently ignore doColor for now since done from TCL - and we just return NO for that style...
353 Require ((*mode & addSize) == 0);
354 RequireNotNull (theStyle);
355
356 unsigned int resultMode = *mode;
357 IncrementalFontSpecification resultSpec = GetContinuousStyleInfo (from, nTChars);
358 if (resultMode & doFont) {
359 resultSpec.GetOSRep (&theStyle->tsFont, nullptr, nullptr);
360 }
361 if (resultMode & doFace) {
362 resultSpec.GetOSRep (nullptr, nullptr, &theStyle->tsFace);
363 }
364 if (resultMode & doSize) {
365 resultSpec.GetOSRep (nullptr, &theStyle->tsSize, nullptr);
366 }
367
368 bool result = (resultMode != *mode);
369 *mode = resultMode;
370 return (result);
371}
372
373vector<StyledInfoSummaryRecord> StandardStyledTextImager::Convert (const ScrpSTElement* teScrapFmt, size_t nElts)
374{
375 vector<StyledInfoSummaryRecord> result;
376 for (size_t i = 0; i < nElts; ++i) {
377 IncrementalFontSpecification fsp;
378 fsp.SetOSRep (teScrapFmt[i].scrpFont, teScrapFmt[i].scrpSize, teScrapFmt[i].scrpFace);
379 size_t length = (i < (nElts - 1)) ? (teScrapFmt[i + 1].scrpStartChar - teScrapFmt[i].scrpStartChar) : 9999999;
380 StyledInfoSummaryRecord isr (fsp, length);
381 result.push_back (isr);
382 }
383 return (result);
384}
385
386void StandardStyledTextImager::Convert (const vector<StyledInfoSummaryRecord>& fromLedStyleRuns, ScrpSTElement* teScrapFmt)
387{
388 size_t nElts = fromLedStyleRuns.size ();
389 size_t startChar = 0;
390
391 GrafPtr oldPort = Led_GetCurrentGDIPort ();
392#if TARGET_CARBON
393 CGrafPtr tmpPort = ::CreateNewPort ();
394 ::SetPort (tmpPort);
395#else
396 CGrafPort tmpPort;
397 ::OpenCPort (&tmpPort);
398#endif
399
400 for (size_t i = 0; i < nElts; ++i) {
401 StyledInfoSummaryRecord isr = fromLedStyleRuns[i];
402
403 (void)::memset (&teScrapFmt[i], 0, sizeof (teScrapFmt[i]));
404 teScrapFmt[i].scrpStartChar = startChar;
405
406 isr.GetOSRep (&teScrapFmt[i].scrpFont, &teScrapFmt[i].scrpSize, &teScrapFmt[i].scrpFace);
407
408 ::TextFont (teScrapFmt[i].scrpFont);
409 ::TextFace (teScrapFmt[i].scrpFace);
410 ::TextSize (teScrapFmt[i].scrpSize);
411
412 FontInfo info;
413 ::GetFontInfo (&info);
414
415 teScrapFmt[i].scrpHeight = info.ascent + info.descent + info.leading;
416 teScrapFmt[i].scrpAscent = info.ascent;
417
418 startChar += isr.fLength;
419 }
420
421#if TARGET_CARBON
422 ::DisposePort (tmpPort);
423#else
424 ::CloseCPort (&tmpPort);
425#endif
426 ::SetPort (oldPort);
427}
428#endif
429
430#if qStroika_Foundation_Debug_AssertionsChecked
431void StandardStyledTextImager::Invariant_ () const
432{
433 StyledTextImager::Invariant_ ();
434 if (fStyleDatabase.get () != nullptr) {
435 fStyleDatabase->Invariant ();
436 }
437}
438#endif
439
440#endif
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347