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