4#include "Stroika/Frameworks/StroikaPreComp.h"
9#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
11#include "BiDiLayoutEngine.h"
13#if qTryToUseUNISCRIBEForTextRuns
22#include "unicode/ubidi.h"
28#ifndef qBuildMemoizedBiDiLevelProc
29#define qBuildMemoizedBiDiLevelProc 0
32#if qBuildMemoizedBiDiLevelProc
40using namespace Stroika::Frameworks;
41using namespace Stroika::Frameworks::Led;
51#ifndef qDebugHack_ReverseDirections
52#define qDebugHack_ReverseDirections 0
60#ifndef qDebugHack_UpperCaseCharsTratedAsRTL
61#define qDebugHack_UpperCaseCharsTratedAsRTL 0
70#ifndef qTestUNISCRIBEResultsEqualFriBidi
71#if qStroika_Foundation_Debug_AssertionsChecked && qTryToUseUNISCRIBEForTextRuns && qUseFriBidi
73#define qTestUNISCRIBEResultsEqualFriBidi 1
77#if qTryToUseUNISCRIBEForTextRuns
78enum InitialUNISCRIBEDir {
83static InitialUNISCRIBEDir myGetInitialUNISCRIBEDir (
wchar_t c);
89#ifndef qTestMyWriteMemoizedUniscribeDirFunction
90#define qTestMyWriteMemoizedUniscribeDirFunction (qUseFriBidi && qTryToUseUNISCRIBEForTextRuns)
93#if qTestMyWriteMemoizedUniscribeDirFunction || qBuildMemoizedBiDiLevelProc
95 InitialUNISCRIBEDir GetInitialUNISCRIBEDir (
wchar_t c)
97 FriBidiCharType ct = fribidi_get_type (c);
98 if (FRIBIDI_IS_LETTER (ct)) {
99 if (FRIBIDI_DIR_TO_LEVEL (ct) & 1) {
113#if qBuildMemoizedBiDiLevelProc
115 template <
class FUNCTION>
116 void WriteMemoizedUniscribeDirProc (FUNCTION function,
const string& origFunctionName,
const string& functionName)
118 ofstream outStream (
"IsXXXProc.txt");
121 outStream <<
" ********************************************************************************\n";
122 outStream <<
" ********** " << functionName <<
" (AUTOGENERATED memoize of " << origFunctionName <<
" - " << __DATE__ <<
") ***********\n";
123 outStream <<
" ********************************************************************************\n";
124 outStream <<
" */\n";
125 outStream <<
"// Hack for SPR#1236\n";
126 outStream <<
"InitialUNISCRIBEDir " << functionName <<
" (wchar_t c)\n";
129 bool firstTime =
true;
130 InitialUNISCRIBEDir lastIST = eNeutralChar;
131 size_t firstRangeIdxTrue = 0;
132 for (
size_t i = 0; i < 256 * 256; ++i) {
133 InitialUNISCRIBEDir isT = function (
static_cast<wchar_t> (i));
137 if (isT != lastIST or i >= 256 * 256 - 1) {
138 if (lastIST != eNeutralChar) {
140 outStream <<
"\tif (" << firstRangeIdxTrue <<
" <= c && c <= " << i - 1 <<
") {\n";
143 outStream <<
"\t\treturn eNeutralChar;\n";
146 outStream <<
"\t\treturn eRTLChar;\n";
149 outStream <<
"\t\treturn eLTRChar;\n";
152 outStream <<
"\t}\n";
155 firstRangeIdxTrue = i;
158 outStream <<
"\treturn eNeutralChar;\n";
166 WriteMemoizedUniscribeDirProc (GetInitialUNISCRIBEDir,
"GetInitialUNISCRIBEDir",
"myGetInitialUNISCRIBEDir");
172#if qTestMyWriteMemoizedUniscribeDirFunction
173class MyIWriteMemoizedUniscribeDirFunction {
175 MyIWriteMemoizedUniscribeDirFunction ()
177 for (
wchar_t c = 0; c < 0xffff; ++c) {
178 Assert (GetInitialUNISCRIBEDir (c) == myGetInitialUNISCRIBEDir (c));
181} aMyIWriteMemoizedUniscribeDirFunction;
184#if qStroika_Foundation_Common_Platform_Windows && qTryToUseUNISCRIBEForTextRuns
191 struct UniscribeDLL {
193 : fDLL (::LoadLibrary (_T (
"Usp10.dll")))
194 , fScriptItemize (nullptr)
195 , fScriptLayout (nullptr)
197 if (fDLL !=
nullptr) {
198 fScriptItemize = (HRESULT (WINAPI*) (
const WCHAR*, int, int,
const SCRIPT_CONTROL*,
const SCRIPT_STATE*, SCRIPT_ITEM*,
199 int*)) (::GetProcAddress (fDLL,
"ScriptItemize"));
200 fScriptLayout = (HRESULT (WINAPI*) (int,
const BYTE*,
int*,
int*)) (::GetProcAddress (fDLL,
"ScriptLayout"));
206 if (fDLL !=
nullptr) {
207 Verify (::FreeLibrary (fDLL));
211 nonvirtual
bool IsAvail ()
const
213 return fDLL !=
nullptr;
216 HRESULT WINAPI ScriptItemize (
const WCHAR* pwcInChars,
int cInChars,
int cMaxItems,
const SCRIPT_CONTROL* psControl,
217 const SCRIPT_STATE* psState, SCRIPT_ITEM* pItems,
int* pcItems)
219 if (fScriptItemize ==
nullptr) {
222 return (*fScriptItemize) (pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pcItems);
225 HRESULT WINAPI ScriptLayout (
int cRuns,
const BYTE* pbLevel,
int* piVisualToLogical,
int* piLogicalToVisual)
227 if (fScriptLayout ==
nullptr) {
230 return (*fScriptLayout) (cRuns, pbLevel, piVisualToLogical, piLogicalToVisual);
234 HRESULT (WINAPI* fScriptItemize)
235 (
const WCHAR*, int, int,
const SCRIPT_CONTROL*,
const SCRIPT_STATE*, SCRIPT_ITEM*,
int*);
236 HRESULT (WINAPI* fScriptLayout)
237 (int,
const BYTE*,
int*,
int*);
239 static UniscribeDLL sUniscribeDLL;
252TextDirection TextLayoutBlock::GetCharacterDirection (
size_t realCharOffset)
const
254 vector<ScriptRunElt> runs = GetScriptRuns ();
255 for (
auto i = runs.begin (); i != runs.end (); ++i) {
256 if ((*i).fRealStart <= realCharOffset and realCharOffset < (*i).fRealEnd) {
257 return (*i).fDirection;
268size_t TextLayoutBlock::MapRealOffsetToVirtual (
size_t )
const
278size_t TextLayoutBlock::MapVirtualOffsetToReal (
size_t i)
const
280 Require (i < GetTextLength ());
281 vector<ScriptRunElt> runs = GetScriptRuns ();
282 for (
auto runIt = runs.begin (); runIt != runs.end (); ++runIt) {
283 const ScriptRunElt& se = *runIt;
284 if (se.fVirtualStart <= i and i < se.fVirtualEnd) {
285 if (se.fDirection == eLeftToRight) {
286 size_t result = (i - se.fVirtualStart) + se.fRealStart;
287 Ensure (result < GetTextLength ());
291 size_t segLen = se.fRealEnd - se.fRealStart;
292 size_t result = (segLen - (i - se.fVirtualStart)) - 1 + se.fRealStart;
293 Ensure (result < GetTextLength ());
302void TextLayoutBlock::CopyOutRealText (
const ScriptRunElt& scriptRunElt, Led_tChar* buf)
const
304 const Led_tChar* s =
nullptr;
305 const Led_tChar* e =
nullptr;
306 PeekAtRealText (scriptRunElt, &s, &e);
310void TextLayoutBlock::CopyOutVirtualText (
const ScriptRunElt& scriptRunElt, Led_tChar* buf)
const
312 const Led_tChar* s =
nullptr;
313 const Led_tChar* e =
nullptr;
314 PeekAtVirtualText (scriptRunElt, &s, &e);
318void TextLayoutBlock::PeekAtRealText (
const ScriptRunElt& scriptRunElt,
const Led_tChar** startText,
const Led_tChar** endText)
const
322 PeekAtRealText_ (startText, endText);
323 *startText += scriptRunElt.fRealStart;
324 size_t len = scriptRunElt.fRealEnd - scriptRunElt.fRealStart;
325 Assert (*endText - *startText >=
static_cast<ptrdiff_t
> (len));
326 *endText = *startText + len;
329Led_tString TextLayoutBlock::GetRealText ()
const
331 const Led_tChar* s =
nullptr;
332 const Led_tChar* e =
nullptr;
333 PeekAtRealText_ (&s, &e);
334 return Led_tString{s, e};
337Led_tString TextLayoutBlock::GetRealText (
const ScriptRunElt& scriptRunElt)
const
339 const Led_tChar* s =
nullptr;
340 const Led_tChar* e =
nullptr;
341 PeekAtRealText (scriptRunElt, &s, &e);
342 return Led_tString{s, e};
345void TextLayoutBlock::PeekAtVirtualText (
const ScriptRunElt& scriptRunElt,
const Led_tChar** startText,
const Led_tChar** endText)
const
349 PeekAtVirtualText_ (startText, endText);
350 *startText += scriptRunElt.fVirtualStart;
351 size_t len = scriptRunElt.fVirtualEnd - scriptRunElt.fVirtualStart;
352 Assert (*endText - *startText >=
static_cast<ptrdiff_t
> (len));
353 *endText = *startText + len;
356Led_tString TextLayoutBlock::GetVirtualText ()
const
358 const Led_tChar* s =
nullptr;
359 const Led_tChar* e =
nullptr;
360 PeekAtVirtualText_ (&s, &e);
361 return Led_tString{s, e};
364Led_tString TextLayoutBlock::GetVirtualText (
const ScriptRunElt& scriptRunElt)
const
366 const Led_tChar* s =
nullptr;
367 const Led_tChar* e =
nullptr;
368 PeekAtVirtualText (scriptRunElt, &s, &e);
369 return Led_tString{s, e};
372#if qStroika_Foundation_Debug_AssertionsChecked
373void TextLayoutBlock::Invariant_ ()
const
375 size_t len = GetTextLength ();
377 vector<ScriptRunElt> scriptRuns = GetScriptRuns ();
381 for (
auto j = scriptRuns.begin (); j != scriptRuns.end (); ++j) {
382 Assert ((*j).fRealStart < len);
383 Assert ((*j).fRealEnd <= len);
384 Assert ((*j).fVirtualStart < len);
385 Assert ((*j).fVirtualEnd <= len);
386 Assert ((*j).fRealStart < (*j).fRealEnd);
396 for (
size_t i = 0; i < len; ++i) {
398 bool foundReal =
false;
399 bool foundVirtual =
false;
400 size_t nRealFound = 0;
401 size_t nVirtualFound = 0;
402 for (
auto j = scriptRuns.begin (); j != scriptRuns.end (); ++j) {
403 if ((*j).fRealStart <= i and i < (*j).fRealEnd) {
404 Assert (not foundReal);
407 Assert ((*j).fVirtualStart < (*j).fVirtualEnd);
408 if ((*j).fVirtualStart <= i and i < (*j).fVirtualEnd) {
409 Assert (not foundVirtual);
412 nRealFound += (*j).fRealEnd - (*j).fRealStart;
413 nVirtualFound += (*j).fVirtualEnd - (*j).fVirtualStart;
416 Assert (foundVirtual);
417 Assert (nRealFound == len);
418 Assert (nVirtualFound == len);
424bool TextLayoutBlock::operator== (
const TextLayoutBlock& rhs)
const
426 if (this->GetTextLength () != rhs.GetTextLength ()) {
429 if (this->GetRealText () != rhs.GetRealText ()) {
432 if (this->GetVirtualText () != rhs.GetVirtualText ()) {
435 vector<TextLayoutBlock::ScriptRunElt> lhsSR = this->GetScriptRuns ();
436 vector<TextLayoutBlock::ScriptRunElt> rhsSR = rhs.GetScriptRuns ();
437 if (lhsSR.size () != rhsSR.size ()) {
440 for (
size_t i = 0; i < lhsSR.size (); ++i) {
441 if (lhsSR[i] != rhsSR[i]) {
453TextLayoutBlock_Basic::TextLayoutBlock_Basic (
const Led_tChar* realText,
const Led_tChar* realTextEnd)
459 Construct (realText, realTextEnd,
nullptr);
462TextLayoutBlock_Basic::TextLayoutBlock_Basic (
const Led_tChar* realText,
const Led_tChar* realTextEnd, TextDirection initialDirection)
468 Construct (realText, realTextEnd, &initialDirection);
471void TextLayoutBlock_Basic::Construct (
const Led_tChar* realText,
const Led_tChar* realTextEnd, [[maybe_unused]]
const TextDirection* initialDirection)
473 size_t textLength = realTextEnd - realText;
474 fTextLength = textLength;
475 fRealText.GrowToSize (textLength);
476 fVirtualText.GrowToSize (textLength);
477 copy (realText, realText + textLength,
static_cast<Led_tChar*
> (fRealText));
479#if qDebugHack_UpperCaseCharsTratedAsRTL
480 for (
size_t i = 0; i < textLength; ++i) {
481 if (
'A' <= fRealText[i] and fRealText[i] <=
'Z') {
482 fRealText[i] = 0xfe7d;
490#if qTestUNISCRIBEResultsEqualFriBidi
491 (void)Construct_UNISCRIBE (initialDirection);
493 copy (
static_cast<const Led_tChar*
> (fVirtualText),
static_cast<const Led_tChar*
> (fVirtualText) + fTextLength,
494 static_cast<Led_tChar*
> (savedVirtualText));
495 vector<ScriptRunElt> savedScriptRuns = fScriptRuns;
496 fScriptRuns = vector<ScriptRunElt> ();
497 Construct_FriBidi (initialDirection);
499 for (
size_t i = 0; i < fTextLength; ++i) {
500 Assert (savedVirtualText[i] == fVirtualText[i]);
504 Assert (savedScriptRuns.size () == fScriptRuns.size ());
505 for (
size_t i = 0; i < savedScriptRuns.size (); ++i) {
506 Assert (savedScriptRuns[i] == fScriptRuns[i]);
511 Construct_FriBidi (initialDirection);
515#elif qTryToUseUNISCRIBEForTextRuns
516 if (Construct_UNISCRIBE (initialDirection)) {
520 Construct_ICU (initialDirection);
526 Construct_Default ();
530 if constexpr (qDebugHack_ReverseDirections) {
531 for (
auto i = fScriptRuns.begin (); i != fScriptRuns.end (); ++i) {
532 ScriptRunElt& se = *i;
533 TextDirection newDir = (se.fDirection == eLeftToRight) ? eRightToLeft : eLeftToRight;
534 se.fDirection = newDir;
536 size_t runLen = se.fVirtualEnd - se.fVirtualStart;
538 for (
size_t j = se.fVirtualStart; j < se.fVirtualEnd; ++j) {
539 reverseBuf[runLen - 1 - (j - se.fVirtualStart)] = fVirtualText[j];
541 copy (
static_cast<Led_tChar*
> (reverseBuf),
static_cast<Led_tChar*
> (reverseBuf) + runLen,
542 static_cast<Led_tChar*
> (fVirtualText) + se.fVirtualStart);
549#if qTryToUseUNISCRIBEForTextRuns
550bool TextLayoutBlock_Basic::Construct_UNISCRIBE (
const TextDirection* initialDirection)
552 if (sUniscribeDLL.IsAvail () and fTextLength > 0) {
557 int nScriptItems = 0;
558 SCRIPT_CONTROL scriptControl;
559 SCRIPT_STATE scriptState;
560 memset (&scriptControl, 0,
sizeof (scriptControl));
561 memset (&scriptState, 0,
sizeof (scriptState));
565 InitialUNISCRIBEDir dir = eNeutralChar;
566 if (initialDirection ==
nullptr) {
567 size_t maxToCheck = min (fTextLength,
size_t (100));
570 for (
size_t i = 0; i < maxToCheck; ++i) {
571 dir = myGetInitialUNISCRIBEDir (fRealText[i]);
572 if (dir != eNeutralChar) {
578 dir = (*initialDirection == eLeftToRight) ? eLTRChar : eRTLChar;
580 if (dir == eRTLChar) {
581 scriptState.uBidiLevel = 1;
584 Verify (sUniscribeDLL.ScriptItemize (
static_cast<const Led_tChar*
> (fRealText), fTextLength, fTextLength + 1, &scriptControl,
585 &scriptState, scriptItems, &nScriptItems) == S_OK);
586 Assert (nScriptItems >= 1);
589 for (
size_t i = 0; i < static_cast<size_t> (nScriptItems); ++i) {
590 bidiLevels[i] = scriptItems[i].a.s.uBidiLevel;
596 Verify (sUniscribeDLL.ScriptLayout (nScriptItems, bidiLevels, visualToLogical, logicalToVisual) == S_OK);
606 Assert (nScriptItems > 0);
607 visualSegStarts[0] = 0;
608 for (
size_t visIndex = 1; visIndex < static_cast<size_t> (nScriptItems); ++visIndex) {
609 size_t prevLogIdx = visualToLogical[visIndex - 1];
610 size_t prevItemWidth = scriptItems[prevLogIdx + 1].iCharPos - scriptItems[prevLogIdx].iCharPos;
611 visualSegStarts[visIndex] = visualSegStarts[visIndex - 1] + prevItemWidth;
616 const Led_tChar* rT =
static_cast<Led_tChar*
> (fRealText);
617 Led_tChar* vT =
static_cast<Led_tChar*
> (fVirtualText);
619 for (
size_t i = 0; i < static_cast<size_t> (nScriptItems); ++i) {
620 TextDirection curDir = (bidiLevels[i] & 1) ? eRightToLeft : eLeftToRight;
624 s.fDirection = curDir;
625 s.fRealStart = scriptItems[i].iCharPos;
626 s.fRealEnd = scriptItems[i + 1].iCharPos;
628#if qStroika_Foundation_Debug_AssertionsChecked
630 for (
size_t j = 0; j < static_cast<size_t> (nScriptItems); ++j) {
631 Assert (logicalToVisual[visualToLogical[i]] == i);
634 size_t referenceVirtualStart = 0;
636 referenceVirtualStart = 0;
637 for (
int visIndex = logicalToVisual[i] - 1; visIndex >= 0; --visIndex) {
638 Assert (visIndex < nScriptItems);
639 size_t itsLogIdx = visualToLogical[visIndex];
640 referenceVirtualStart += (scriptItems[itsLogIdx + 1].iCharPos - scriptItems[itsLogIdx].iCharPos);
643 Assert (referenceVirtualStart == visualSegStarts[logicalToVisual[i]]);
648 s.fVirtualStart = visualSegStarts[logicalToVisual[i]];
649 s.fVirtualEnd = s.fVirtualStart + (s.fRealEnd - s.fRealStart);
650 Assert (s.fVirtualEnd - s.fVirtualStart == s.fRealEnd - s.fRealStart);
665 const bool kDoMerging =
true;
667 if (fScriptRuns.empty ()) {
669 e.fRealEnd = e.fRealStart;
670 e.fVirtualEnd = e.fVirtualStart;
671 fScriptRuns.push_back (e);
673 ScriptRunElt& lastElt = fScriptRuns.back ();
675 if (lastElt.fDirection == s.fDirection and (lastElt.fRealEnd == s.fRealStart or lastElt.fRealStart == s.fRealEnd) and
676 (lastElt.fVirtualEnd == s.fVirtualStart or lastElt.fVirtualStart == s.fVirtualEnd)) {
677 lastElt.fRealStart = min (lastElt.fRealStart, s.fRealStart);
678 lastElt.fRealEnd = max (lastElt.fRealEnd, s.fRealEnd);
679 lastElt.fVirtualStart = min (lastElt.fVirtualStart, s.fVirtualStart);
680 lastElt.fVirtualEnd = max (lastElt.fVirtualEnd, s.fVirtualEnd);
683 fScriptRuns.push_back (s);
687 fScriptRuns.push_back (s);
690 if (curDir == eLeftToRight) {
691 copy (rT + s.fRealStart, rT + s.fRealEnd, vT + s.fVirtualStart);
694 reverse_copy (rT + s.fRealStart, rT + s.fRealEnd, vT + s.fVirtualStart);
698 for (
auto cur = vT + s.fVirtualStart; cur < vT + s.fVirtualStart + (s.fRealEnd - s.fRealStart); ++cur) {
699 Led_tChar mirrorChar =
'\0';
700 if (CharacterProperties::IsMirrored (*cur, &mirrorChar)) {
715void TextLayoutBlock_Basic::Construct_FriBidi (
const TextDirection* initialDirection)
717 Assert (fTextLength <= FRIBIDI_MAX_STRING_LENGTH);
719 FriBidiCharType baseDir = FRIBIDI_TYPE_ON;
721 if (initialDirection !=
nullptr) {
722 baseDir = (*initialDirection == eLeftToRight) ? FRIBIDI_TYPE_L : FRIBIDI_TYPE_R;
726 copy (
static_cast<Led_tChar*
> (fRealText), fRealText + fTextLength,
static_cast<FriBidiChar*
> (srcText));
731 bool result = ::fribidi_log2vis (srcText, fTextLength, &baseDir, vText, posLtoVList,
nullptr, bidiLevels);
735 for (
size_t i = 0; i < fTextLength; ++i) {
736 TextDirection curDir = (bidiLevels[i] & 1) ? eRightToLeft : eLeftToRight;
739 ScriptRunElt thisCharElt;
740 thisCharElt.fDirection = curDir;
741 thisCharElt.fRealStart = i;
742 thisCharElt.fRealEnd = thisCharElt.fRealStart + 1;
743 thisCharElt.fVirtualStart = posLtoVList[i];
744 thisCharElt.fVirtualEnd = thisCharElt.fVirtualStart + 1;
747 ScriptRunElt s = thisCharElt;
748 s.fRealEnd = s.fRealStart;
749 s.fVirtualEnd = s.fVirtualStart;
750 fScriptRuns.push_back (s);
752 ScriptRunElt& lastElt = fScriptRuns[fScriptRuns.size () - 1];
762 if (lastElt.fDirection == thisCharElt.fDirection and
763 (lastElt.fRealEnd == thisCharElt.fRealStart or lastElt.fRealStart == thisCharElt.fRealEnd) and
764 (lastElt.fVirtualEnd == thisCharElt.fVirtualStart or lastElt.fVirtualStart == thisCharElt.fVirtualEnd)) {
765 lastElt.fRealStart = min (lastElt.fRealStart, thisCharElt.fRealStart);
766 lastElt.fRealEnd = max (lastElt.fRealEnd, thisCharElt.fRealEnd);
767 lastElt.fVirtualStart = min (lastElt.fVirtualStart, thisCharElt.fVirtualStart);
768 lastElt.fVirtualEnd = max (lastElt.fVirtualEnd, thisCharElt.fVirtualEnd);
771 fScriptRuns.push_back (thisCharElt);
776 copy (
static_cast<FriBidiChar*
> (vText), vText + fTextLength,
static_cast<Led_tChar*
> (fVirtualText));
781void TextLayoutBlock_Basic::Construct_ICU (
const TextDirection* initialDirection)
784 UErrorCode err = U_ZERO_ERROR;
785 UBiDi* para = ubidi_openSized (textLength, 0, &err);
787#error "NOT YET IMPLEMENTED (maybe won't be)"
791void TextLayoutBlock_Basic::Construct_Default ()
794 copy (
static_cast<Led_tChar*
> (fRealText),
static_cast<Led_tChar*
> (fRealText) + fTextLength,
static_cast<Led_tChar*
> (fVirtualText));
795 if (fTextLength != 0) {
796 ScriptRunElt thisCharElt;
797 thisCharElt.fDirection = eLeftToRight;
798 thisCharElt.fRealStart = 0;
799 thisCharElt.fRealEnd = fTextLength;
800 thisCharElt.fVirtualStart = 0;
801 thisCharElt.fVirtualEnd = fTextLength;
802 fScriptRuns.push_back (thisCharElt);
806void TextLayoutBlock_Basic::PeekAtRealText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
810 *startText = fRealText.data ();
811 *endText = fRealText.data () + fTextLength;
814void TextLayoutBlock_Basic::PeekAtVirtualText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
818 *startText = fVirtualText.data ();
819 *endText = fVirtualText.data () + fTextLength;
822vector<TextLayoutBlock::ScriptRunElt> TextLayoutBlock_Basic::GetScriptRuns ()
const
832TextLayoutBlock_Copy::TextLayoutBlock_Copy (
const TextLayoutBlock& from)
837 size_t strLength = from.GetTextLength ();
838 vector<ScriptRunElt> scriptRuns = from.GetScriptRuns ();
841 size_t neededSize =
sizeof (BlockRep);
842 neededSize +=
sizeof (Led_tChar) * strLength;
843 neededSize +=
sizeof (Led_tChar) * strLength;
844 neededSize +=
sizeof (ScriptRunElt) * scriptRuns.size ();
845 auto deleter = [] (BlockRep* br) {
delete[] (
reinterpret_cast<byte*
> (br)); };
846 fRep = shared_ptr<BlockRep>{
reinterpret_cast<BlockRep*
> (
new byte[neededSize]), deleter};
848 fRep->fTextLength = strLength;
850 fRep->fRealText =
reinterpret_cast<Led_tChar*
> (fRep.get () + 1);
852 const Led_tChar* s =
nullptr;
853 const Led_tChar* e =
nullptr;
854 from.PeekAtRealText_ (&s, &e);
855 copy (s, e,
const_cast<Led_tChar*
> (fRep->fRealText));
858 fRep->fVirtualText = fRep->fRealText + strLength;
860 const Led_tChar* s =
nullptr;
861 const Led_tChar* e =
nullptr;
862 from.PeekAtVirtualText_ (&s, &e);
863 copy (s, e,
const_cast<Led_tChar*
> (fRep->fVirtualText));
866 fRep->fScriptRuns =
reinterpret_cast<const ScriptRunElt*
> (fRep->fVirtualText + strLength);
867 fRep->fScriptRunsEnd = fRep->fScriptRuns + scriptRuns.size ();
868 copy (scriptRuns.begin (), scriptRuns.end (),
const_cast<ScriptRunElt*
> (fRep->fScriptRuns));
871TextLayoutBlock_Copy::TextLayoutBlock_Copy (
const TextLayoutBlock_Copy& from)
877void TextLayoutBlock_Copy::PeekAtRealText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
881 *startText = fRep->fRealText;
882 *endText = fRep->fRealText + fRep->fTextLength;
885void TextLayoutBlock_Copy::PeekAtVirtualText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
889 *startText = fRep->fVirtualText;
890 *endText = fRep->fVirtualText + fRep->fTextLength;
893vector<TextLayoutBlock_Copy::ScriptRunElt> TextLayoutBlock_Copy::GetScriptRuns ()
const
895 return vector<ScriptRunElt> (fRep->fScriptRuns, fRep->fScriptRunsEnd);
903void TextLayoutBlock_Copy::BlockRep::operator
delete (
void* p)
906 delete[] (
reinterpret_cast<char*
> (p));
914TextLayoutBlock_VirtualSubset::TextLayoutBlock_VirtualSubset (
const TextLayoutBlock& subsetOf,
size_t start,
size_t end)
915 : fSubsetOf{subsetOf}
918 , fRealText{end - start}
920 vector<ScriptRunElt> origRuns = fSubsetOf.GetScriptRuns ();
921 size_t offsetSoFar = 0;
922 const Led_tChar* fullRealText = fSubsetOf.PeekAtRealText ();
923 for (
auto i = origRuns.begin (); i != origRuns.end (); ++i) {
924 size_t offsetStart = (*i).fVirtualStart;
925 size_t offsetEnd = (*i).fVirtualEnd;
927 size_t runRelStart = max (offsetStart,
static_cast<size_t> (fStart));
928 size_t runRelEnd = min (offsetEnd,
static_cast<size_t> (fEnd));
929 if (runRelStart < runRelEnd) {
932 Assert (runRelStart >= fStart);
933 Assert (runRelEnd >= fStart);
934 s.fVirtualStart = runRelStart - fStart;
935 s.fVirtualEnd = runRelEnd - fStart;
945 Assert (runRelEnd >= runRelStart);
946 size_t runEltLen = runRelEnd - runRelStart;
947 copy (fullRealText + s.fRealStart, fullRealText + s.fRealStart + runEltLen, fRealText.data () + offsetSoFar);
948 s.fRealStart = offsetSoFar;
949 offsetSoFar += runEltLen;
950 s.fRealEnd = offsetSoFar;
951 Containers::Support::ReserveTweaks::Reserve4Add1 (fScriptRuns);
952 fScriptRuns.push_back (s);
959void TextLayoutBlock_VirtualSubset::PeekAtRealText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
963 *startText = fRealText.data ();
964 *endText = *startText + (fEnd - fStart);
967void TextLayoutBlock_VirtualSubset::PeekAtVirtualText_ (
const Led_tChar** startText,
const Led_tChar** endText)
const
971 fSubsetOf.PeekAtVirtualText_ (startText, endText);
972 *startText += fStart;
973 Assert (fStart <= fEnd);
974 Assert (*endText - *startText >=
static_cast<int> (fEnd - fStart));
975 *endText = *startText + (fEnd - fStart);
978vector<TextLayoutBlock::ScriptRunElt> TextLayoutBlock_VirtualSubset::GetScriptRuns ()
const
983#if qTryToUseUNISCRIBEForTextRuns
990InitialUNISCRIBEDir myGetInitialUNISCRIBEDir (
wchar_t c)
992 if (65 <= c && c <= 90) {
995 if (97 <= c && c <= 122) {
998 if (170 <= c && c <= 170) {
1001 if (181 <= c && c <= 181) {
1004 if (186 <= c && c <= 186) {
1007 if (192 <= c && c <= 214) {
1010 if (216 <= c && c <= 246) {
1013 if (248 <= c && c <= 696) {
1016 if (699 <= c && c <= 705) {
1019 if (720 <= c && c <= 721) {
1022 if (736 <= c && c <= 740) {
1025 if (750 <= c && c <= 767) {
1028 if (848 <= c && c <= 863) {
1031 if (880 <= c && c <= 883) {
1034 if (886 <= c && c <= 893) {
1037 if (895 <= c && c <= 899) {
1040 if (902 <= c && c <= 902) {
1043 if (904 <= c && c <= 1013) {
1046 if (1015 <= c && c <= 1154) {
1049 if (1159 <= c && c <= 1159) {
1052 if (1162 <= c && c <= 1417) {
1055 if (1419 <= c && c <= 1423) {
1058 if (1424 <= c && c <= 1424) {
1061 if (1442 <= c && c <= 1442) {
1064 if (1466 <= c && c <= 1466) {
1067 if (1470 <= c && c <= 1470) {
1070 if (1472 <= c && c <= 1472) {
1073 if (1475 <= c && c <= 1475) {
1076 if (1477 <= c && c <= 1547) {
1079 if (1549 <= c && c <= 1610) {
1082 if (1622 <= c && c <= 1631) {
1085 if (1645 <= c && c <= 1647) {
1088 if (1649 <= c && c <= 1749) {
1091 if (1757 <= c && c <= 1757) {
1094 if (1765 <= c && c <= 1766) {
1097 if (1774 <= c && c <= 1775) {
1100 if (1786 <= c && c <= 1806) {
1103 if (1808 <= c && c <= 1808) {
1106 if (1810 <= c && c <= 1839) {
1109 if (1867 <= c && c <= 1957) {
1112 if (1969 <= c && c <= 1983) {
1115 if (1984 <= c && c <= 2304) {
1118 if (2307 <= c && c <= 2363) {
1121 if (2365 <= c && c <= 2368) {
1124 if (2377 <= c && c <= 2380) {
1127 if (2382 <= c && c <= 2384) {
1130 if (2389 <= c && c <= 2401) {
1133 if (2404 <= c && c <= 2432) {
1136 if (2434 <= c && c <= 2491) {
1139 if (2493 <= c && c <= 2496) {
1142 if (2501 <= c && c <= 2508) {
1145 if (2510 <= c && c <= 2529) {
1148 if (2532 <= c && c <= 2545) {
1151 if (2548 <= c && c <= 2561) {
1154 if (2563 <= c && c <= 2619) {
1157 if (2621 <= c && c <= 2624) {
1160 if (2627 <= c && c <= 2630) {
1163 if (2633 <= c && c <= 2634) {
1166 if (2638 <= c && c <= 2671) {
1169 if (2674 <= c && c <= 2688) {
1172 if (2691 <= c && c <= 2747) {
1175 if (2749 <= c && c <= 2752) {
1178 if (2758 <= c && c <= 2758) {
1181 if (2761 <= c && c <= 2764) {
1184 if (2766 <= c && c <= 2816) {
1187 if (2818 <= c && c <= 2875) {
1190 if (2877 <= c && c <= 2878) {
1193 if (2880 <= c && c <= 2880) {
1196 if (2884 <= c && c <= 2892) {
1199 if (2894 <= c && c <= 2901) {
1202 if (2903 <= c && c <= 2945) {
1205 if (2947 <= c && c <= 3007) {
1208 if (3009 <= c && c <= 3020) {
1211 if (3022 <= c && c <= 3133) {
1214 if (3137 <= c && c <= 3141) {
1217 if (3145 <= c && c <= 3145) {
1220 if (3150 <= c && c <= 3156) {
1223 if (3159 <= c && c <= 3262) {
1226 if (3264 <= c && c <= 3269) {
1229 if (3271 <= c && c <= 3275) {
1232 if (3278 <= c && c <= 3392) {
1235 if (3396 <= c && c <= 3404) {
1238 if (3406 <= c && c <= 3529) {
1241 if (3531 <= c && c <= 3537) {
1244 if (3541 <= c && c <= 3541) {
1247 if (3543 <= c && c <= 3632) {
1250 if (3634 <= c && c <= 3635) {
1253 if (3643 <= c && c <= 3646) {
1256 if (3648 <= c && c <= 3654) {
1259 if (3663 <= c && c <= 3760) {
1262 if (3762 <= c && c <= 3763) {
1265 if (3770 <= c && c <= 3770) {
1268 if (3773 <= c && c <= 3783) {
1271 if (3790 <= c && c <= 3863) {
1274 if (3866 <= c && c <= 3892) {
1277 if (3894 <= c && c <= 3894) {
1280 if (3896 <= c && c <= 3896) {
1283 if (3902 <= c && c <= 3952) {
1286 if (3967 <= c && c <= 3967) {
1289 if (3973 <= c && c <= 3973) {
1292 if (3976 <= c && c <= 3983) {
1295 if (3992 <= c && c <= 3992) {
1298 if (4029 <= c && c <= 4037) {
1301 if (4039 <= c && c <= 4140) {
1304 if (4145 <= c && c <= 4145) {
1307 if (4147 <= c && c <= 4149) {
1310 if (4152 <= c && c <= 4152) {
1313 if (4154 <= c && c <= 4183) {
1316 if (4186 <= c && c <= 5759) {
1319 if (5761 <= c && c <= 5786) {
1322 if (5789 <= c && c <= 5905) {
1325 if (5909 <= c && c <= 5937) {
1328 if (5941 <= c && c <= 5969) {
1331 if (5972 <= c && c <= 6001) {
1334 if (6004 <= c && c <= 6070) {
1337 if (6078 <= c && c <= 6085) {
1340 if (6087 <= c && c <= 6088) {
1343 if (6100 <= c && c <= 6106) {
1346 if (6108 <= c && c <= 6143) {
1349 if (6159 <= c && c <= 6312) {
1352 if (6314 <= c && c <= 8124) {
1355 if (8126 <= c && c <= 8126) {
1358 if (8130 <= c && c <= 8140) {
1361 if (8144 <= c && c <= 8156) {
1364 if (8160 <= c && c <= 8172) {
1367 if (8176 <= c && c <= 8188) {
1370 if (8191 <= c && c <= 8191) {
1373 if (8206 <= c && c <= 8206) {
1376 if (8207 <= c && c <= 8207) {
1379 if (8275 <= c && c <= 8278) {
1382 if (8280 <= c && c <= 8286) {
1385 if (8292 <= c && c <= 8297) {
1388 if (8305 <= c && c <= 8307) {
1391 if (8319 <= c && c <= 8319) {
1394 if (8335 <= c && c <= 8351) {
1397 if (8370 <= c && c <= 8399) {
1400 if (8427 <= c && c <= 8447) {
1403 if (8450 <= c && c <= 8450) {
1406 if (8455 <= c && c <= 8455) {
1409 if (8458 <= c && c <= 8467) {
1412 if (8469 <= c && c <= 8469) {
1415 if (8473 <= c && c <= 8477) {
1418 if (8484 <= c && c <= 8484) {
1421 if (8486 <= c && c <= 8486) {
1424 if (8488 <= c && c <= 8488) {
1427 if (8490 <= c && c <= 8493) {
1430 if (8495 <= c && c <= 8497) {
1433 if (8499 <= c && c <= 8505) {
1436 if (8507 <= c && c <= 8511) {
1439 if (8517 <= c && c <= 8521) {
1442 if (8524 <= c && c <= 8530) {
1445 if (8544 <= c && c <= 8591) {
1448 if (9014 <= c && c <= 9082) {
1451 if (9109 <= c && c <= 9109) {
1454 if (9167 <= c && c <= 9215) {
1457 if (9255 <= c && c <= 9279) {
1460 if (9291 <= c && c <= 9311) {
1463 if (9372 <= c && c <= 9449) {
1466 if (9471 <= c && c <= 9471) {
1469 if (9748 <= c && c <= 9749) {
1472 if (9752 <= c && c <= 9752) {
1475 if (9854 <= c && c <= 9855) {
1478 if (9866 <= c && c <= 9984) {
1481 if (9989 <= c && c <= 9989) {
1484 if (9994 <= c && c <= 9995) {
1487 if (10024 <= c && c <= 10024) {
1490 if (10060 <= c && c <= 10060) {
1493 if (10062 <= c && c <= 10062) {
1496 if (10067 <= c && c <= 10069) {
1499 if (10071 <= c && c <= 10071) {
1502 if (10079 <= c && c <= 10080) {
1505 if (10133 <= c && c <= 10135) {
1508 if (10160 <= c && c <= 10160) {
1511 if (10175 <= c && c <= 10191) {
1514 if (10220 <= c && c <= 10223) {
1517 if (11008 <= c && c <= 11903) {
1520 if (11930 <= c && c <= 11930) {
1523 if (12020 <= c && c <= 12031) {
1526 if (12246 <= c && c <= 12271) {
1529 if (12284 <= c && c <= 12287) {
1532 if (12293 <= c && c <= 12295) {
1535 if (12321 <= c && c <= 12329) {
1538 if (12337 <= c && c <= 12341) {
1541 if (12344 <= c && c <= 12348) {
1544 if (12352 <= c && c <= 12440) {
1547 if (12445 <= c && c <= 12447) {
1550 if (12449 <= c && c <= 12538) {
1553 if (12540 <= c && c <= 12880) {
1556 if (12896 <= c && c <= 12976) {
1559 if (12992 <= c && c <= 42127) {
1562 if (42183 <= c && c <= 64284) {
1565 if (64285 <= c && c <= 64285) {
1568 if (64287 <= c && c <= 64296) {
1571 if (64298 <= c && c <= 64829) {
1574 if (64832 <= c && c <= 65023) {
1577 if (65040 <= c && c <= 65055) {
1580 if (65060 <= c && c <= 65071) {
1583 if (65095 <= c && c <= 65096) {
1586 if (65107 <= c && c <= 65107) {
1589 if (65127 <= c && c <= 65127) {
1592 if (65132 <= c && c <= 65135) {
1595 if (65136 <= c && c <= 65278) {
1598 if (65280 <= c && c <= 65280) {
1601 if (65313 <= c && c <= 65338) {
1604 if (65345 <= c && c <= 65370) {
1607 if (65382 <= c && c <= 65503) {
1610 if (65511 <= c && c <= 65511) {
1613 if (65519 <= c && c <= 65528) {
1616 if (65534 <= c && c <= 65534) {
1619 return eNeutralChar;
#define RequireNotNull(p)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...