Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
StyledTextEmbeddedObjects.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "Stroika/Foundation/DataExchange/BadFormatException.h"
7#if qStroika_Foundation_Common_Platform_Windows
8#include "Stroika/Foundation/Memory/Platform/Windows/Handle.h"
9#endif
10
11#include "Stroika/Frameworks/Led/StandardStyledTextImager.h"
12
13#include "StyledTextEmbeddedObjects.h"
14
15using namespace Stroika::Foundation;
16using namespace Stroika::Frameworks;
17using namespace Stroika::Frameworks::Led;
18
19#if qStroika_Frameworks_Led_SupportGDI
20// Hack to free up registry data on program exit. No real point to this but
21// to shutup MFC leak detector. That has SOME value, since it makes it easier to see REAL
22// leaks.
23static struct FooBarBlatzRegistryCleanupHack {
24 ~FooBarBlatzRegistryCleanupHack ()
25 {
26 delete EmbeddedObjectCreatorRegistry::sThe;
27 EmbeddedObjectCreatorRegistry::sThe = nullptr;
28 }
29} sOneOfThese;
30
31#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
32static void MacPictureDrawSegment (StandardMacPictureStyleMarker::PictureHandle pictureHandle, Tablet* tablet, Color foreColor,
33 Color backColor, const Led_Rect& drawInto, CoordinateType useBaseLine, DistanceType* pixelsDrawn,
34 const Led_Size& imageSize, const Led_Size& margin = kDefaultEmbeddingMargin) noexcept;
35#endif
36static void DIBDrawSegment (const Led_DIB* dib, Tablet* tablet, Color foreColor, Color backColor, const Led_Rect& drawInto, CoordinateType useBaseLine,
37 DistanceType* pixelsDrawn, const Led_Size& imageSize, const Led_Size& margin = kDefaultEmbeddingMargin) noexcept;
38#if qStroika_Foundation_Common_Platform_MacOS
39static PixMap** MakePixMapFromDIB (const Led_DIB* dib);
40#endif
41
42struct UnsupportedFormat {};
43
44namespace {
45 using StackBasedHandleLocker = Memory::Platform::Windows::StackBasedHandleLocker;
46}
47
48/*
49 ********************************************************************************
50 ************************** EmbeddedObjectCreatorRegistry ***********************
51 ********************************************************************************
52 */
53EmbeddedObjectCreatorRegistry* EmbeddedObjectCreatorRegistry::sThe = nullptr;
54
55void EmbeddedObjectCreatorRegistry::AddStandardTypes ()
56{
57#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
58 AddAssoc (StandardMacPictureStyleMarker::kClipFormat, StandardMacPictureStyleMarker::kEmbeddingTag, &StandardMacPictureStyleMarker::mk,
59 &StandardMacPictureStyleMarker::mk);
60 AddAssoc (StandardDIBStyleMarker::kClipFormat, StandardDIBStyleMarker::kEmbeddingTag, &StandardDIBStyleMarker::mk, &StandardDIBStyleMarker::mk);
61#endif
62
63 AddAssoc (StandardURLStyleMarker::kURLDClipFormat, StandardURLStyleMarker::kEmbeddingTag, &StandardURLStyleMarker::mk, &StandardURLStyleMarker::mk);
64#if qStroika_Foundation_Common_Platform_Windows
65 AddAssoc (StandardURLStyleMarker::kWin32URLClipFormat, StandardURLStyleMarker::kEmbeddingTag, &StandardURLStyleMarker::mk,
66 &StandardURLStyleMarker::mk);
67#endif
68
69#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
70 AddAssoc (StandardMacPictureWithURLStyleMarker::kClipFormats, StandardMacPictureWithURLStyleMarker::kClipFormatCount,
71 StandardMacPictureWithURLStyleMarker::kEmbeddingTag, &StandardMacPictureWithURLStyleMarker::mk,
72 &StandardMacPictureWithURLStyleMarker::mk);
73 AddAssoc (StandardMacPictureWithURLStyleMarker::kOld1EmbeddingTag, &StandardMacPictureWithURLStyleMarker::mk);
74 AddAssoc (StandardDIBWithURLStyleMarker::kClipFormats, StandardDIBWithURLStyleMarker::kClipFormatCount,
75 StandardDIBWithURLStyleMarker::kEmbeddingTag, &StandardDIBWithURLStyleMarker::mk, &StandardDIBWithURLStyleMarker::mk);
76#endif
77}
78
79bool EmbeddedObjectCreatorRegistry::Lookup (const char* embeddingTag, Assoc* result) const
80{
81 RequireNotNull (embeddingTag);
82 RequireNotNull (result);
83 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = GetAssocList ();
84 for (size_t i = 0; i < types.size (); ++i) {
85 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
86 if (memcmp (assoc.fEmbeddingTag, embeddingTag, sizeof (assoc.fEmbeddingTag)) == 0) {
87 *result = assoc;
88 return true;
89 }
90 }
91 return false;
92}
93
94/*
95 ********************************************************************************
96 ********************* SimpleEmbeddedObjectStyleMarker **************************
97 ********************************************************************************
98 */
99SimpleEmbeddedObjectStyleMarker::CommandNames SimpleEmbeddedObjectStyleMarker::sCommandNames =
100 SimpleEmbeddedObjectStyleMarker::MakeDefaultCommandNames ();
101
102int SimpleEmbeddedObjectStyleMarker::GetPriority () const
103{
104 return eEmbeddedObjectPriority;
105}
106
107DistanceType SimpleEmbeddedObjectStyleMarker::MeasureSegmentBaseLine (const StyledTextImager* imager, const StyleRunElement& runElement,
108 size_t from, size_t to) const
109{
110 // Baseline for embeddings should be very bottom of the embedding (less the bottom margin)
111 Require (from + 1 == to);
112 return (MeasureSegmentHeight (imager, runElement, from, to) - 1 * kDefaultEmbeddingMargin.v);
113}
114
115void SimpleEmbeddedObjectStyleMarker::DidUpdateText (const MarkerOwner::UpdateInfo& updateInfo) noexcept
116{
117 RequireNotNull (GetOwner ());
118 RequireNotNull (GetOwner ()->PeekAtTextStore ());
119 size_t newLength = GetLength ();
120 if (newLength == 0) {
121 GetOwner ()->PeekAtTextStore ()->RemoveMarker (this);
122 delete this;
123 }
124 else if (newLength == 1) {
125 inherited::DidUpdateText (updateInfo);
126 }
127 else {
128 Assert (GetEnd () > 0); // cuz otherwise we couldn't have a non-zero length!
129 GetOwner ()->PeekAtTextStore ()->SetMarkerStart (this, GetEnd () - 1);
130 inherited::DidUpdateText (updateInfo);
131 }
132}
133
134/*
135@METHOD: SimpleEmbeddedObjectStyleMarker::HandleClick
136@DESCRIPTION: <p>Called when a user clicks on the given embedding. 'clickedAt' is relative to the embedding itself.</p>
137*/
138bool SimpleEmbeddedObjectStyleMarker::HandleClick (Led_Point /*clickedAt*/, unsigned clickCount)
139{
140 if (clickCount == 2) {
141 return HandleOpen ();
142 }
143 return true;
144}
145
146bool SimpleEmbeddedObjectStyleMarker::HandleOpen ()
147{
148 return true;
149}
150
151/*
152@METHOD: SimpleEmbeddedObjectStyleMarker::GetCmdNumbers
153@DESCRIPTION: <p>Return a list of all private commands (such as eOpenCmdNum) which this embedding object can support.
154 See also @'SimpleEmbeddedObjectStyleMarker::IsCmdEnabled' (), @'SimpleEmbeddedObjectStyleMarker::GetCmdText' (),
155 and @'SimpleEmbeddedObjectStyleMarker::DoCommand' () which also must be supported for each of those commands.</p>
156*/
157vector<SimpleEmbeddedObjectStyleMarker::PrivateCmdNumber> SimpleEmbeddedObjectStyleMarker::GetCmdNumbers () const
158{
159 return vector<PrivateCmdNumber> ();
160}
161
162/*
163@METHOD: SimpleEmbeddedObjectStyleMarker::IsCmdEnabled
164@DESCRIPTION: <p>For all commands specified in overrides of @'SimpleEmbeddedObjectStyleMarker::GetCmdNumbers' (ie all private commands
165 supported) return whether or not that command is currently enabled.</p>
166*/
167bool SimpleEmbeddedObjectStyleMarker::IsCmdEnabled (PrivateCmdNumber /*cmd*/) const
168{
169 return false; // default to disabled - subclasses OVERRIDE SimpleEmbeddedObjectStyleMarker::GetCmdNumbers () && SimpleEmbeddedObjectStyleMarker::IsCmdEnabled ()
170}
171
172/*
173@METHOD: SimpleEmbeddedObjectStyleMarker::GetCmdText
174@DESCRIPTION: <p>For all commands specified in overrides of @'SimpleEmbeddedObjectStyleMarker::GetCmdNumbers' (ie all private commands
175 supported) return the command name text.</p>
176*/
177SDKString SimpleEmbeddedObjectStyleMarker::GetCmdText (PrivateCmdNumber cmd)
178{
179 switch (cmd) {
180 case eOpenCmdNum:
181 return GetCommandNames ().fOpenCommandName;
182 default:
183 Assert (false);
184 return SDKString{};
185 }
186}
187
188/*
189@METHOD: SimpleEmbeddedObjectStyleMarker::DoCommand
190@DESCRIPTION: <p>For all commands specified in overrides of @'SimpleEmbeddedObjectStyleMarker::GetCmdNumbers' (ie all private commands
191 supported) perform that command. This is invoked by the menu commands, etc (for example). The only command automatically
192 handled by this implementation (@'SimpleEmbeddedObjectStyleMarker::DoCommand') is for eOpenCmdNum, and that just invokes
193 @'SimpleEmbeddedObjectStyleMarker::HandleOpen' (). For other command numbers, the subclasser must handle the
194 commands themselves.</p>
195*/
196void SimpleEmbeddedObjectStyleMarker::DoCommand (PrivateCmdNumber cmd)
197{
198 switch (cmd) {
199 case eOpenCmdNum:
200 HandleOpen ();
201 break;
202 default:
203 Assert (false);
204 break;
205 }
206}
207
208SimpleEmbeddedObjectStyleMarker::CommandNames SimpleEmbeddedObjectStyleMarker::MakeDefaultCommandNames ()
209{
210 SimpleEmbeddedObjectStyleMarker::CommandNames cmdNames;
211 cmdNames.fOpenCommandName = Led_SDK_TCHAROF ("Open Embedding");
212 return cmdNames;
213}
214
215#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
216/*
217 ********************************************************************************
218 ************************** StandardMacPictureStyleMarker ***********************
219 ********************************************************************************
220 */
221#if qStroika_Foundation_Common_Platform_MacOS
222const Led_ClipFormat StandardMacPictureStyleMarker::kClipFormat = kPICTClipFormat;
223#elif qStroika_Foundation_Common_Platform_Windows
224// Surprising, the QuickTime for windows 2.1 picture viewer doesn't appear to export (on copy) a
225// native format rep of the picture. So I've no guess what the RIGHT arg is to RegisterClipboardFormat.
226// So - this is as good a guess as any. At least then Led can xfer pictures among instances of itself.
227// LGP 960429
228const Led_ClipFormat StandardMacPictureStyleMarker::kClipFormat = static_cast<Led_ClipFormat> (::RegisterClipboardFormat (_T ("Mac PICT Format")));
229#endif
230constexpr Led_PrivateEmbeddingTag StandardMacPictureStyleMarker::kEmbeddingTag = "Pict2";
231
232#if qStroika_Foundation_Common_Platform_Windows
233const Led_DIB* StandardMacPictureStyleMarker::sUnsupportedFormatPict = nullptr;
234#endif
235
236StandardMacPictureStyleMarker::StandardMacPictureStyleMarker (const Led_Picture* pictData, size_t picSize)
237 : SimpleEmbeddedObjectStyleMarker ()
238 , fPictureHandle (nullptr)
239#if qStroika_Foundation_Common_Platform_Windows
240 , fPictureSize (0)
241#endif
242{
243 RequireNotNull (pictData);
244#if qStroika_Foundation_Common_Platform_Windows
245 RequireNotNull (sUnsupportedFormatPict);
246#endif
247#if qStroika_Foundation_Common_Platform_MacOS
248 fPictureHandle = (PictureHandle)Led_DoNewHandle (picSize);
249#elif qStroika_Foundation_Common_Platform_Windows
250 fPictureSize = picSize;
251 fPictureHandle = ::GlobalAlloc (GMEM_MOVEABLE, picSize);
252 Execution::ThrowIfNull (fPictureHandle);
253#endif
254 StackBasedHandleLocker locker (GetPictureHandle ());
255 memcpy (locker.GetPointer (), pictData, picSize);
256}
257
258StandardMacPictureStyleMarker::~StandardMacPictureStyleMarker ()
259{
260 AssertNotNull (fPictureHandle);
261#if qStroika_Foundation_Common_Platform_MacOS
262 ::DisposeHandle (Handle (fPictureHandle));
263#else
264 ::GlobalFree (fPictureHandle);
265#endif
266}
267
268SimpleEmbeddedObjectStyleMarker* StandardMacPictureStyleMarker::mk ([[maybe_unused]] const char* embeddingTag, const void* data, size_t len)
269{
270 Require (memcmp (embeddingTag, kEmbeddingTag, sizeof (kEmbeddingTag)) == 0);
271 return (new StandardMacPictureStyleMarker ((Led_Picture*)data, len));
272}
273
274SimpleEmbeddedObjectStyleMarker* StandardMacPictureStyleMarker::mk (ReaderFlavorPackage& flavorPackage)
275{
276 size_t length = flavorPackage.GetFlavorSize (kClipFormat);
277 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, length};
278 length = flavorPackage.ReadFlavorData (kClipFormat, length, buf.data ());
279 return (mk (kEmbeddingTag, buf.data (), length));
280}
281
282void StandardMacPictureStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, Tablet* tablet,
283 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
284 [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
285 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
286{
287 Assert (from + 1 == to);
288 Require (text.PeekAtVirtualText ()[0] == kEmbeddingSentinelChar);
289 StackBasedHandleLocker locker (GetPictureHandle ());
290 MacPictureDrawSegment (GetPictureHandle (), tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
291 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
292 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn,
293 Led_GetMacPictSize ((Led_Picture*)locker.GetPointer ()));
294}
295
296void StandardMacPictureStyleMarker::MeasureSegmentWidth ([[maybe_unused]] const StyledTextImager* imager,
297 [[maybe_unused]] const StyleRunElement& runElement, [[maybe_unused]] size_t from,
298 [[maybe_unused]] size_t to, [[maybe_unused]] const Led_tChar* text,
299 DistanceType* distanceResults) const
300{
301 Assert (from + 1 == to);
302 RequireNotNull (text);
303 /*
304 * Though we generally require that:
305 *
306 * Require (text[0] == kEmbeddingSentinelChar);
307 *
308 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
309 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
310 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
311 * character here. We know the right width here anyhow.
312 * See SPR#0821.
313 */
314 StackBasedHandleLocker locker (GetPictureHandle ());
315 distanceResults[0] = Led_GetMacPictWidth ((Led_Picture*)locker.GetPointer ()) + 2 * kDefaultEmbeddingMargin.h;
316}
317
318DistanceType StandardMacPictureStyleMarker::MeasureSegmentHeight ([[maybe_unused]] const StyledTextImager* imager,
319 [[maybe_unused]] const StyleRunElement& runElement,
320 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
321{
322 Assert (from + 1 == to);
323 StackBasedHandleLocker locker (GetPictureHandle ());
324 return (Led_GetMacPictHeight ((Led_Picture*)locker.GetPointer ()) + 2 * kDefaultEmbeddingMargin.v);
325}
326
327void StandardMacPictureStyleMarker::Write (SinkStream& sink)
328{
329 StackBasedHandleLocker locker (GetPictureHandle ());
330 sink.write (locker.GetPointer (), GetPictureByteSize ());
331}
332
333void StandardMacPictureStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
334{
335 StackBasedHandleLocker locker (GetPictureHandle ());
336 flavorPackage.AddFlavorData (kClipFormat, GetPictureByteSize (), (Led_Picture*)locker.GetPointer ());
337}
338
339const char* StandardMacPictureStyleMarker::GetTag () const
340{
341 return kEmbeddingTag;
342}
343#endif
344
345/*
346 ********************************************************************************
347 ************************** StandardDIBStyleMarker ******************************
348 ********************************************************************************
349 */
350#if qStroika_Foundation_Common_Platform_MacOS
351// I don't know of any standard type for this, so just make one up...
352// LGP 960429
353const Led_ClipFormat StandardDIBStyleMarker::kClipFormat = 'DIB ';
354#elif qStroika_Foundation_Common_Platform_Windows
355const Led_ClipFormat StandardDIBStyleMarker::kClipFormat = CF_DIB;
356#elif qStroika_FeatureSupported_XWindows
357const Led_ClipFormat StandardDIBStyleMarker::kClipFormat = 666; // X-TMP-HACK-LGP991214
358#endif
359constexpr Led_PrivateEmbeddingTag StandardDIBStyleMarker::kEmbeddingTag = "DIB";
360
361#if qStroika_Foundation_Common_Platform_MacOS
362Led_Picture** StandardDIBStyleMarker::sUnsupportedFormatPict = nullptr;
363#endif
364
365StandardDIBStyleMarker::StandardDIBStyleMarker (const Led_DIB* pictData)
366 : SimpleEmbeddedObjectStyleMarker ()
367 , fDIBData (nullptr)
368{
369#if qStroika_Foundation_Common_Platform_MacOS
370 RequireNotNull (sUnsupportedFormatPict); // see class declaration for descriptio
371#endif
372 RequireNotNull (pictData);
373 fDIBData = Led_CloneDIB (pictData);
374}
375
376StandardDIBStyleMarker::~StandardDIBStyleMarker ()
377{
378 AssertNotNull (fDIBData);
379 delete fDIBData;
380}
381
382SimpleEmbeddedObjectStyleMarker* StandardDIBStyleMarker::mk ([[maybe_unused]] const char* embeddingTag, const void* data, size_t len)
383{
384 Require (memcmp (embeddingTag, kEmbeddingTag, sizeof (kEmbeddingTag)) == 0);
385 if (len < 40) {
386 // This is less than we need to peek and see size of DIB...
387 Execution::Throw (DataExchange::BadFormatException::kThe);
388 }
389
390 size_t picSize = Led_GetDIBImageByteCount ((Led_DIB*)data);
391 // It appears that sometimes (at least on NT 4.0 beta) that the length of the flavor package is longer
392 // than we expect. I'm guessing this is some optional additional information MS now passes along.
393 // The picts APPEAR to come out looking fine if we ignore this stuff of the end. So continue doing so...
394 if (len != picSize) {
395 // Set a breakpoint here if this worries you...
396 if (len < picSize) {
397 // This is definitely bad!!!
398 Execution::Throw (DataExchange::BadFormatException::kThe);
399 }
400 else {
401 // we'll just ignore the stuff off the end... Hope thats OK - LGP 960429
402 }
403 }
404 return (new StandardDIBStyleMarker ((Led_DIB*)data));
405}
406
407SimpleEmbeddedObjectStyleMarker* StandardDIBStyleMarker::mk (ReaderFlavorPackage& flavorPackage)
408{
409 size_t length = flavorPackage.GetFlavorSize (kClipFormat);
410 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, length};
411 length = flavorPackage.ReadFlavorData (kClipFormat, length, buf.data ());
412 return mk (kEmbeddingTag, buf.data (), length);
413}
414
415void StandardDIBStyleMarker::DrawSegment (const StyledTextImager* imager, [[maybe_unused]] const StyleRunElement& runElement,
416 Tablet* tablet, [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
417 [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
418 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
419{
420 Assert (from + 1 == to);
421 Require (text.PeekAtVirtualText ()[0] == kEmbeddingSentinelChar);
422 DIBDrawSegment (fDIBData, tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
423 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
424 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn, Led_GetDIBImageSize (fDIBData));
425}
426
427void StandardDIBStyleMarker::MeasureSegmentWidth (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
428 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
429 [[maybe_unused]] const Led_tChar* text, DistanceType* distanceResults) const
430{
431 Assert (from + 1 == to);
432 RequireNotNull (text);
433 /*
434 * Though we generally require that:
435 *
436 * Require (text[0] == kEmbeddingSentinelChar);
437 *
438 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
439 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
440 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
441 * character here. We know the right width here anyhow.
442 * See SPR#0821.
443 */
444 distanceResults[0] = Led_GetDIBImageSize (GetDIBData ()).h + 2 * kDefaultEmbeddingMargin.h;
445}
446
447DistanceType StandardDIBStyleMarker::MeasureSegmentHeight (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
448 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
449{
450 Assert (from + 1 == to);
451 return (Led_GetDIBImageSize (GetDIBData ()).v + 2 * kDefaultEmbeddingMargin.v);
452}
453
454void StandardDIBStyleMarker::Write (SinkStream& sink)
455{
456 const Led_DIB* dib = GetDIBData ();
457 size_t dibSize = Led_GetDIBImageByteCount (dib);
458 sink.write (dib, dibSize);
459}
460
461void StandardDIBStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
462{
463 const Led_DIB* dib = GetDIBData ();
464 size_t dibSize = Led_GetDIBImageByteCount (dib);
465 flavorPackage.AddFlavorData (kClipFormat, dibSize, dib);
466}
467
468const char* StandardDIBStyleMarker::GetTag () const
469{
470 return kEmbeddingTag;
471}
472
473/*
474 ********************************************************************************
475 ****************************** StandardURLStyleMarker **************************
476 ********************************************************************************
477 */
478#if qStroika_Foundation_Common_Platform_MacOS
479const Led_ClipFormat StandardURLStyleMarker::kURLDClipFormat = 'URLD';
480#elif qStroika_Foundation_Common_Platform_Windows
481// Netscape USED to have some sort of predefined name like Netscsape Bookmark, or something like that.
482// Apparently not any more. Will have to investigate further to see what todo for Netscape...
483// LGP 960429
484const Led_ClipFormat StandardURLStyleMarker::kURLDClipFormat = static_cast<Led_ClipFormat> (::RegisterClipboardFormat (_T ("Netscape Bookmark")));
485const Led_ClipFormat StandardURLStyleMarker::kWin32URLClipFormat =
486 static_cast<Led_ClipFormat> (::RegisterClipboardFormat (_T ("UniformResourceLocator")));
487#elif qStroika_FeatureSupported_XWindows
488const Led_ClipFormat StandardURLStyleMarker::kURLDClipFormat = 'URLD'; //??? NOT SURE WHAT RIGHT ANSWER SB HERE!!!
489#endif
490
491constexpr Led_PrivateEmbeddingTag StandardURLStyleMarker::kEmbeddingTag = "URL";
492
493StandardURLStyleMarker::StandardURLStyleMarker (const Led_URLD& urlData)
494 : SimpleEmbeddedObjectStyleMarker ()
495 , fURLData (urlData)
496{
497}
498
499StandardURLStyleMarker::~StandardURLStyleMarker ()
500{
501}
502
503SimpleEmbeddedObjectStyleMarker* StandardURLStyleMarker::mk ([[maybe_unused]] const char* embeddingTag, const void* data, size_t len)
504{
505 Require (memcmp (embeddingTag, kEmbeddingTag, sizeof (kEmbeddingTag)) == 0);
506 return (new StandardURLStyleMarker (Led_URLD (data, len)));
507}
508
509SimpleEmbeddedObjectStyleMarker* StandardURLStyleMarker::mk (ReaderFlavorPackage& flavorPackage)
510{
511 /*
512 * First try URLD format, and then Win32URL format.
513 */
514 if (flavorPackage.GetFlavorAvailable (kURLDClipFormat)) {
515 size_t length = flavorPackage.GetFlavorSize (kURLDClipFormat);
516 Memory::StackBuffer<Led_tChar> buf{Memory::eUninitialized, length};
517 length = flavorPackage.ReadFlavorData (kURLDClipFormat, length, buf.data ());
518 return (mk (kEmbeddingTag, buf.data (), length));
519 }
520#if qStroika_Foundation_Common_Platform_Windows
521 if (flavorPackage.GetFlavorAvailable (kWin32URLClipFormat)) {
522 size_t length = flavorPackage.GetFlavorSize (kWin32URLClipFormat);
523 Memory::StackBuffer<char> buf{Memory::eUninitialized, length};
524 length = flavorPackage.ReadFlavorData (kWin32URLClipFormat, length, buf.data ());
525 // tmp/medium term hack.. Seems both formats look roughly the same. URL first. Then title. At least for now,
526 // we can take advtangage of this and share code on read. If not, we can read/reformat to fit so this below works.
527 // LGP 961012
528 return (mk (kEmbeddingTag, buf.data (), length));
529 }
530#endif
531 Execution::Throw (DataExchange::BadFormatException::kThe);
532 Assert (false);
533 return nullptr;
534}
535
536void StandardURLStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& runElement, Tablet* tablet, size_t from,
537 [[maybe_unused]] size_t to, [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
538 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
539{
540 RequireNotNull (imager);
541
542 FontSpecification fsp = GetDisplayFont (runElement);
543 Led_tString displayText = GetDisplayString ();
544 imager->DrawSegment_ (tablet, fsp, from, from + displayText.length (),
545 TextLayoutBlock_Basic (displayText.c_str (), displayText.c_str () + displayText.length ()), drawInto, useBaseLine, pixelsDrawn);
546}
547
548void StandardURLStyleMarker::MeasureSegmentWidth (const StyledTextImager* imager, const StyleRunElement& runElement, [[maybe_unused]] size_t from,
549 [[maybe_unused]] size_t to, [[maybe_unused]] const Led_tChar* text, DistanceType* distanceResults) const
550{
551 Assert (from + 1 == to);
552 RequireNotNull (text);
553 /*
554 * Though we generally require that:
555 *
556 * Require (text[0] == kEmbeddingSentinelChar);
557 *
558 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
559 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
560 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
561 * character here. We know the right width here anyhow.
562 * See SPR#0821.
563 */
564
565 FontSpecification fsp = GetDisplayFont (runElement);
566 Led_tString displayText = GetDisplayString ();
567 if (displayText.empty ()) {
568 distanceResults[0] = 0;
569 }
570 else {
571 Memory::StackBuffer<DistanceType> distRes{Memory::eUninitialized, displayText.length ()};
572 imager->MeasureSegmentWidth_ (fsp, from, from + displayText.length (), displayText.c_str (), distRes.data ());
573 distanceResults[0] = distRes[displayText.length () - 1];
574 }
575}
576
577DistanceType StandardURLStyleMarker::MeasureSegmentHeight (const StyledTextImager* imager, const StyleRunElement& runElement,
578 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
579{
580 Assert (from + 1 == to);
581
582 FontSpecification fsp = GetDisplayFont (runElement);
583 Led_tString displayText = GetDisplayString ();
584 return imager->MeasureSegmentHeight_ (fsp, from, from + displayText.length ());
585}
586
587void StandardURLStyleMarker::Write (SinkStream& sink)
588{
589 sink.write (fURLData.PeekAtURLD (), fURLData.GetURLDLength ());
590}
591
592void StandardURLStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
593{
594 flavorPackage.AddFlavorData (kURLDClipFormat, fURLData.GetURLDLength (), fURLData.PeekAtURLD ());
595#if qStroika_Foundation_Common_Platform_Windows
596 size_t len = fURLData.GetURLLength () + 1;
597 Memory::StackBuffer<char> hackBuf{Memory::eUninitialized, len};
598 memcpy (hackBuf.data (), fURLData.PeekAtURL (), len - 1);
599 hackBuf[len] = '\0';
600 flavorPackage.AddFlavorData (kWin32URLClipFormat, len, hackBuf.data ());
601#endif
602}
603
604const char* StandardURLStyleMarker::GetTag () const
605{
606 return kEmbeddingTag;
607}
608
609bool StandardURLStyleMarker::HandleOpen ()
610{
611 Led_URLManager::Get ().Open (fURLData.GetURL ());
612 return false; // indicate double click 'eaten'
613 // return (HandleOpenURL (fURLData.PeekAtURLD ()));
614}
615
616vector<StandardURLStyleMarker::PrivateCmdNumber> StandardURLStyleMarker::GetCmdNumbers () const
617{
618 vector<PrivateCmdNumber> x;
619 x.push_back (eOpenCmdNum);
620 return x;
621}
622
623bool StandardURLStyleMarker::IsCmdEnabled (PrivateCmdNumber cmd) const
624{
625 switch (cmd) {
626 case eOpenCmdNum:
627 return true;
628 default:
629 return inherited::IsCmdEnabled (cmd);
630 }
631}
632
633const Led_URLD& StandardURLStyleMarker::GetURLData () const
634{
635 return fURLData;
636}
637
638void StandardURLStyleMarker::SetURLData (const Led_URLD& urlData)
639{
640 fURLData = urlData;
641}
642
643Led_tString StandardURLStyleMarker::GetDisplayString () const
644{
645 string displayText = fURLData.GetTitle ();
646 if (displayText.empty ()) {
647 displayText = fURLData.GetURL ();
648 }
649 /*
650 * Replace tab characters with space characters, since tabs won't get aligned properly, and wouldn't make much
651 * sense anyhow (SPR#1131).
652 */
653 for (auto i = displayText.begin (); i != displayText.end (); ++i) {
654 if (*i == '\t') {
655 *i = ' ';
656 }
657 }
658 return Led_ANSIString2tString (displayText);
659}
660
661FontSpecification StandardURLStyleMarker::GetDisplayFont (const StyleRunElement& runElement) const
662{
664 if (dynamic_cast<StandardStyleMarker*> (runElement.fMarker) != nullptr) {
665 StandardStyleMarker* sm = dynamic_cast<StandardStyleMarker*> (runElement.fMarker);
666 fsp = sm->fFontSpecification;
667 }
668 else {
669 for (auto i = runElement.fSupercededMarkers.begin (); i != runElement.fSupercededMarkers.end (); ++i) {
670 StandardStyleMarker* sm = dynamic_cast<StandardStyleMarker*> (*i);
671 if (sm != nullptr) {
672 fsp = sm->fFontSpecification;
673 break;
674 }
675 }
676 }
677 fsp.SetPointSize (static_cast<unsigned short> (fsp.GetPointSize () * 1.05));
678 fsp.SetTextColor (Color::kBlue);
679 fsp.SetStyle_Underline (true);
680 return fsp;
681}
682
683#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
684/*
685 ********************************************************************************
686 ************************ StandardMacPictureWithURLStyleMarker ******************
687 ********************************************************************************
688 */
689const Led_ClipFormat StandardMacPictureWithURLStyleMarker::kClipFormats[] = {kPICTClipFormat, StandardURLStyleMarker::kURLDClipFormat};
690const size_t StandardMacPictureWithURLStyleMarker::kClipFormatCount = sizeof (kClipFormats) / sizeof (kClipFormats[0]);
691constexpr Led_PrivateEmbeddingTag StandardMacPictureWithURLStyleMarker::kEmbeddingTag = "Pict&URL";
692constexpr Led_PrivateEmbeddingTag StandardMacPictureWithURLStyleMarker::kOld1EmbeddingTag = "PictWEmbd"; // Only used in Led 2.0b7 - I believe - LGP 960427
693
694StandardMacPictureWithURLStyleMarker::StandardMacPictureWithURLStyleMarker (const Led_Picture* pictData, size_t picSize, const Led_URLD& urlData)
695 : SimpleEmbeddedObjectStyleMarker ()
696 , fPictureHandle (nullptr)
697 ,
698#if qStroika_Foundation_Common_Platform_Windows
699 fPictureSize (0)
700 ,
701#endif
702 fURLData (urlData)
703{
704 RequireNotNull (pictData);
705#if qStroika_Foundation_Common_Platform_MacOS
706 fPictureHandle = (StandardMacPictureStyleMarker::PictureHandle)Led_DoNewHandle (picSize);
707#elif qStroika_Foundation_Common_Platform_Windows
708 fPictureSize = picSize;
709 fPictureHandle = ::GlobalAlloc (GMEM_MOVEABLE, picSize);
710 Execution::ThrowIfNull (fPictureHandle);
711#endif
712 {
713 StackBasedHandleLocker locker (GetPictureHandle ());
714 memcpy (locker.GetPointer (), pictData, picSize);
715 }
716}
717
718StandardMacPictureWithURLStyleMarker::~StandardMacPictureWithURLStyleMarker ()
719{
720 AssertNotNull (fPictureHandle);
721#if qStroika_Foundation_Common_Platform_MacOS
722 ::DisposeHandle (Handle (fPictureHandle));
723#elif qStroika_Foundation_Common_Platform_Windows
724 ::GlobalFree (fPictureHandle);
725#endif
726}
727
728SimpleEmbeddedObjectStyleMarker* StandardMacPictureWithURLStyleMarker::mk (const char* embeddingTag, const void* data, size_t len)
729{
730 Require (memcmp (embeddingTag, kOld1EmbeddingTag, sizeof (kOld1EmbeddingTag)) == 0 or
731 memcmp (embeddingTag, kEmbeddingTag, sizeof (kEmbeddingTag)) == 0);
732
733 if (memcmp (embeddingTag, kOld1EmbeddingTag, sizeof (kOld1EmbeddingTag)) == 0) {
734 Led_Picture* picBuf = (Led_Picture*)data;
735 size_t picSize = Led_ByteSwapFromMac (picBuf->picSize);
736
737 if (picSize >= len) {
738 Execution::Throw (DataExchange::BadFormatException::kThe);
739 }
740 const char* url = ((char*)data) + picSize;
741 size_t urlSize = len - picSize;
742 Assert (urlSize > 0); // cuz of above throw-test above...
743
744 return new StandardMacPictureWithURLStyleMarker (picBuf, Led_ByteSwapFromMac (picBuf->picSize), Led_URLD (url, urlSize));
745 }
746 else {
747 if (len < 4 + 1 + sizeof (Led_Picture)) {
748 Execution::Throw (DataExchange::BadFormatException::kThe);
749 }
750
751 uint32_t picSize = *(uint32_t*)data;
752 picSize = BufToUInt32 (&picSize);
753
754 Led_Picture* picBuf = (Led_Picture*)((char*)data + 4);
755
756 if (picSize + 4 >= len) { // must leave room for ULRD.
757 Execution::Throw (DataExchange::BadFormatException::kThe);
758 }
759 const char* url = ((char*)picBuf) + picSize;
760 size_t urlSize = len - 4 - picSize;
761 Assert (urlSize > 0); // cuz of above throw-test above...
762
763 return new StandardMacPictureWithURLStyleMarker (picBuf, picSize, Led_URLD (url, urlSize));
764 }
765}
766
767SimpleEmbeddedObjectStyleMarker* StandardMacPictureWithURLStyleMarker::mk (ReaderFlavorPackage& flavorPackage)
768{
769 size_t pictLength = flavorPackage.GetFlavorSize (kPICTClipFormat);
770 Memory::StackBuffer<char> buf1{Memory::eUninitialized, pictLength};
771 pictLength = flavorPackage.ReadFlavorData (kPICTClipFormat, pictLength, buf1.data ());
772 Led_Picture* picBuf = (Led_Picture*)(char*)buf1;
773
774 size_t urlSize = flavorPackage.GetFlavorSize (StandardURLStyleMarker::kURLDClipFormat);
775 Memory::StackBuffer<Led_tChar> buf2{Memory::eUninitialized, urlSize};
776 urlSize = flavorPackage.ReadFlavorData (StandardURLStyleMarker::kURLDClipFormat, urlSize, buf2.data ());
777 return new StandardMacPictureWithURLStyleMarker{picBuf, pictLength, Led_URLD{buf2.data (), urlSize}};
778}
779
780void StandardMacPictureWithURLStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/,
781 Tablet* tablet, [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
782 [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
783 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
784{
785 Assert (from + 1 == to);
786 Require (text.PeekAtVirtualText ()[0] == kEmbeddingSentinelChar);
787 StackBasedHandleLocker locker (GetPictureHandle ());
788 MacPictureDrawSegment (GetPictureHandle (), tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
789 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
790 drawInto - Led_Point{0, imager->GetHScrollPos ()}, useBaseLine, pixelsDrawn,
791 Led_GetMacPictSize ((Led_Picture*)locker.GetPointer ()));
792}
793
794void StandardMacPictureWithURLStyleMarker::MeasureSegmentWidth (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
795 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
796 [[maybe_unused]] const Led_tChar* text, DistanceType* distanceResults) const
797{
798 Assert (from + 1 == to);
799 RequireNotNull (text);
800 /*
801 * Though we generally require that:
802 *
803 * Require (text[0] == kEmbeddingSentinelChar);
804 *
805 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
806 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
807 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
808 * character here. We know the right width here anyhow.
809 * See SPR#0821.
810 */
811 StackBasedHandleLocker locker (GetPictureHandle ());
812 distanceResults[0] = Led_GetMacPictWidth ((Led_Picture*)locker.GetPointer ()) + 2 * kDefaultEmbeddingMargin.h;
813}
814
815DistanceType StandardMacPictureWithURLStyleMarker::MeasureSegmentHeight (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
816 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
817{
818 Assert (from + 1 == to);
819 StackBasedHandleLocker locker (GetPictureHandle ());
820 return (Led_GetMacPictHeight ((Led_Picture*)locker.GetPointer ()) + 2 * kDefaultEmbeddingMargin.v);
821}
822
823void StandardMacPictureWithURLStyleMarker::Write (SinkStream& sink)
824{
825 {
826 uint32_t picSize = static_cast<uint32_t> (GetPictureByteSize ());
827 UInt32ToBuf (picSize, &picSize);
828 Assert (sizeof (picSize) == 4);
829 sink.write (&picSize, sizeof (picSize));
830 }
831 StackBasedHandleLocker locker (GetPictureHandle ());
832 sink.write ((Led_Picture*)locker.GetPointer (), GetPictureByteSize ());
833 sink.write (fURLData.PeekAtURLD (), fURLData.GetURLDLength ());
834}
835
836void StandardMacPictureWithURLStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
837{
838 StackBasedHandleLocker locker (GetPictureHandle ());
839 flavorPackage.AddFlavorData (StandardMacPictureStyleMarker::kClipFormat, GetPictureByteSize (), (Led_Picture*)locker.GetPointer ());
840 flavorPackage.AddFlavorData (StandardURLStyleMarker::kURLDClipFormat, fURLData.GetURLDLength (), fURLData.PeekAtURLD ());
841}
842
843bool StandardMacPictureWithURLStyleMarker::HandleOpen ()
844{
845 Led_URLManager::Get ().Open (fURLData.GetURL ());
846 return false; // indicate double click 'eaten'
847}
848
849vector<StandardMacPictureWithURLStyleMarker::PrivateCmdNumber> StandardMacPictureWithURLStyleMarker::GetCmdNumbers () const
850{
851 vector<PrivateCmdNumber> x;
852 x.push_back (eOpenCmdNum);
853 return x;
854}
855
856bool StandardMacPictureWithURLStyleMarker::IsCmdEnabled (PrivateCmdNumber cmd) const
857{
858 switch (cmd) {
859 case eOpenCmdNum:
860 return true;
861 default:
862 return inherited::IsCmdEnabled (cmd);
863 }
864}
865
866const Led_URLD& StandardMacPictureWithURLStyleMarker::GetURLData () const
867{
868 return fURLData;
869}
870
871void StandardMacPictureWithURLStyleMarker::SetURLData (const Led_URLD& urlData)
872{
873 fURLData = urlData;
874}
875
876const char* StandardMacPictureWithURLStyleMarker::GetTag () const
877{
878 return kEmbeddingTag;
879}
880#endif
881
882/*
883 ********************************************************************************
884 **************************** StandardDIBWithURLStyleMarker *********************
885 ********************************************************************************
886 */
887const Led_ClipFormat StandardDIBWithURLStyleMarker::kClipFormats[] = {StandardDIBStyleMarker::kClipFormat, StandardURLStyleMarker::kURLDClipFormat};
888const size_t StandardDIBWithURLStyleMarker::kClipFormatCount = sizeof (kClipFormats) / sizeof (kClipFormats[0]);
889const Led_PrivateEmbeddingTag StandardDIBWithURLStyleMarker::kEmbeddingTag = "DIB&URL";
890
891StandardDIBWithURLStyleMarker::StandardDIBWithURLStyleMarker (const Led_DIB* dibData, const Led_URLD& urlData)
892 : SimpleEmbeddedObjectStyleMarker ()
893 , fDIBData (nullptr)
894 , fURLData (urlData)
895{
896#if qStroika_Foundation_Common_Platform_MacOS
897 RequireNotNull (StandardDIBStyleMarker::sUnsupportedFormatPict); // see class declaration for descriptio
898#endif
899 RequireNotNull (dibData);
900 fDIBData = Led_CloneDIB (dibData);
901}
902
903StandardDIBWithURLStyleMarker::~StandardDIBWithURLStyleMarker ()
904{
905 AssertNotNull (fDIBData);
906 delete fDIBData;
907}
908
909SimpleEmbeddedObjectStyleMarker* StandardDIBWithURLStyleMarker::mk ([[maybe_unused]] const char* embeddingTag, const void* data, size_t len)
910{
911 Require (memcmp (embeddingTag, kEmbeddingTag, sizeof (kEmbeddingTag)) == 0);
912
913 if (len < 4 + 40) {
914 // This is less than we need to peek and see size of DIB...
915 Execution::Throw (DataExchange::BadFormatException::kThe);
916 }
917
918 uint32_t picSize = *(uint32_t*)data;
919 picSize = BufToUInt32 (&picSize);
920
921 Led_DIB* picBuf = (Led_DIB*)((char*)data + 4);
922
923 if (len < picSize) {
924 Execution::Throw (DataExchange::BadFormatException::kThe);
925 }
926
927 if (picSize + 4 >= len) { // must leave room for ULRD.
928 Execution::Throw (DataExchange::BadFormatException::kThe);
929 }
930 const char* url = ((char*)picBuf) + picSize;
931 size_t urlSize = len - 4 - picSize;
932 Assert (urlSize > 0); // cuz of above throw-test above...
933
934 return new StandardDIBWithURLStyleMarker (picBuf, Led_URLD (url, urlSize));
935}
936
937SimpleEmbeddedObjectStyleMarker* StandardDIBWithURLStyleMarker::mk (ReaderFlavorPackage& flavorPackage)
938{
939 size_t length = flavorPackage.GetFlavorSize (StandardDIBStyleMarker::kClipFormat);
940 Memory::StackBuffer<char> buf{Memory::eUninitialized, length};
941 length = flavorPackage.ReadFlavorData (StandardDIBStyleMarker::kClipFormat, length, buf.data ());
942 if (length < 40) {
943 // This is less than we need to peek and see size of DIB...
944 Execution::Throw (DataExchange::BadFormatException::kThe);
945 }
946
947 size_t picSize = Led_GetDIBImageByteCount ((Led_DIB*)(char*)buf);
948 // It appears that sometimes (at least on NT 4.0 beta) that the length of the flavor package is longer
949 // than we expect. I'm guessing this is some optional additional information MS now passes along.
950 // The picts APPEAR to come out looking fine if we ignore this stuff of the end. So continue doing so...
951 if (length != picSize) {
952 // Set a breakpoint here if this worries you...
953 if (length < picSize) {
954 // This is definitely bad!!!
955 Execution::Throw (DataExchange::BadFormatException::kThe);
956 }
957 else {
958 // we'll just ignore the stuff off the end... Hope thats OK - LGP 960429
959 }
960 }
961
962 size_t urlSize = flavorPackage.GetFlavorSize (StandardURLStyleMarker::kURLDClipFormat);
963 Memory::StackBuffer<char> buf2{Memory::eUninitialized, urlSize};
964 urlSize = flavorPackage.ReadFlavorData (StandardURLStyleMarker::kURLDClipFormat, urlSize, buf2.data ());
965
966 return new StandardDIBWithURLStyleMarker{(const Led_DIB*)(char*)buf, Led_URLD{buf2.data (), urlSize}};
967}
968
969void StandardDIBWithURLStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, Tablet* tablet,
970 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
971 [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
972 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
973{
974 Assert (from + 1 == to);
975 Require (text.PeekAtVirtualText ()[0] == kEmbeddingSentinelChar);
976 DIBDrawSegment (fDIBData, tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
977 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
978 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn, Led_GetDIBImageSize (fDIBData));
979}
980
981void StandardDIBWithURLStyleMarker::MeasureSegmentWidth (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
982 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
983 [[maybe_unused]] const Led_tChar* text, DistanceType* distanceResults) const
984{
985 Assert (from + 1 == to);
986 RequireNotNull (text);
987 /*
988 * Though we generally require that:
989 *
990 * Require (text[0] == kEmbeddingSentinelChar);
991 *
992 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
993 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
994 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
995 * character here. We know the right width here anyhow.
996 * See SPR#0821.
997 */
998 distanceResults[0] = Led_GetDIBImageSize (GetDIBData ()).h + 2 * kDefaultEmbeddingMargin.h;
999}
1000
1001DistanceType StandardDIBWithURLStyleMarker::MeasureSegmentHeight (const StyledTextImager* /*imager*/, const StyleRunElement& /*runElement*/,
1002 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
1003{
1004 Assert (from + 1 == to);
1005 return (Led_GetDIBImageSize (GetDIBData ()).v + 2 * kDefaultEmbeddingMargin.v);
1006}
1007
1008void StandardDIBWithURLStyleMarker::Write (SinkStream& sink)
1009{
1010 const Led_DIB* dib = GetDIBData ();
1011 {
1012 uint32_t dibSize = static_cast<uint32_t> (Led_GetDIBImageByteCount (dib));
1013 UInt32ToBuf (dibSize, &dibSize);
1014 Assert (sizeof (dibSize) == 4);
1015 sink.write (&dibSize, sizeof (dibSize));
1016 }
1017 sink.write (dib, Led_GetDIBImageByteCount (dib));
1018 sink.write (fURLData.PeekAtURLD (), fURLData.GetURLDLength ());
1019}
1020
1021void StandardDIBWithURLStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
1022{
1023 const Led_DIB* dib = GetDIBData ();
1024 size_t dibSize = Led_GetDIBImageByteCount (dib);
1025 flavorPackage.AddFlavorData (StandardDIBStyleMarker::kClipFormat, dibSize, dib);
1026 flavorPackage.AddFlavorData (StandardURLStyleMarker::kURLDClipFormat, fURLData.GetURLDLength (), fURLData.PeekAtURLD ());
1027}
1028
1029bool StandardDIBWithURLStyleMarker::HandleOpen ()
1030{
1031 Led_URLManager::Get ().Open (fURLData.GetURL ());
1032 return false; // indicate double click 'eaten'
1033}
1034
1035vector<StandardDIBWithURLStyleMarker::PrivateCmdNumber> StandardDIBWithURLStyleMarker::GetCmdNumbers () const
1036{
1037 vector<PrivateCmdNumber> x;
1038 x.push_back (eOpenCmdNum);
1039 return x;
1040}
1041
1042bool StandardDIBWithURLStyleMarker::IsCmdEnabled (PrivateCmdNumber cmd) const
1043{
1044 switch (cmd) {
1045 case eOpenCmdNum:
1046 return true;
1047 default:
1048 return inherited::IsCmdEnabled (cmd);
1049 }
1050}
1051
1052const Led_URLD& StandardDIBWithURLStyleMarker::GetURLData () const
1053{
1054 return fURLData;
1055}
1056
1057void StandardDIBWithURLStyleMarker::SetURLData (const Led_URLD& urlData)
1058{
1059 fURLData = urlData;
1060}
1061
1062const char* StandardDIBWithURLStyleMarker::GetTag () const
1063{
1064 return kEmbeddingTag;
1065}
1066
1067/*
1068 ********************************************************************************
1069 ************************* StandardUnknownTypeStyleMarker ***********************
1070 ********************************************************************************
1071 */
1072#if qStroika_Foundation_Common_Platform_MacOS
1073Led_Picture** StandardUnknownTypeStyleMarker::sUnknownPict = nullptr;
1074#elif qStroika_Foundation_Common_Platform_Windows
1075const Led_DIB* StandardUnknownTypeStyleMarker::sUnknownPict = nullptr;
1076#endif
1077const Led_PrivateEmbeddingTag StandardUnknownTypeStyleMarker::kDefaultEmbeddingTag = "UnknwnDlf";
1078
1079StandardUnknownTypeStyleMarker::StandardUnknownTypeStyleMarker (Led_ClipFormat format, const char* embeddingTag,
1080 const void* unknownTypeData, size_t nBytes, const Led_DIB* dib)
1081 : SimpleEmbeddedObjectStyleMarker ()
1082 ,
1083 // fShownSize (TWIPS_Point (TWIPS{0}, TWIPS{0})),
1084 fShownSize ()
1085 , fData (nullptr)
1086 , fLength (nBytes)
1087 , fFormat (format)
1088 ,
1089 //fEmbeddingTag (),
1090 fDisplayDIB ()
1091{
1092 memcpy (fEmbeddingTag, embeddingTag, sizeof (fEmbeddingTag));
1093#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
1094 RequireNotNull (sUnknownPict); // If this is ever triggered, see class declaration where we delcare this field
1095#endif
1096 fData = new char[nBytes];
1097 memcpy (fData, unknownTypeData, nBytes);
1098
1099 if (dib != nullptr) {
1100#if qCannotAssignRValueAutoPtrToExistingOneInOneStepBug || qTroubleOverloadingXofXRefCTORWithTemplatedMemberCTOR
1101 unique_ptr<Led_DIB> x = unique_ptr<Led_DIB> (Led_CloneDIB (dib));
1102 fDisplayDIB = x;
1103#else
1104 fDisplayDIB = unique_ptr<Led_DIB> (Led_CloneDIB (dib));
1105#endif
1106 }
1107 fShownSize = CalcDefaultShownSize ();
1108}
1109
1110StandardUnknownTypeStyleMarker::~StandardUnknownTypeStyleMarker ()
1111{
1112 delete[] (char*)fData;
1113}
1114
1115/*
1116@METHOD: StandardUnknownTypeStyleMarker::SetShownSize
1117@DESCRIPTION: <p>See @'StandardUnknownTypeStyleMarker::GetShownSize', or
1118 @'StandardUnknownTypeStyleMarker::CalcDefaultShownSize'.</p>
1119 <p>NB: it is the CALLERs responsability to assure the appropriate
1120 TextInteractors/TextImagers are notified to adjust any caching of size information they may have. This can be avoided
1121 by setting this value BEFORE adding the embedding to the TextStore.</p>
1122*/
1123void StandardUnknownTypeStyleMarker::SetShownSize (TWIPS_Point size)
1124{
1125 fShownSize = size;
1126}
1127
1128/*
1129@METHOD: StandardUnknownTypeStyleMarker::CalcDefaultShownSize
1130@DESCRIPTION: <p>See @'StandardUnknownTypeStyleMarker::GetShownSize'.</p>
1131 <p>Generates a reasonable default size (based on sUnknownPict size) for the embedding. Used unless
1132 overridden by calls to @'StandardUnknownTypeStyleMarker::SetShownSize'.</p>
1133*/
1134TWIPS_Point StandardUnknownTypeStyleMarker::CalcDefaultShownSize ()
1135{
1136 if (fDisplayDIB.get () != nullptr) {
1137 Led_Size pixelSize = Led_GetDIBImageSize (fDisplayDIB.get ());
1138 return TWIPS_Point (Led_CvtScreenPixelsToTWIPSV (pixelSize.v), Led_CvtScreenPixelsToTWIPSH (pixelSize.h));
1139 }
1140 return CalcStaticDefaultShownSize ();
1141}
1142
1143TWIPS_Point StandardUnknownTypeStyleMarker::CalcStaticDefaultShownSize ()
1144{
1145#if qStroika_Foundation_Common_Platform_MacOS
1146 RequireNotNull (sUnknownPict);
1147 StackBasedHandleLocker locker (sUnknownPict);
1148 Led_Size pixelSize = Led_GetMacPictSize (sUnknownPict);
1149#elif qStroika_Foundation_Common_Platform_Windows
1150 RequireNotNull (sUnknownPict);
1151 Led_Size pixelSize = Led_GetDIBImageSize (sUnknownPict);
1152#elif qStroika_FeatureSupported_XWindows
1153 Led_Size pixelSize = Led_Size (10, 10); // X-TMP-HACK-LGP2000-06-13
1154#endif
1155
1156 return TWIPS_Point (Led_CvtScreenPixelsToTWIPSV (pixelSize.v), Led_CvtScreenPixelsToTWIPSH (pixelSize.h));
1157}
1158
1159void StandardUnknownTypeStyleMarker::DrawSegment (const StyledTextImager* imager, const StyleRunElement& /*runElement*/, Tablet* tablet,
1160 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
1161 [[maybe_unused]] const TextLayoutBlock& text, const Led_Rect& drawInto,
1162 const Led_Rect& /*invalidRect*/, CoordinateType useBaseLine, DistanceType* pixelsDrawn)
1163{
1164 Assert (from + 1 == to);
1165 Require (text.PeekAtVirtualText ()[0] == kEmbeddingSentinelChar);
1166 Led_Size shownPixelSize = Led_Size (tablet->CvtFromTWIPSV (fShownSize.v), tablet->CvtFromTWIPSH (fShownSize.h));
1167
1168 if (fDisplayDIB.get () != nullptr) {
1169 DIBDrawSegment (fDisplayDIB.get (), tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
1170 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
1171 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn, shownPixelSize);
1172 return;
1173 }
1174#if qStroika_Foundation_Common_Platform_MacOS
1175 MacPictureDrawSegment (sUnknownPict, tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
1176 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
1177 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn, shownPixelSize);
1178#elif qStroika_Foundation_Common_Platform_Windows
1179 DIBDrawSegment (sUnknownPict, tablet, imager->GetEffectiveDefaultTextColor (TextImager::eDefaultTextColor),
1180 imager->GetEffectiveDefaultTextColor (TextImager::eDefaultBackgroundColor),
1181 drawInto - Led_Point (0, imager->GetHScrollPos ()), useBaseLine, pixelsDrawn, shownPixelSize);
1182#endif
1183}
1184
1185void StandardUnknownTypeStyleMarker::MeasureSegmentWidth (const StyledTextImager* imager, const StyleRunElement& /*runElement*/,
1186 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to,
1187 [[maybe_unused]] const Led_tChar* text, DistanceType* distanceResults) const
1188{
1189 Assert (from + 1 == to);
1190 RequireNotNull (text);
1191 /*
1192 * Though we generally require that:
1193 *
1194 * Require (text[0] == kEmbeddingSentinelChar);
1195 *
1196 * we cannot here - cuz we provent assure we are a one-length marker surrouding a sentinel
1197 * in SimpleEmbeddedObjectStyleMarker::DidUpdateText - which may not have yet been called
1198 * when THIS is called (cuz some other update handlers may force it. No big deal. We just ignore that
1199 * character here. We know the right width here anyhow.
1200 * See SPR#0821.
1201 */
1202 if (fDisplayDIB.get () != nullptr) {
1203 distanceResults[0] = Led_GetDIBImageSize (fDisplayDIB.get ()).h + 2 * kDefaultEmbeddingMargin.h;
1204 return;
1205 }
1206 TextInteractor::Tablet_Acquirer tablet_{imager};
1207 Tablet* tablet = tablet_;
1208 distanceResults[0] = tablet->CvtFromTWIPSH (fShownSize.h) + 2 * kDefaultEmbeddingMargin.h;
1209}
1210
1211DistanceType StandardUnknownTypeStyleMarker::MeasureSegmentHeight (const StyledTextImager* imager, const StyleRunElement& /*runElement*/,
1212 [[maybe_unused]] size_t from, [[maybe_unused]] size_t to) const
1213{
1214 Assert (from + 1 == to);
1215 if (fDisplayDIB.get () != nullptr) {
1216 return (Led_GetDIBImageSize (fDisplayDIB.get ()).v + 2 * kDefaultEmbeddingMargin.v);
1217 }
1218 TextInteractor::Tablet_Acquirer tablet_ (imager);
1219 Tablet* tablet = tablet_;
1220 return tablet->CvtFromTWIPSV (fShownSize.v) + 2 * kDefaultEmbeddingMargin.v;
1221}
1222
1223void StandardUnknownTypeStyleMarker::Write (SinkStream& sink)
1224{
1225 sink.write (fData, fLength);
1226}
1227
1228void StandardUnknownTypeStyleMarker::ExternalizeFlavors (WriterFlavorPackage& flavorPackage)
1229{
1230 flavorPackage.AddFlavorData (fFormat, fLength, fData);
1231}
1232
1233const char* StandardUnknownTypeStyleMarker::GetTag () const
1234{
1235 return fEmbeddingTag;
1236}
1237
1238/*
1239 ********************************************************************************
1240 ************************ InsertEmbeddingForExistingSentinel ********************
1241 ********************************************************************************
1242 */
1243void Led::InsertEmbeddingForExistingSentinel (SimpleEmbeddedObjectStyleMarker* embedding, TextStore& textStore, size_t insertAt, MarkerOwner* ownerForEmbedding)
1244{
1245 RequireNotNull (embedding);
1246 RequireNotNull (ownerForEmbedding);
1247 TextStore::SimpleUpdater updater (textStore, insertAt, insertAt + 1);
1248 textStore.AddMarker (embedding, insertAt, 1, ownerForEmbedding);
1249}
1250
1251/*
1252 ********************************************************************************
1253 ********************************* AddEmbedding *********************************
1254 ********************************************************************************
1255 */
1256void Led::AddEmbedding (SimpleEmbeddedObjectStyleMarker* embedding, TextStore& textStore, size_t insertAt, MarkerOwner* ownerForEmbedding)
1257{
1258 RequireNotNull (embedding);
1259 RequireNotNull (ownerForEmbedding);
1260 textStore.Replace (insertAt, insertAt, &kEmbeddingSentinelChar, 1);
1261 InsertEmbeddingForExistingSentinel (embedding, textStore, insertAt, ownerForEmbedding);
1262}
1263
1264#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
1265/*
1266 ********************************************************************************
1267 ************************** MacPictureDrawSegment *******************************
1268 ********************************************************************************
1269 */
1270static void MacPictureDrawSegment (StandardMacPictureStyleMarker::PictureHandle pictureHandle, Tablet* tablet, Color foreColor,
1271 Color backColor, const Led_Rect& drawInto, CoordinateType useBaseLine, DistanceType* pixelsDrawn,
1272 const Led_Size& imageSize, const Led_Size& margin) noexcept
1273{
1274 RequireNotNull (pictureHandle);
1275
1276 StackBasedHandleLocker locker (pictureHandle);
1277
1278#if qStroika_Foundation_Common_Platform_MacOS
1279 tablet->SetPort ();
1280#elif qStroika_Foundation_Common_Platform_Windows
1281 Tablet* dc = tablet;
1282#endif
1283
1284 Led_Size pictSize = imageSize;
1285
1286 Led_Rect ourBoundsRect = drawInto;
1287 ourBoundsRect.SetRight (ourBoundsRect.GetLeft () + pictSize.h + 2 * margin.h);
1288 CoordinateType embedBottom = useBaseLine;
1289 CoordinateType embedTop = embedBottom - pictSize.v;
1290 Assert (embedTop >= drawInto.top);
1291 Assert (embedBottom <= drawInto.bottom);
1292 Led_Rect innerBoundsRect = Led_Rect (Led_Point (embedTop, drawInto.GetLeft () + margin.h), pictSize);
1293
1294#if qStroika_Foundation_Common_Platform_MacOS
1295 GDI_RGBForeColor (foreColor.GetOSRep ());
1296 GDI_RGBBackColor (backColor.GetOSRep ());
1297#elif qStroika_Foundation_Common_Platform_Windows
1298 dc->SetTextColor (foreColor.GetOSRep ());
1299 dc->SetBkColor (backColor.GetOSRep ());
1300#endif
1301 if (pixelsDrawn != nullptr) {
1302 *pixelsDrawn = ourBoundsRect.GetWidth ();
1303 }
1304}
1305#endif
1306
1307static void DIBDrawSegment (const Led_DIB* dib, Tablet* tablet, [[maybe_unused]] Color foreColor, [[maybe_unused]] Color backColor,
1308 const Led_Rect& drawInto, CoordinateType useBaseLine, DistanceType* pixelsDrawn, const Led_Size& imageSize,
1309 const Led_Size& margin) noexcept
1310{
1311 RequireNotNull (dib);
1312 RequireNotNull (tablet);
1313
1314#if qStroika_Foundation_Common_Platform_MacOS
1315 tablet->SetPort ();
1316#elif qStroika_Foundation_Common_Platform_Windows
1317 Tablet* dc = tablet;
1318#endif
1319
1320 Led_Size dibImageSize = imageSize;
1321
1322 Led_Rect ourBoundsRect = drawInto;
1323 ourBoundsRect.right = ourBoundsRect.left + dibImageSize.h + 2 * margin.h;
1324 CoordinateType embedBottom = useBaseLine;
1325 CoordinateType embedTop = embedBottom - dibImageSize.v;
1326 Assert (embedTop >= drawInto.GetTop ());
1327 Assert (embedBottom <= drawInto.GetBottom ());
1328 Led_Rect innerBoundsRect = Led_Rect (Led_Point (embedTop, drawInto.GetLeft () + margin.h), dibImageSize);
1329
1330 if (pixelsDrawn != nullptr) {
1331 *pixelsDrawn = ourBoundsRect.GetWidth ();
1332 }
1333
1334#if qStroika_Foundation_Common_Platform_MacOS
1335#if 1
1336 GDI_RGBForeColor (Color::kBlack.GetOSRep ());
1337 GDI_RGBBackColor (Color::kWhite.GetOSRep ());
1338#else
1339 GDI_RGBForeColor (foreColor.GetOSRep ());
1340 GDI_RGBBackColor (backColor.GetOSRep ());
1341#endif
1342#elif qStroika_Foundation_Common_Platform_Windows
1343 dc->SetTextColor (foreColor.GetOSRep ());
1344 dc->SetBkColor (backColor.GetOSRep ());
1345#endif
1346
1347#if qStroika_Foundation_Common_Platform_MacOS
1348 // Must erase above the picture, and below it. And
1349 Rect rr = AsQDRect (innerBoundsRect);
1350
1351 // Turn the DIB into a pixmap, and then image it, and free it again...
1352 try {
1353 PixMap** pm = MakePixMapFromDIB (dib);
1354 PixMap* pmPtr = *pm;
1355 GrafPtr destPort = *tablet;
1356#if TARGET_CARBON
1357 ::CopyBits (reinterpret_cast<BitMap*> (pmPtr), GetPortBitMapForCopyBits (destPort), &pmPtr->bounds, &rr, srcCopy, nullptr);
1358#else
1359 ::CopyBits (reinterpret_cast<BitMap*> (pmPtr), &destPort->portBits, &pmPtr->bounds, &rr, srcCopy, nullptr);
1360#endif
1361 delete[] (char*)pmPtr->baseAddr;
1362 ::DisposePixMap (pm);
1363 }
1364 catch (...) {
1365 // treat all excpetions the same. In principle, could draw different picst for memory and
1366 // unsupported format exceptions...
1367 AssertNotNull (StandardDIBStyleMarker::sUnsupportedFormatPict);
1368 ::DrawPicture (StandardDIBStyleMarker::sUnsupportedFormatPict, &rr);
1369 }
1370#elif qStroika_Foundation_Common_Platform_Windows
1371 //const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1372 const void* lpBits = Led_GetDIBBitsPointer (dib);
1373 //const char* lpBits = ((const char*)dib) + Led_ByteSwapFromWindows (hdr.biSize) + Led_GetDIBPalletByteCount (dib);
1374 ::StretchDIBits (dc->m_hDC, innerBoundsRect.left, innerBoundsRect.top, innerBoundsRect.GetWidth (), innerBoundsRect.GetHeight (), 0, 0,
1375 dibImageSize.h, dibImageSize.v, lpBits, dib, DIB_RGB_COLORS, SRCCOPY);
1376#endif
1377}
1378
1379#if qStroika_Foundation_Common_Platform_MacOS
1380static PixMap** MakePixMapFromDIB (const Led_DIB* dib)
1381{
1382 RequireNotNull (dib);
1383
1384 Led_Size dibImageSize = Led_GetDIBImageSize (dib);
1385
1386 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1387 const RGBQUAD* srcCLUT = (const RGBQUAD*)(((const unsigned char*)dib) + Led_ByteSwapFromWindows (hdr.biSize));
1388 const unsigned char* srcBits = ((const unsigned char*)srcCLUT) + Led_GetDIBPalletByteCount (dib);
1389 unsigned short bitCount = Led_ByteSwapFromWindows (hdr.biBitCount);
1390 size_t srcRowBytes = (((dibImageSize.h * bitCount + 31) & ~31) >> 3);
1391
1392 if (bitCount != 8 and bitCount != 24) { // only supported sizes, for now...
1393 // LGP 960430
1394 throw UnsupportedFormat ();
1395 }
1396
1397 if (hdr.biCompression != 0) { // unsupported for now, thought here is DECODE code on the 'Encyclopedia of Graphix Formats' CD
1398 // LGP 960430
1399 throw UnsupportedFormat ();
1400 }
1401
1402 if (bitCount > 8) {
1403 srcCLUT = 0;
1404 }
1405
1406 // make sure CLUT looks good...
1407 if (srcCLUT != nullptr) {
1408 size_t nColors = Led_ByteSwapFromWindows (hdr.biClrUsed);
1409 if (nColors > (1 << bitCount)) {
1410 throw UnsupportedFormat (); // really bad format, probably...
1411 }
1412 }
1413
1414 size_t dstBitCount = bitCount;
1415 if (bitCount == 24) {
1416 dstBitCount = 32;
1417 }
1418 size_t dstRowBytes = ((((dstBitCount * dibImageSize.h) + 15) >> 4) << 1);
1419 unsigned char* newImageData = new unsigned char[dstRowBytes * dibImageSize.v];
1420 AssertNotNull (newImageData);
1421
1422 PixMap** result = ::NewPixMap ();
1423 if (result == nullptr) {
1424 delete[] (char*)newImageData;
1425 Execution::Throw (bad_alloc{});
1426 }
1427 (*result)->bounds.top = 0;
1428 (*result)->bounds.left = 0;
1429 (*result)->bounds.bottom = dibImageSize.v;
1430 (*result)->bounds.right = dibImageSize.h;
1431
1432 (*result)->baseAddr = Ptr (newImageData);
1433
1434 switch (bitCount) {
1435 case 8: {
1436 (*result)->rowBytes = 0x8000 | dstRowBytes;
1437 (*result)->cmpCount = 1;
1438 (*result)->cmpSize = 8;
1439 (*result)->pixelType = chunky;
1440 (*result)->pixelSize = 8;
1441 } break;
1442
1443 case 24: {
1444 (*result)->rowBytes = 0x8000 | dstRowBytes;
1445 (*result)->cmpCount = 3;
1446 (*result)->cmpSize = 8;
1447 (*result)->pixelType = RGBDirect;
1448 (*result)->pixelSize = 32;
1449 } break;
1450
1451 default: {
1452 Assert (false); // not supported - should have punted above!
1453 } break;
1454 }
1455
1456 /*
1457 * Copy the CLUT data.
1458 */
1459 if (srcCLUT != nullptr) { // 'if' so support 24-bit and no CLUT!!!
1460 size_t nColors = Led_ByteSwapFromWindows (hdr.biClrUsed);
1461 if (nColors == 0) {
1462 nColors = 1 << bitCount;
1463 }
1464 Assert (nColors <= (1 << bitCount));
1465
1466 CTabHandle newCLUT = (CTabHandle)::NewHandle (sizeof (ColorTable) + (nColors - 1) * sizeof (ColorSpec));
1467 if (newCLUT == nullptr) {
1468 delete[] (char*)newImageData;
1469 ::DisposePixMap (result);
1470 Execution::Throw (bad_alloc{});
1471 }
1472 (*newCLUT)->ctSeed = ::GetCTSeed ();
1473 (*newCLUT)->ctFlags = 0;
1474 (*newCLUT)->ctSize = nColors - 1;
1475 for (size_t i = 0; i < nColors; ++i) {
1476 (*newCLUT)->ctTable[i].value = i;
1477 (*newCLUT)->ctTable[i].rgb.red = srcCLUT[i].rgbRed << 8;
1478 (*newCLUT)->ctTable[i].rgb.green = srcCLUT[i].rgbGreen << 8;
1479 (*newCLUT)->ctTable[i].rgb.blue = srcCLUT[i].rgbBlue << 8;
1480 }
1481 if ((*result)->pmTable != nullptr) {
1482 ::DisposeCTable ((*result)->pmTable);
1483 }
1484 (*result)->pmTable = newCLUT;
1485 ::CTabChanged (newCLUT);
1486 }
1487
1488 /*
1489 * Copy the PixMap data.
1490 */
1491 bool rowsReversed = (Led_ByteSwapFromWindows (hdr.biHeight) > 0);
1492 for (size_t row = 0; row < dibImageSize.v; ++row) {
1493 const unsigned char* srcRow = srcBits + (rowsReversed ? (dibImageSize.v - row - 1) : row) * srcRowBytes;
1494 unsigned char* dstRow = newImageData + row * dstRowBytes;
1495
1496 switch (bitCount) {
1497 case 8: {
1498 // we use the same CLUT, so this should be OK
1499 memcpy (dstRow, srcRow, min (srcRowBytes, dstRowBytes));
1500 } break;
1501
1502 case 24: {
1503 for (size_t col = 0; col < dibImageSize.h; ++col) {
1504 const unsigned char* srcCell = srcRow + 3 * col;
1505 unsigned char* dstCell = dstRow + 4 * col;
1506 unsigned char blueComp = *srcCell++;
1507 unsigned char greenComp = *srcCell++;
1508 unsigned char redComp = *srcCell++;
1509 *dstCell++ = 0;
1510 *dstCell++ = redComp;
1511 *dstCell++ = greenComp;
1512 *dstCell++ = blueComp;
1513 }
1514 } break;
1515
1516 default: {
1517 // too bad, we don't support that size - just zero out the memory...
1518 memset (dstRow, 0, dstRowBytes);
1519 } break;
1520 }
1521 }
1522
1523 return result;
1524}
1525#endif
1526#endif
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
virtual size_t GetFlavorSize(Led_ClipFormat clipFormat) const =0
basic_string< SDKChar > SDKString
Definition SDKString.h:38
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43
void ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...