40 #include <QtGui/private/qtguiglobal_p.h>
48 #include <QtCore/private/qunicodetables_p.h>
64 static const float smallCapsFraction = 0.7f;
88 generateScriptItemsSmallCaps(
reinterpret_cast<const ushort *
>(m_string.unicode()),
start,
length);
100 enum { MaxItemLength = 4096 };
105 if (m_items.isEmpty())
121 if (m_analysis[
i].bidiLevel == m_analysis[
start].bidiLevel
125 &&
i -
start < MaxItemLength)
133 void generateScriptItemsCapitalize(
int start,
int length)
140 m_string.constData(), m_string.length(),
143 m_splitter->setPosition(
start);
149 m_splitter->toNextBoundary();
153 bool atWordStart =
false;
155 if (
i == m_splitter->position()) {
161 m_splitter->toNextBoundary();
164 if (m_analysis[
i] == itemAnalysis
167 &&
i -
start < MaxItemLength)
172 itemAnalysis = m_analysis[
start];
189 if ((m_analysis[
i] == m_analysis[
start])
192 &&
i -
start < MaxItemLength)
221 enum { BidiDebugEnabled =
false };
222 #define BIDI_DEBUG if (1) ; else qDebug
224 enum { BidiDebugEnabled =
true };
225 static const char *directions[] = {
226 "DirL",
"DirR",
"DirEN",
"DirES",
"DirET",
"DirAN",
"DirCS",
"DirB",
"DirS",
"DirWS",
"DirON",
227 "DirLRE",
"DirLRO",
"DirAL",
"DirRLE",
"DirRLO",
"DirPDF",
"DirNSM",
"DirBN",
228 "DirLRI",
"DirRLI",
"DirFSI",
"DirPDI"
230 #define BIDI_DEBUG qDebug
232 return (
d << directions[
dir]);
236 struct QBidiAlgorithm {
243 baseLevel(baseDirectionIsRtl ? 1 : 0)
253 void initScriptAnalysisAndIsolatePairs(Vector<IsolatePair> &isolatePairs)
255 int isolateStack[128];
256 int isolateLevel = 0;
260 char32_t uc =
text[
i].unicode();
285 if (isolateLevel < 128) {
286 isolateStack[isolateLevel] = isolatePairs.size();
293 if (isolateLevel > 0) {
295 if (isolateLevel < 128)
296 isolatePairs[isolateStack[isolateLevel]].end =
pos;
307 while (isolateLevel > 0) {
309 if (isolateLevel < 128)
310 isolatePairs[isolateStack[isolateLevel]].end =
pos;
320 struct DirectionalRun {
329 void generateDirectionalRuns(
const Vector<IsolatePair> &isolatePairs, Vector<DirectionalRun> &runs)
331 struct DirectionalStack {
332 enum { MaxDepth = 125 };
337 int runBeforeIsolate;
356 int overflowIsolateCount = 0;
357 int overflowEmbeddingCount = 0;
358 int validIsolateCount = 0;
361 bool override =
false;
362 stack.push({
level,
false,
false, -1 });
366 int continuationFrom = -1;
367 int lastRunWithContent = -1;
368 bool runHasContent =
false;
370 auto appendRun = [&](
int runEnd) {
371 if (runEnd < runStart)
373 bool isContinuation =
false;
374 if (continuationFrom != -1) {
375 runs[continuationFrom].continuation = runs.size();
376 isContinuation =
true;
377 }
else if (lastRunWithContent != -1 &&
level == runs.at(lastRunWithContent).level) {
378 runs[lastRunWithContent].continuation = runs.size();
379 isContinuation =
true;
382 lastRunWithContent = runs.size();
383 BIDI_DEBUG() <<
" appending run start/end" << runStart << runEnd <<
"level" <<
level;
384 runs.append({ runStart, runEnd, -1,
level, isContinuation, runHasContent });
385 runHasContent =
false;
386 runStart = runEnd + 1;
387 continuationFrom = -1;
390 int isolatePairPosition = 0;
396 auto doEmbed = [&](
bool isRtl,
bool isOverride,
bool isIsolate) {
400 runHasContent =
true;
401 lastRunWithContent = -1;
402 ++isolatePairPosition;
404 int runBeforeIsolate = runs.size();
405 ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.
top().
level + 2) & ~1);
406 if (newLevel <= DirectionalStack::MaxDepth && !overflowEmbeddingCount && !overflowIsolateCount) {
410 runBeforeIsolate = -1;
411 appendRun(isIsolate ?
i :
i - 1);
412 BIDI_DEBUG() <<
"pushing new item on stack: level" << (int)newLevel <<
"isOverride" << isOverride <<
"isIsolate" << isIsolate << runBeforeIsolate;
413 stack.push({ newLevel, isOverride, isIsolate, runBeforeIsolate });
414 override = isOverride;
418 ++overflowIsolateCount;
419 else if (!overflowIsolateCount)
420 ++overflowEmbeddingCount;
432 doEmbed(
false,
false,
false);
435 doEmbed(
true,
false,
false);
438 doEmbed(
false,
true,
false);
441 doEmbed(
true,
true,
false);
444 doEmbed(
false,
false,
true);
447 doEmbed(
true,
false,
true);
451 if (isolatePairPosition < isolatePairs.size()) {
452 const auto &pair = isolatePairs.at(isolatePairPosition);
456 doEmbed(isRtl,
false,
true);
465 if (overflowIsolateCount) {
467 }
else if (overflowEmbeddingCount) {
468 --overflowEmbeddingCount;
469 }
else if (!stack.top().isIsolate && stack.depth() >= 2) {
472 override = stack.top().isOverride;
473 level = stack.top().level;
474 BIDI_DEBUG() <<
"popped PDF from stack, level now" << (int)stack.top().level;
478 runHasContent =
true;
479 if (overflowIsolateCount) {
480 --overflowIsolateCount;
481 }
else if (validIsolateCount == 0) {
485 overflowEmbeddingCount = 0;
486 while (!stack.top().isIsolate)
488 continuationFrom = stack.top().runBeforeIsolate;
489 BIDI_DEBUG() <<
"popped PDI from stack, level now" << (int)stack.top().level <<
"continuation from" << continuationFrom;
491 override = stack.top().isOverride;
492 level = stack.top().level;
493 lastRunWithContent = -1;
503 while (stack.counter > 1) {
506 const auto &
t = stack.top();
508 runs[
t.runBeforeIsolate].continuation = -2;
512 continuationFrom = -1;
513 lastRunWithContent = -1;
514 validIsolateCount = 0;
515 overflowIsolateCount = 0;
516 overflowEmbeddingCount = 0;
521 runHasContent =
true;
530 while (stack.counter > 1) {
533 const auto &
t = stack.top();
535 runs[
t.runBeforeIsolate].continuation = -2;
541 void resolveExplicitLevels(Vector<DirectionalRun> &runs)
543 Vector<IsolatePair> isolatePairs;
545 initScriptAnalysisAndIsolatePairs(isolatePairs);
546 generateDirectionalRuns(isolatePairs, runs);
549 struct IsolatedRunSequenceIterator {
557 bool isValid()
const {
return pos != -1; }
560 IsolatedRunSequenceIterator(
const Vector<DirectionalRun> &runs,
int i)
564 pos = runs.at(current).start;
567 bool atEnd()
const {
return pos < 0; }
570 if (
pos > runs.at(current).end) {
571 current = runs.at(current).continuation;
573 pos = runs.at(current).start;
589 const Vector<DirectionalRun> &runs;
595 void resolveW1W2W3(
const Vector<DirectionalRun> &runs,
int i,
QChar::Direction sos)
599 IsolatedRunSequenceIterator
it(runs,
i);
600 while (!
it.atEnd()) {
607 analysis[
pos].bidiDirection = current;
626 analysis[
pos].bidiDirection = current;
631 lastStrong = current;
634 lastStrong = current;
648 IsolatedRunSequenceIterator
it(runs,
i);
654 while (!
it.atEnd()) {
664 analysis[lastPos].bidiDirection = last;
668 analysis[lastPos].bidiDirection = last;
671 analysis[lastPos].bidiDirection = last;
681 void resolveW5(
const Vector<DirectionalRun> &runs,
int i)
686 IsolatedRunSequenceIterator
it(runs,
i);
690 lastETPosition =
it.position();
693 while (!
it.atEnd()) {
703 analysis[
pos].bidiDirection = current;
704 }
else if (!lastETPosition.isValid()) {
705 lastETPosition =
it.position();
707 }
else if (lastETPosition.isValid()) {
709 it.setPosition(lastETPosition);
716 lastETPosition.clear();
724 void resolveW6W7(
const Vector<DirectionalRun> &runs,
int i,
QChar::Direction sos)
727 IsolatedRunSequenceIterator
it(runs,
i);
728 while (!
it.atEnd()) {
743 lastStrong = current;
745 analysis[
pos].bidiDirection = lastStrong;
755 bool isValid()
const {
return second > 0; }
758 int isolateCounter = 0;
760 for (
int i =
first + 1;
i < second; ++
i) {
762 if (isolateCounter) {
769 if (embeddingDir ==
dir)
778 BIDI_DEBUG() <<
" contained dir for backet pair" <<
first <<
"/" << second <<
"is" << containedDir;
784 struct BracketStack {
788 uint pairedBracked = 0;
797 int match(
uint unicode) {
801 if (stack[
p].pairedBracked == unicode ||
803 (stack[
p].pairedBracked == 0x3009 && unicode == 0x232a) ||
804 (stack[
p].pairedBracked == 0x232a && unicode == 0x3009)) {
806 return stack[
p].position;
813 enum { MaxDepth = 63 };
814 Item stack[MaxDepth];
817 bool overflowed()
const {
return position > MaxDepth; }
824 Vector<BracketPair> bracketPairs;
826 BracketStack bracketStack;
827 IsolatedRunSequenceIterator
it(runs,
i);
828 while (!
it.atEnd()) {
837 uint closingBracked =
text[
pos].unicode() +
p->mirrorDiff;
838 bracketStack.push(closingBracked, bracketPairs.size());
839 if (bracketStack.overflowed()) {
840 bracketPairs.clear();
843 bracketPairs.append({
pos, -1 });
845 int pairPos = bracketStack.match(
text[
pos].unicode());
847 bracketPairs[pairPos].second =
pos;
855 if (BidiDebugEnabled && bracketPairs.size()) {
857 for (
int i = 0;
i < bracketPairs.size(); ++
i)
858 BIDI_DEBUG() <<
" " << bracketPairs.at(
i).first << bracketPairs.at(
i).second;
862 IsolatedRunSequenceIterator
it(runs,
i);
864 for (
int i = 0;
i < bracketPairs.size(); ++
i) {
865 const auto &pair = bracketPairs.at(
i);
868 QChar::Direction containedDir = pair.containedDirection(analysis, embeddingDir);
870 BIDI_DEBUG() <<
" 3: resolve bracket pair" <<
i <<
"to DirON";
872 }
else if (containedDir == embeddingDir) {
875 BIDI_DEBUG() <<
" 1: resolve bracket pair" <<
i <<
"to" << embeddingDir;
878 while (
it.pos < pair.first) {
880 switch (analysis[
pos].bidiDirection) {
896 BIDI_DEBUG() <<
" 2: resolve bracket pair" <<
i <<
"to" << lastStrong;
898 for (
int i = pair.second + 1;
i <
length; ++
i) {
912 IsolatedRunSequenceIterator
it(runs,
i);
926 if (niPos.isValid()) {
928 if (lastStrong != currentStrong)
930 it.setPosition(niPos);
938 lastStrong = currentStrong;
950 if (!niPos.isValid())
951 niPos =
it.position();
964 void resolveImplicitLevelsForIsolatedRun(
const Vector<DirectionalRun> &runs,
int i)
967 int level = runs.at(
i).level;
969 while (before >= 0 && !runs.at(before).hasContent)
971 int level_before = (before >= 0) ? runs.at(before).level : baseLevel;
973 while (runs.at(after).continuation >= 0)
974 after = runs.at(after).continuation;
975 if (runs.at(after).continuation == -2) {
979 while (after < runs.size() && !runs.at(after).hasContent)
982 int level_after = (after == runs.size()) ? baseLevel : runs.at(after).level;
986 if (BidiDebugEnabled) {
987 BIDI_DEBUG() <<
"Isolated run starting at" <<
i <<
"sos/eos" << sos << eos;
988 BIDI_DEBUG() <<
"before implicit level processing:";
989 IsolatedRunSequenceIterator
it(runs,
i);
990 while (!
it.atEnd()) {
996 resolveW1W2W3(runs,
i, sos);
997 resolveW4(runs,
i, sos);
1000 if (BidiDebugEnabled) {
1002 IsolatedRunSequenceIterator
it(runs,
i);
1003 while (!
it.atEnd()) {
1009 resolveW6W7(runs,
i, sos);
1014 resolveN0(runs,
i, sos);
1015 resolveN1N2(runs,
i, sos, eos);
1021 IsolatedRunSequenceIterator
it(runs,
i);
1022 while (!
it.atEnd()) {
1048 void resolveImplicitLevels(
const Vector<DirectionalRun> &runs)
1050 for (
int i = 0;
i < runs.size(); ++
i) {
1051 if (runs.at(
i).isContinuation)
1054 resolveImplicitLevelsForIsolatedRun(runs,
i);
1058 bool checkForBidi()
const
1063 if (
text[
i].unicode() >= 0x590) {
1082 bool hasBidi = checkForBidi();
1087 if (BidiDebugEnabled) {
1094 Vector<DirectionalRun> runs;
1095 resolveExplicitLevels(runs);
1097 if (BidiDebugEnabled) {
1098 BIDI_DEBUG() <<
"resolved explicit levels, nruns" << runs.size();
1099 for (
int i = 0;
i < runs.size(); ++
i)
1100 BIDI_DEBUG() <<
" " <<
i <<
"start/end" << runs.at(
i).start << runs.at(
i).end <<
"level" << (int)runs.at(
i).level <<
"continuation" << runs.at(
i).continuation;
1106 resolveImplicitLevels(runs);
1111 bool resetLevel =
true;
1114 BIDI_DEBUG() <<
"resetting pos" <<
i <<
"to baselevel";
1118 BIDI_DEBUG() <<
"resetting pos" <<
i <<
"to baselevel (maybereset flag)";
1128 int lastLevel = baseLevel;
1137 if (lastBNPos >= 0) {
1138 if (
l < lastLevel) {
1139 while (lastBNPos <
i) {
1149 if (lastBNPos >= 0 && baseLevel < lastLevel) {
1150 while (lastBNPos <
length) {
1151 analysis[lastBNPos].
bidiLevel = baseLevel;
1156 if (BidiDebugEnabled) {
1181 while (
i < numItems) {
1195 if (!(levelLow%2)) levelLow++;
1197 BIDI_DEBUG() <<
"reorderLine: lineLow = " << (
uint)levelLow <<
", lineHigh = " << (
uint)levelHigh;
1199 int count = numItems - 1;
1200 for (
i = 0;
i < numItems;
i++)
1203 while(levelHigh >= levelLow) {
1214 int tmp = visualOrder[
start+
j];
1216 visualOrder[
end-
j] = tmp;
1244 #if QT_CONFIG(harfbuzz)
1250 static inline void qt_getDefaultJustificationOpportunities(
const ushort *
string,
int length,
const QGlyphLayout &
g,
ushort *log_clusters,
int spaceAs)
1253 while (str_pos <
length) {
1254 int glyph_pos = log_clusters[str_pos];
1256 Q_ASSERT(glyph_pos <
g.numGlyphs &&
g.attributes[glyph_pos].clusterStart);
1258 uint ucs4 =
string[str_pos];
1260 ushort low =
string[str_pos + 1];
1270 }
while (str_pos <
length && log_clusters[str_pos] == glyph_pos);
1273 }
while (glyph_pos <
g.numGlyphs && !
g.attributes[glyph_pos].clusterStart);
1280 g.attributes[glyph_pos].justification = spaceAs;
1288 for (
int glyph_pos = 0; glyph_pos <
g.numGlyphs; ++glyph_pos)
1320 qt_getDefaultJustificationOpportunities(
string,
length,
g, log_clusters, spaceAs);
1357 #if QT_CONFIG(harfbuzz)
1358 extern bool qt_useHarfbuzzNG();
1373 if (!fontEngine->
symbol) {
1378 const uint engineIndex = glyphs->
glyphs[glyphPosition] & 0xff000000;
1384 glyphs->
glyphs[glyphPosition] = glyph;
1386 glyphs->
glyphs[glyphPosition] |= engineIndex;
1398 void QTextEngine::shapeText(
int item)
const
1414 casedString.
resize(itemLength);
1416 for (
int i = 0;
i < itemLength; ++
i) {
1417 uint ucs4 =
string[
i];
1419 uint low =
string[
i + 1];
1426 :
QChar::toUpper(ucs4);
1431 :
QChar::toUpper(ucs4);
1444 bool kerningEnabled;
1445 bool letterSpacingIsAbsolute;
1446 bool shapingEnabled;
1447 QFixed letterSpacing, wordSpacing;
1448 #ifndef QT_NO_RAWFONT
1457 letterSpacingIsAbsolute =
true;
1469 if (letterSpacingIsAbsolute && letterSpacing.
value())
1483 QFontEngine::ShaperFlags shaperFlags =
1492 uint lastEngine = ~0
u;
1493 for (
int i = 0, glyph_pos = 0;
i < itemLength; ++
i, ++glyph_pos) {
1494 const uint engineIdx = initialGlyphs.
glyphs[glyph_pos] >> 24;
1495 if (lastEngine != engineIdx) {
1497 itemBoundaries.
append(glyph_pos);
1498 itemBoundaries.
append(engineIdx);
1500 if (engineIdx != 0) {
1507 lastEngine = engineIdx;
1514 itemBoundaries.
append(0);
1515 itemBoundaries.
append(0);
1516 itemBoundaries.
append(0);
1519 #if QT_CONFIG(harfbuzz)
1520 if (
Q_LIKELY(shapingEnabled && qt_useHarfbuzzNG())) {
1521 si.
num_glyphs = shapeTextWithHarfbuzzNG(si,
string, itemLength,
fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
1528 for (
int i = 0;
i < itemLength; ++
i, ++glyph_pos) {
1529 log_clusters[
i] = glyph_pos;
1532 &&
i + 1 < itemLength
1536 log_clusters[
i] = glyph_pos;
1545 const uint engineIdx = initialGlyphs.
glyphs[glyph_pos] >> 24;
1549 applyVisibilityRules(
string[
i], &initialGlyphs, glyph_pos, actualFontEngine);
1558 qWarning() <<
"Unable to allocate space for place-holder glyph";
1567 g.attributes[0].clusterStart =
true;
1570 for (
int i = 0;
i < itemLength; ++
i)
1571 log_clusters[
i] = 0;
1580 #if QT_CONFIG(harfbuzz)
1582 qt_getJustificationOpportunities(
string, itemLength, si, glyphs,
logClusters(&si));
1585 if (letterSpacing != 0) {
1588 if (letterSpacingIsAbsolute)
1589 glyphs.
advances[
i - 1] += letterSpacing;
1592 advance += (letterSpacing - 100) * advance / 100;
1596 if (letterSpacingIsAbsolute)
1600 advance += (letterSpacing - 100) * advance / 100;
1603 if (wordSpacing != 0) {
1620 #if QT_CONFIG(harfbuzz)
1628 int QTextEngine::shapeTextWithHarfbuzzNG(
const QScriptItem &si,
1633 bool kerningEnabled,
1634 bool hasLetterSpacing)
const
1636 uint glyphs_shaped = 0;
1653 for (
int k = 0; k < itemBoundaries.
size(); k += 3) {
1654 const uint item_pos = itemBoundaries[k];
1655 const uint item_length = (k + 4 < itemBoundaries.
size() ? itemBoundaries[k + 3] : itemLength) - item_pos;
1656 const uint engineIdx = itemBoundaries[k + 2];
1687 bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
1695 const int num_features = dontLigate ? 5 : 1;
1698 static const char *shaper_list[] = {
1729 uint last_cluster = ~0
u;
1730 uint last_glyph_pos = glyphs_shaped;
1731 for (
uint i = 0;
i < num_glyphs; ++
i, ++infos, ++positions) {
1732 g.glyphs[
i] = infos->codepoint;
1738 uint cluster = infos->cluster;
1739 if (
Q_LIKELY(last_cluster != cluster)) {
1740 g.attributes[
i].clusterStart =
true;
1744 while (last_cluster++ < cluster && str_pos < item_length)
1745 log_clusters[str_pos++] = last_glyph_pos;
1746 last_glyph_pos =
i + glyphs_shaped;
1747 last_cluster = cluster;
1749 applyVisibilityRules(
string[item_pos + str_pos], &
g,
i, actualFontEngine);
1752 while (str_pos < item_length)
1753 log_clusters[str_pos++] = last_glyph_pos;
1757 g.glyphs[
i] |= (engineIdx << 24);
1761 for (
uint i = 0;
i < num_glyphs; ++
i)
1762 g.advances[
i] =
g.advances[
i].round();
1765 glyphs_shaped += num_glyphs;
1770 return glyphs_shaped;
1777 e->ignoreBidi =
false;
1778 e->cacheGlyphs =
false;
1779 e->forceJustification =
false;
1780 e->visualMovement =
false;
1781 e->delayDecorations =
false;
1783 e->layoutData =
nullptr;
1788 e->specialData =
nullptr;
1789 e->stackEngine =
false;
1790 #ifndef QT_NO_RAWFONT
1791 e->useRawFont =
false;
1833 scriptItems.
data(), scriptItems.
size(),
1863 fontEngine(li, &li.ascent, &li.descent, &li.leading);
1874 static inline void releaseCachedFontEngine(
QFontEngine *fontEngine)
1876 if (fontEngine && !fontEngine->
ref.
deref())
1882 releaseCachedFontEngine(feCache.prevFontEngine);
1883 releaseCachedFontEngine(feCache.prevScaledFontEngine);
1918 if (specialData && specialData->preeditPosition != -1)
1945 for (
int i = 0;
i < scriptItems.
length(); ++
i) {
1946 const auto &
item = scriptItems.
at(
i);
1968 *
const_cast<ushort*
>(uc) = 0x21B5;
1997 SpecialData *
s = specialData;
2003 int preeditPosition =
s ?
s->preeditPosition : INT_MAX;
2004 int prevPosition = 0;
2011 preeditPosition = INT_MAX;
2019 for (
const auto &
range : qAsConst(
s->formats)) {
2023 if (
range.start > prevPosition)
2024 itemizer.generate(prevPosition,
range.start - prevPosition, capitalization);
2025 int newStart = std::max(prevPosition,
range.start);
2027 itemizer.generate(newStart, newEnd - newStart,
range.format.fontCapitalization());
2028 prevPosition = newEnd;
2032 itemizer.generate(prevPosition,
position - prevPosition, capitalization);
2045 #ifndef QT_NO_RAWFONT
2048 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2063 addRequiredBoundaries();
2069 switch (
option.textDirection()) {
2092 int left = firstItem + 1;
2098 else if (strPos < layoutData->
items.
at(middle).position)
2108 template<
typename InnerFunc>
2114 int ilen = textEngine->
length(
i);
2118 if (
pos + ilen > from) {
2130 unsigned short *logClusters = textEngine->
logClusters(si);
2137 int charFrom = from -
pos;
2140 int glyphStart = logClusters[charFrom];
2141 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)
2142 while (charFrom < ilen && logClusters[charFrom] == glyphStart)
2144 if (charFrom < ilen) {
2145 glyphStart = logClusters[charFrom];
2146 int charEnd = from +
len - 1 -
pos;
2147 if (charEnd >= ilen)
2149 int glyphEnd = logClusters[charEnd];
2150 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)
2152 glyphEnd = (charEnd == ilen) ? si->
num_glyphs : logClusters[charEnd];
2155 innerFunc(glyphStart, glyphEnd, si);
2168 textIterator(
this, from,
len,
w, [
this, &
w](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2170 for (
int j = glyphStart;
j < glyphEnd;
j++)
2183 textIterator(
this, from,
len, gm.
width, [
this, &gm](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2184 if (glyphStart <= glyphEnd) {
2185 QGlyphLayout glyphs = this->shapedGlyphs(si);
2186 QFontEngine *fe = this->fontEngine(*si);
2187 glyph_metrics_t m = fe->boundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));
2188 gm.x = qMin(gm.x, m.x + gm.xoff);
2189 gm.y = qMin(gm.y, m.y + gm.yoff);
2190 gm.width = qMax(gm.width, m.width + gm.xoff);
2191 gm.height = qMax(gm.height, m.height + gm.yoff);
2206 textIterator(
this, from,
len, gm.
width, [
this, &gm](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2207 if (glyphStart <= glyphEnd) {
2208 QGlyphLayout glyphs = this->shapedGlyphs(si);
2209 QFontEngine *fe = fontEngine(*si);
2210 glyph_metrics_t m = fe->tightBoundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));
2211 gm.x = qMin(gm.x, m.x + gm.xoff);
2212 gm.y = qMin(gm.y, m.y + gm.yoff);
2213 gm.width = qMax(gm.width, m.width + gm.xoff);
2214 gm.height = qMax(gm.height, m.height + gm.yoff);
2230 if (document_d !=
nullptr && document_d->
layout() !=
nullptr) {
2253 QTextEngine::FontEngineCache::FontEngineCache()
2267 #ifndef QT_NO_RAWFONT
2269 if (feCache.prevFontEngine && feCache.prevFontEngine->type() ==
QFontEngine::Multi && feCache.prevScript ==
script) {
2270 engine = feCache.prevFontEngine;
2273 feCache.prevFontEngine = engine;
2274 feCache.prevScript =
script;
2276 if (feCache.prevScaledFontEngine) {
2277 releaseCachedFontEngine(feCache.prevScaledFontEngine);
2278 feCache.prevScaledFontEngine =
nullptr;
2282 if (feCache.prevScaledFontEngine) {
2283 scaledEngine = feCache.prevScaledFontEngine;
2295 feCache.prevScaledFontEngine = scaledEngine;
2297 if (!scEngine->ref.deref())
2307 if (feCache.prevFontEngine && feCache.prevPosition == si.
position && feCache.prevLength ==
length(&si) && feCache.prevScript ==
script) {
2308 engine = feCache.prevFontEngine;
2309 scaledEngine = feCache.prevScaledFontEngine;
2337 if (feCache.prevFontEngine)
2338 releaseCachedFontEngine(feCache.prevFontEngine);
2339 feCache.prevFontEngine = engine;
2341 if (feCache.prevScaledFontEngine)
2342 releaseCachedFontEngine(feCache.prevScaledFontEngine);
2343 feCache.prevScaledFontEngine = scaledEngine;
2345 feCache.prevScript =
script;
2346 feCache.prevPosition = si.
position;
2347 feCache.prevLength =
length(&si);
2350 if (feCache.prevFontEngine && feCache.prevScript ==
script && feCache.prevPosition == -1) {
2351 engine = feCache.prevFontEngine;
2356 if (feCache.prevFontEngine)
2357 releaseCachedFontEngine(feCache.prevFontEngine);
2358 feCache.prevFontEngine = engine;
2360 feCache.prevScript =
script;
2361 feCache.prevPosition = -1;
2362 feCache.prevLength = -1;
2363 feCache.prevScaledFontEngine =
nullptr;
2369 scaledEngine =
p->engineForScript(
script);
2377 *ascent = engine->
ascent();
2383 return scaledEngine;
2398 point->
glyph = glyph;
2401 const char32_t
ch =
U'\x640';
2404 if (kashidaGlyph != 0) {
2407 g.glyphs = &kashidaGlyph;
2424 if (
line.gridfitted &&
line.justified)
2427 if (!
line.gridfitted) {
2454 while (line_length &&
a[line_length-1].whiteSpace)
2459 if (line_length <= 0)
2463 int lastItem =
findItem(
line.from + line_length - 1, firstItem);
2464 int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2469 QFixed minKashida = 0x100000;
2474 for (
int i = 0;
i < nItems; ++
i) {
2480 for (
int i = 0;
i < nItems; ++
i) {
2484 int kashida_pos = -1;
2491 int gs = log_clusters[
start];
2498 for (
int i = gs;
i < ge; ++
i) {
2500 g.justifications[
i].nKashidas = 0;
2501 g.justifications[
i].space_18d6 = 0;
2503 justificationPoints.
resize(nPoints+3);
2504 int justification =
g.attributes[
i].justification;
2506 switch(justification) {
2511 if (kashida_pos >= 0) {
2513 set(&justificationPoints[nPoints], kashida_type,
g.mid(kashida_pos),
fontEngine(si));
2514 if (justificationPoints[nPoints].kashidaWidth > 0) {
2515 minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
2516 maxJustify = qMax(maxJustify, justificationPoints[nPoints].
type);
2524 set(&justificationPoints[nPoints++], justification,
g.mid(
i),
fontEngine(si));
2525 maxJustify = qMax(maxJustify, justification);
2534 if (justification >= kashida_type) {
2536 kashida_type = justification;
2540 if (kashida_pos >= 0) {
2541 set(&justificationPoints[nPoints], kashida_type,
g.mid(kashida_pos),
fontEngine(si));
2542 if (justificationPoints[nPoints].kashidaWidth > 0) {
2543 minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
2544 maxJustify = qMax(maxJustify, justificationPoints[nPoints].
type);
2563 while (need >= minKashida) {
2565 for (
int i = 0; need >= minKashida &&
i < nPoints; ++
i) {
2566 if (justificationPoints[
i].
type ==
type && justificationPoints[
i].kashidaWidth <= need) {
2567 justificationPoints[
i].glyph.justifications->nKashidas++;
2569 justificationPoints[
i].glyph.justifications->space_18d6 += justificationPoints[
i].kashidaWidth.
value();
2570 need -= justificationPoints[
i].kashidaWidth;
2582 for (
int type = maxJustify; need != 0 &&
type > 0; --
type) {
2584 for (
int i = 0;
i < nPoints; ++
i) {
2585 if (justificationPoints[
i].
type ==
type)
2594 for (
int i = 0;
i < nPoints; ++
i) {
2595 if (justificationPoints[
i].
type ==
type) {
2598 justificationPoints[
i].glyph.justifications[0].space_18d6 =
add.value();
2626 QFixed other_ascent =
e->ascent();
2627 QFixed other_descent =
e->descent();
2628 QFixed other_leading =
e->leading();
2653 int space_logClusters = int(
sizeof(
unsigned short) *
string.
length() /
sizeof(
void*) + 1);
2668 void *
m =
memory + space_charAttributes + space_logClusters;
2671 memset(
memory, 0, space_charAttributes*
sizeof(
void *));
2681 if (!memory_on_stack)
2688 Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs);
2689 if (memory_on_stack && available_glyphs >= totalGlyphs) {
2690 glyphLayout.grow(glyphLayout.data(), totalGlyphs);
2695 int space_logClusters = int(
sizeof(
unsigned short) *
string.
length() /
sizeof(
void*) + 1);
2698 int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
2702 if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {
2707 void **newMem = (
void **)::realloc(memory_on_stack ?
nullptr :
memory, newAllocated*
sizeof(
void *));
2712 if (memory_on_stack)
2713 memcpy(newMem,
memory, allocated*
sizeof(
void *));
2715 memory_on_stack =
false;
2718 m += space_charAttributes;
2719 logClustersPtr = (
unsigned short *)
m;
2720 m += space_logClusters;
2722 const int space_preGlyphLayout = space_charAttributes + space_logClusters;
2723 if (allocated < space_preGlyphLayout)
2724 memset(
memory + allocated, 0, (space_preGlyphLayout - allocated)*
sizeof(
void *));
2726 glyphLayout.grow(
reinterpret_cast<char *
>(
m), totalGlyphs);
2728 allocated = newAllocated;
2765 specialData->resolvedFormats.clear();
2774 if (specialData && !specialData->resolvedFormats.isEmpty()) {
2784 if (specialData && si->
position >= specialData->preeditPosition) {
2785 if (si->
position < specialData->preeditPosition + specialData->preeditText.length())
2786 pos = qMax(qMin(
block.
length(), specialData->preeditPosition) - 1, 0);
2788 pos -= specialData->preeditText.length();
2791 return it.value()->format;
2802 void QTextEngine::addRequiredBoundaries()
const
2805 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2807 setBoundary(
r.start);
2808 setBoundary(
r.start +
r.length);
2817 switch (
c.unicode()) {
2861 if (specialData->formats.isEmpty()) {
2863 specialData =
nullptr;
2865 specialData->preeditText =
QString();
2866 specialData->preeditPosition = -1;
2870 specialData =
new SpecialData;
2871 specialData->preeditPosition =
position;
2872 specialData->preeditText = preeditText;
2883 if (specialData->preeditText.isEmpty()) {
2885 specialData =
nullptr;
2887 specialData->formats.clear();
2891 specialData =
new SpecialData;
2892 specialData->preeditPosition = -1;
2894 specialData->formats =
formats;
2901 void QTextEngine::indexFormats()
2907 collection = specialData->formatCollection.data();
2911 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2921 static inline bool nextCharJoins(
const QString &
string,
int pos)
2931 static inline bool prevCharJoins(
const QString &
string,
int pos)
2941 static inline bool isRetainableControlCode(
QChar c)
2943 return (
c.unicode() >= 0x202a &&
c.unicode() <= 0x202e)
2944 || (
c.unicode() >= 0x200e &&
c.unicode() <= 0x200f)
2945 || (
c.unicode() >= 0x2066 &&
c.unicode() <= 0x2069);
2957 for (
int i=subStringFrom;
i<midStart; ++
i) {
2959 if (isRetainableControlCode(
c))
2964 for (
int i=midStart + midLength;
i<subStringTo; ++
i) {
2966 if (isRetainableControlCode(
c))
2970 return prefix + ellidePrefix +
QStringView{
string}.
mid(midStart, midLength) + ellideSuffix + suffix;
3022 QChar ellipsisChar =
u'\x2026';
3031 engine = multiEngine->
engine(0);
3044 ellipsisText = ellipsisChar;
3056 ellipsisText = ellipsisChar;
3061 const QFixed availableWidth =
width - ellipsisWidth;
3062 if (availableWidth < 0)
3069 constexpr char16_t ZWJ =
u'\x200d';
3074 int nextBreak = from;
3080 while (nextBreak < layoutData->
string.
length() && !
attributes[nextBreak].graphemeBoundary)
3083 currentWidth += this->
width(pos, nextBreak -
pos);
3084 }
while (nextBreak < to
3085 && currentWidth < availableWidth);
3103 while (nextBreak > 0 && !
attributes[nextBreak].graphemeBoundary)
3106 currentWidth += this->
width(nextBreak,
pos - nextBreak);
3107 }
while (nextBreak > from
3108 && currentWidth < availableWidth);
3111 ellipsisText.
append(ZWJ);
3122 int nextLeftBreak = from;
3125 int nextRightBreak = to;
3128 leftPos = nextLeftBreak;
3129 rightPos = nextRightBreak;
3132 while (nextLeftBreak < layoutData->
string.
length() && !
attributes[nextLeftBreak].graphemeBoundary)
3136 while (nextRightBreak > from && !
attributes[nextRightBreak].graphemeBoundary)
3139 leftWidth += this->
width(leftPos, nextLeftBreak - leftPos);
3140 rightWidth += this->
width(nextRightBreak, rightPos - nextRightBreak);
3141 }
while (nextLeftBreak < to
3142 && nextRightBreak > from
3143 && leftWidth + rightWidth < availableWidth);
3148 ellipsisText.
append(ZWJ);
3156 void QTextEngine::setBoundary(
int strPos)
const
3190 const auto cit = std::find_if(
cbegin,
cend, isLeftOrRightTab);
3194 const auto end = tabArray.
end();
3215 tabSectionEnd =
item.position;
3237 const int end = qMin(
item.position +
item.num_glyphs, tabSectionEnd) -
item.position;
3238 for (
int i=0;
i <
end;
i++)
3244 switch (tabSpec.type) {
3266 QFixed nextTabPos = ((
x / tab).truncate() + 1) * tab;
3267 QFixed tabWidth = nextTabPos -
x;
3273 class FormatRangeComparatorByStart {
3281 class FormatRangeComparatorByEnd {
3291 void QTextEngine::resolveFormats()
const
3293 if (!specialData || specialData->formats.isEmpty())
3295 Q_ASSERT(specialData->resolvedFormats.isEmpty());
3302 formatsSortedByStart.
reserve(specialData->formats.size());
3303 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
3304 if (specialData->formats.at(
i).length >= 0)
3305 formatsSortedByStart.
append(
i);
3308 std::sort(formatsSortedByStart.
begin(), formatsSortedByStart.
end(),
3309 FormatRangeComparatorByStart(specialData->formats));
3310 std::sort(formatsSortedByEnd.
begin(), formatsSortedByEnd.
end(),
3311 FormatRangeComparatorByEnd(specialData->formats));
3314 const int *startIt = formatsSortedByStart.
constBegin();
3315 const int *endIt = formatsSortedByEnd.
constBegin();
3321 while (startIt != formatsSortedByStart.
constEnd() &&
3322 specialData->formats.at(*startIt).start <= si->
position) {
3323 currentFormats.
insert(std::upper_bound(currentFormats.
begin(), currentFormats.
end(), *startIt),
3327 while (endIt != formatsSortedByEnd.
constEnd() &&
3328 specialData->formats.at(*endIt).start + specialData->formats.at(*endIt).length <
end) {
3329 int *currentFormatIterator = std::lower_bound(currentFormats.
begin(), currentFormats.
end(), *endIt);
3330 if (*endIt < *currentFormatIterator)
3331 currentFormatIterator = currentFormats.
end();
3332 currentFormats.
remove(currentFormatIterator - currentFormats.
begin());
3342 if (!currentFormats.
isEmpty()) {
3343 for (
int cur : currentFormats) {
3352 specialData->resolvedFormats = resolvedFormats;
3357 if (!
line.hasTrailingSpaces
3371 int align =
option.alignment();
3387 int offsetInCluster = 0;
3388 for (
int i =
pos - 1;
i >= 0;
i--) {
3397 if (offsetInCluster > 0) {
3398 int clusterLength = 0;
3399 for (
int i =
pos - offsetInCluster;
i < max;
i++) {
3406 return glyphs.
advances[glyph_pos] * offsetInCluster / clusterLength;
3413 int QTextEngine::getClusterLength(
unsigned short *
logClusters,
3415 int from,
int to,
int glyph_pos,
int *
start)
3417 int clusterLength = 0;
3418 for (
int i = from;
i < to;
i++) {
3424 else if (clusterLength)
3427 return clusterLength;
3432 bool cursorOnCharacter)
3435 int clusterStart = -1;
3436 int clusterLength = 0;
3445 if (glyph_pos == -1)
3449 for (
i = 0;
i <
end;
i++)
3456 if (glyph_pos == -1 &&
end > 0)
3465 clusterLength = getClusterLength(
logClusters, attrs, 0,
end, glyph_pos, &clusterStart);
3467 if (clusterLength) {
3471 QFixed perItemWidth = glyphWidth / clusterLength;
3472 if (perItemWidth <= 0)
3473 return si->
position + clusterStart;
3474 QFixed left =
x > edge ? edge : edge - glyphWidth;
3477 int closestItem =
dist > (perItemWidth / 2) ?
n + 1 :
n;
3478 if (cursorOnCharacter && closestItem > 0)
3480 int pos = clusterStart + closestItem;
3482 while (
pos <
end && !attrs[
pos].graphemeBoundary)
3495 if (!attrs || oldPos <= 0 || oldPos >
len)
3499 while (oldPos && !attrs[oldPos].graphemeBoundary)
3510 if (!attrs || oldPos < 0 || oldPos >=
len)
3514 while (oldPos <
len && !attrs[oldPos].graphemeBoundary)
3537 std::vector<int> insertionPoints;
3538 insertionPoints.reserve(
size_t(
iterator.line.length));
3540 bool lastLine = lineNum >=
lines.
size() - 1;
3550 insertionPoints.push_back(
i);
3553 insertionPoints.push_back(
i);
3556 return insertionPoints;
3559 int QTextEngine::endOfLine(
int lineNum)
3562 if (insertionPoints.size() > 0)
3563 return insertionPoints.back();
3567 int QTextEngine::beginningOfLine(
int lineNum)
3570 if (insertionPoints.size() > 0)
3571 return insertionPoints.front();
3589 for (
size_t i = 0, max = insertionPoints.size();
i < max; ++
i)
3590 if (
pos == insertionPoints[
i]) {
3593 return insertionPoints[
i + 1];
3596 return insertionPoints[
i - 1];
3599 if (moveRight ^ alignRight) {
3601 return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1);
3605 return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);
3642 if (decorationList.isEmpty())
3645 for (
const ItemDecoration &
decoration : decorationList) {
3687 underlinePos = qMax(underlinePos,
it->y);
3688 penWidth = qMax(penWidth,
it->pen.widthF());
3692 underlinePos =
start->y;
3693 penWidth =
start->pen.widthF();
3695 lastLineEnd =
it->x2;
3707 it->y = underlinePos;
3708 it->pen.setWidthF(penWidth);
3714 _layoutData(
string, _memory, MemSize)
3723 fontEngine(
font->
d->engineForScript(si.analysis.
script))
3732 num_chars(numChars),
3754 ||
f->d->underline) {
3829 line(eng->lines[_lineNum]),
3833 firstItem(eng->findItem(
line.from)),
3834 lastItem(eng->findItem(lineEnd - 1, firstItem)),
3835 nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
3838 visualOrder(nItems),
3898 *selectionX = *selectionWidth = 0;
3919 int start_glyph = logClusters[from];
3926 for (
int g = end_glyph - 1;
g >= start_glyph; --
g)
3931 for (
int g = start_glyph;
g < end_glyph; ++
g)
3940 *selectionX =
x + soff + leftOffsetInLigature;
3941 *selectionWidth = swidth - leftOffsetInLigature;
small capitals from c petite p scientific f u
small capitals from c petite p scientific i
[1]
xD9 x84 xD8 xAD xD9 x80 xF0 x90 xAC x9A xE0 xA7 xA6 xE0 xA7 xAA xF0 x91 x84 xA4 xF0 x91 x84 x89 xF0 x91 x84 x9B xF0 x90 x8A xAB xF0 x90 x8B x89 xE2 xB2 x9E xE2 xB2 x9F xD0 xBE xD0 x9E xF0 x90 x90 x84 xF0 x90 x90 xAC xE1 x83 x98 xE1 x83 x94 xE1 x83 x90 xE1 xB2 xBF xE2 xB0 x95 xE2 xB1 x85 xCE xBF xCE x9F xE0 xA8 xA0 xE0 xA8 xB0 xE0 xA9 xA6 Kayah xEA xA4 x8D xEA xA4 x80 Khmer xE1 xA7 xA1 xE1 xA7 xAA xE0 xBB x90 Latin Subscript xE2 x82 x92 xE2 x82 x80 xEA x93 xB3 xF0 x96 xB9 xA1 xF0 x96 xB9 x9B xF0 x96 xB9 xAF xE1 x80 x9D xE1 x80 x84 xE1 x80 x82 no script
virtual void resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
QPaintDevice * paintDevice() const
The QChar class provides a 16-bit Unicode character.
constexpr bool isLetterOrNumber() const noexcept
static constexpr char32_t surrogateToUcs4(char16_t high, char16_t low) noexcept
@ ObjectReplacementCharacter
QChar toLower() const noexcept
constexpr bool isLowSurrogate() const noexcept
constexpr char16_t unicode() const noexcept
bool isPrint() const noexcept
static constexpr char16_t lowSurrogate(char32_t ucs4) noexcept
Category category() const noexcept
constexpr bool isSpace() const noexcept
constexpr bool isHighSurrogate() const noexcept
operator<<(QDataStream &ds, qfloat16 f)
The QDebug class provides an output stream for debugging information.
virtual bool supportsHorizontalSubPixelPositions() const
virtual QFixed descent() const
virtual QFixed ascent() const
static bool scriptRequiresOpenType(QChar::Script script)
virtual glyph_t glyphIndex(uint ucs4) const =0
virtual QFontEngine * cloneWithSize(qreal) const
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const
virtual QFixed leading() const
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const =0
void ensureEngineAt(int at)
static QFontEngine * createMultiFontEngine(QFontEngine *fe, int script)
QFontEngine * engine(int at) const
The QFont class specifies a query for a font used for drawing text.
StyleStrategy styleStrategy() const
qreal letterSpacing() const
QFont resolve(const QFont &) const
Capitalization capitalization() const
qreal wordSpacing() const
bool letterSpacingIsAbsolute
QFontPrivate * smallCapsFontPrivate() const
QFontEngine * engineForScript(int script) const
QFont smallCapsFont() const
GraphicsItemFlags flags() const
static QInputMethod * inputMethod()
The QLineF class provides a two-dimensional vector using floating point precision.
qsizetype size() const noexcept
const_pointer constData() const noexcept
bool isEmpty() const noexcept
iterator insert(qsizetype i, parameter_type t)
const_reference at(qsizetype i) const noexcept
qsizetype count() const noexcept
void reserve(qsizetype size)
const_iterator cend() const noexcept
void append(parameter_type t)
const_iterator cbegin() const noexcept
The QPainter class performs low-level painting on widgets and other paint devices.
void setPen(const QColor &color)
void drawLine(const QLineF &line)
The QPen class defines how a QPainter should draw lines and outlines of shapes.
The QPointF class defines a point in the plane using floating point precision.
constexpr int x() const noexcept
The QRectF class defines a finite rectangle in the plane using floating point precision.
constexpr int width() const noexcept
QStackTextEngine(const QString &string, const QFont &f)
The QString class provides a Unicode character string.
QString & prepend(QChar c)
const QChar * constData() const
QString mid(qsizetype position, qsizetype n=-1) const
const QChar at(qsizetype i) const
QString & insert(qsizetype i, QChar c)
QString & append(QChar c)
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
bool isRightToLeft() const
const QChar * unicode() const
void resize(qsizetype size)
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
bool isRightToLeft() const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
QTextCharFormat charFormat() const
The QTextBoundaryFinder class provides a way of finding Unicode text boundaries in a string.
The QTextCharFormat class provides formatting information for characters in a QTextDocument....
UnderlineStyle underlineStyle() const
bool fontStrikeOut() const
QFont::Capitalization fontCapitalization() const
bool fontOverline() const
FragmentMap::ConstIterator FragmentIterator
static const QTextDocumentPrivate * get(const QTextDocument *document)
QAbstractTextDocumentLayout * layout() const
QList< ItemDecoration > ItemDecorationList
glyph_metrics_t boundingBox(int from, int len) const
void setPreeditArea(int position, const QString &text)
int lineNumberForTextPosition(int pos)
ItemDecorationList strikeOutList
QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags=0, int from=0, int count=-1) const
void justify(const QScriptLine &si)
ItemDecorationList underlineList
QAbstractTextDocumentLayout * docLayout() const
bool isRightToLeft() const
void shapeLine(const QScriptLine &line)
QGlyphLayout shapedGlyphs(const QScriptItem *si) const
int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter)
int findItem(int strPos, int firstItem=0) const
void shape(int item) const
void resetFontEngineCache()
const QCharAttributes * attributes() const
void addOverline(QPainter *painter, const QLineF &line)
QFixed leadingSpaceWidth(const QScriptLine &line)
QFixed alignLine(const QScriptLine &line)
bool ensureSpace(int nGlyphs) const
int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op)
int formatIndex(const QScriptItem *si) const
QFontEngine * fontEngine(const QScriptItem &si, QFixed *ascent=nullptr, QFixed *descent=nullptr, QFixed *leading=nullptr) const
void drawDecorations(QPainter *painter)
QFixed calculateTabWidth(int index, QFixed x) const
returns the width of tab at index (in the tabs array) with the tab-start at position x
bool atWordSeparator(int position) const
void addStrikeOut(QPainter *painter, const QLineF &line)
void setFormats(const QList< QTextLayout::FormatRange > &formats)
QGlyphLayout availableGlyphs(const QScriptItem *si) const
unsigned short * logClusters(const QScriptItem *si) const
void addUnderline(QPainter *painter, const QLineF &line)
QTextCharFormat format(const QScriptItem *si) const
std::vector< int > insertionPointsForLine(int lineNum)
int nextLogicalPosition(int oldPos) const
QFixed width(int charFrom, int numChars) const
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
glyph_metrics_t tightBoundingBox(int from, int len) const
int previousLogicalPosition(int oldPos) const
QTextFormatCollection * formatCollection() const
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos)
QList< QTextLayout::FormatRange > formats() const
int length(int item) const
ItemDecorationList overlineList
int indexForFormat(const QTextFormat &f)
QFont defaultFont() const
QTextCharFormat charFormat(int index) const
bool boolProperty(int propertyId) const
bool hasProperty(int propertyId) const
The QTextInlineObject class represents an inline object in a QAbstractTextDocumentLayout and its impl...
void initWithScriptItem(const QScriptItem &si)
const QTextCharFormat charFormat
QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const
const unsigned short * logClusters
QTextCharFormat::UnderlineStyle underlineStyle
@ ShowLineAndParagraphSeparators
constexpr size_type size() const noexcept
void remove(qsizetype i, qsizetype n=1)
value_type value(qsizetype i) const
void resize(qsizetype sz)
void insert(qsizetype i, T &&t)
const_iterator constEnd() const
const T & at(qsizetype idx) const
auto constBegin() const -> const_iterator
void reserve(qsizetype sz)
iterator begin() noexcept
const QLoggingCategory & category()
[1]
for(n=0;n< outline->n_points;n++)
constexpr T & operator()(T &v) const
void hb_buffer_add_utf16(hb_buffer_t *buffer, const uint16_t *text, int text_length, unsigned int item_offset, int item_length)
void hb_buffer_reverse(hb_buffer_t *buffer)
hb_bool_t hb_buffer_pre_allocate(hb_buffer_t *buffer, unsigned int size)
void hb_buffer_clear_contents(hb_buffer_t *buffer)
void hb_buffer_set_segment_properties(hb_buffer_t *buffer, const hb_segment_properties_t *props)
unsigned int hb_buffer_get_length(hb_buffer_t *buffer)
hb_buffer_t * hb_buffer_create()
void hb_buffer_set_flags(hb_buffer_t *buffer, hb_buffer_flags_t flags)
hb_glyph_position_t * hb_buffer_get_glyph_positions(hb_buffer_t *buffer, unsigned int *length)
void hb_buffer_destroy(hb_buffer_t *buffer)
hb_bool_t hb_buffer_allocation_successful(hb_buffer_t *buffer)
void hb_buffer_set_unicode_funcs(hb_buffer_t *buffer, hb_unicode_funcs_t *unicode_funcs)
hb_glyph_info_t * hb_buffer_get_glyph_infos(hb_buffer_t *buffer, unsigned int *length)
hb_language_t hb_language_get_default()
hb_bool_t hb_shape_full(hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features, const char *const *shaper_list)
auto generate(StringRef generatorName, SourceLineInfo const &lineInfo, L const &generatorExpression) -> decltype(std::declval< decltype(generatorExpression())>().get())
typename C::iterator iterator
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
const PluginKeyMapConstIterator cend
Q_DECL_CONST_FUNCTION Q_CORE_EXPORT const Properties *QT_FASTCALL properties(char32_t ucs4) noexcept
QTextStream & hex(QTextStream &stream)
QTextStream & dec(QTextStream &stream)
decltype(auto) cbegin(const T &t)
int distance(TestIterator &a, TestIterator &b)
void *PRIV() memmove(void *d, const void *s, size_t n)
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d ®2 endm macro vzip8 reg2 vzip d d ®2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
[3]
set set set set set set set macro pixldst1 op
#define QT_WARNING_DISABLE_GCC(text)
constexpr bool operator!=(const timespec &t1, const timespec &t2)
constexpr timespec operator*(const timespec &t1, int mul)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Q_GUI_EXPORT int qt_defaultDpiY()
#define QT_BEGIN_INCLUDE_NAMESPACE
QT_END_INCLUDE_NAMESPACE typedef double qreal
#define QT_END_INCLUDE_NAMESPACE
hb_unicode_funcs_t * hb_qt_get_unicode_funcs()
hb_font_t * hb_qt_font_get_for_engine(QFontEngine *fe)
hb_script_t hb_qt_script_to_script(QChar::Script script)
void hb_qt_font_set_use_design_metrics(hb_font_t *font, uint value)
GLenum GLuint GLenum GLsizei length
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLenum const void GLbitfield GLsizei numGlyphs
GLenum GLuint GLsizei const GLenum * props
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLsizei GLenum GLsizei GLsizei GLuint memory
GLenum const void GLbitfield GLuint firstGlyphIndex
GLfloat GLfloat GLfloat GLfloat h
GLuint GLuint64EXT address
GLsizei const GLchar *const * string
[0]
#define QStringLiteral(str)
QTransform qt_true_matrix(qreal w, qreal h, const QTransform &x)
Q_DECLARE_TYPEINFO(QJustificationPoint, Q_PRIMITIVE_TYPE)
@ Justification_Arabic_Waw
@ Justification_Arabic_Kashida
@ Justification_Arabic_Alef
@ Justification_Arabic_HahDal
@ Justification_Character
@ Justification_Arabic_Space
@ Justification_Arabic_Seen
@ Justification_Arabic_BaRa
@ Justification_Arabic_Normal
@ Justification_Prohibited
#define HB_SEGMENT_PROPERTIES_DEFAULT
@ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
#define HB_TAG(c1, c2, c3, c4)
#define HB_FEATURE_GLOBAL_END
#define HB_DIRECTION_IS_BACKWARD(dir)
#define HB_FEATURE_GLOBAL_START
QFuture< QSet< QChar > > set
[10]
std::uniform_real_distribution dist(1, 2.5)
[2]
QItemSelection * selection
[0]
constexpr QFixed floor() const
constexpr int value() const
constexpr static QFixed fromReal(qreal r)
constexpr int toInt() const
constexpr qreal toReal() const
constexpr static QFixed fromFixed(int fixed)
QGlyphJustification * justifications
void grow(char *address, int totalGlyphs)
QFixed effectiveAdvance(int item) const
void clear(int first=0, int last=-1)
QGlyphAttributes * attributes
QGlyphLayout mid(int position, int n=-1) const
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
@ BidiResetToParagraphLevel
@ BidiMaybeResetToParagraphLevel
QChar::Direction bidiDirection
@ LineOrParagraphSeparator
unsigned short num_glyphs
void setDefaultHeight(QTextEngine *eng)
bool reallocate(int totalGlyphs)
unsigned short * logClustersPtr
The QTextLayout::FormatRange structure is used to apply extra formatting information for a specified ...
bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const
QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos=QPointF(), const QTextLayout::FormatRange *_selection=nullptr)
const QTextLayout::FormatRange * selection
QVarLengthArray< int > visualOrder
glyph_metrics_t transformed(const QTransform &xform) const
QPair< int, int > Position
void add(int &result, const int &sum)