4#include <QtGui/private/qtguiglobal_p.h>
13#include <QtCore/private/qunicodetables_p.h>
53 generateScriptItemsSmallCaps(
reinterpret_cast<const ushort *
>(m_string.unicode()),
start,
length);
65 enum { MaxItemLength = 4096 };
70 if (m_items.isEmpty())
86 if (m_analysis[
i].bidiLevel == m_analysis[
start].bidiLevel
88 && (m_analysis[
i].script == m_analysis[
start].script || m_string[
i] == u
'.')
90 &&
i -
start < MaxItemLength)
98 void generateScriptItemsCapitalize(
int start,
int length)
105 m_string.constData(), m_string.size(),
108 m_splitter->setPosition(
start);
114 m_splitter->toNextBoundary();
118 bool atWordStart =
false;
120 if (
i == m_splitter->position()) {
126 m_splitter->toNextBoundary();
129 if (m_analysis[
i] == itemAnalysis
132 &&
i -
start < MaxItemLength)
137 itemAnalysis = m_analysis[
start];
154 if ((m_analysis[
i] == m_analysis[
start])
157 &&
i -
start < MaxItemLength)
186enum { BidiDebugEnabled =
false };
187#define BIDI_DEBUG if (1) ; else qDebug
189enum { BidiDebugEnabled =
true };
190static const char *directions[] = {
191 "DirL",
"DirR",
"DirEN",
"DirES",
"DirET",
"DirAN",
"DirCS",
"DirB",
"DirS",
"DirWS",
"DirON",
192 "DirLRE",
"DirLRO",
"DirAL",
"DirRLE",
"DirRLO",
"DirPDF",
"DirNSM",
"DirBN",
193 "DirLRI",
"DirRLI",
"DirFSI",
"DirPDI"
195#define BIDI_DEBUG qDebug
197 return (
d << directions[
dir]);
201struct QBidiAlgorithm {
208 baseLevel(baseDirectionIsRtl ? 1 : 0)
218 void initScriptAnalysisAndIsolatePairs(Vector<IsolatePair> &isolatePairs)
220 int isolateStack[128];
221 int isolateLevel = 0;
250 if (isolateLevel < 128) {
251 isolateStack[isolateLevel] = isolatePairs.size();
258 if (isolateLevel > 0) {
260 if (isolateLevel < 128)
261 isolatePairs[isolateStack[isolateLevel]].end =
pos;
272 while (isolateLevel > 0) {
274 if (isolateLevel < 128)
275 isolatePairs[isolateStack[isolateLevel]].end =
pos;
285 struct DirectionalRun {
294 void generateDirectionalRuns(
const Vector<IsolatePair> &isolatePairs, Vector<DirectionalRun> &runs)
296 struct DirectionalStack {
297 enum { MaxDepth = 125 };
302 int runBeforeIsolate;
321 int overflowIsolateCount = 0;
322 int overflowEmbeddingCount = 0;
323 int validIsolateCount = 0;
326 bool override =
false;
327 stack.push({
level,
false,
false, -1 });
331 int continuationFrom = -1;
332 int lastRunWithContent = -1;
333 bool runHasContent =
false;
335 auto appendRun = [&](
int runEnd) {
336 if (runEnd < runStart)
338 bool isContinuation =
false;
339 if (continuationFrom != -1) {
340 runs[continuationFrom].continuation = runs.size();
341 isContinuation =
true;
342 }
else if (lastRunWithContent != -1 &&
level == runs.at(lastRunWithContent).level) {
343 runs[lastRunWithContent].continuation = runs.size();
344 isContinuation =
true;
347 lastRunWithContent = runs.size();
348 BIDI_DEBUG() <<
" appending run start/end" << runStart << runEnd <<
"level" <<
level;
349 runs.append({ runStart, runEnd, -1,
level, isContinuation, runHasContent });
350 runHasContent =
false;
351 runStart = runEnd + 1;
352 continuationFrom = -1;
355 int isolatePairPosition = 0;
361 auto doEmbed = [&](
bool isRtl,
bool isOverride,
bool isIsolate) {
365 runHasContent =
true;
366 lastRunWithContent = -1;
367 ++isolatePairPosition;
369 int runBeforeIsolate = runs.size();
370 ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.
top().
level + 2) & ~1);
371 if (newLevel <= DirectionalStack::MaxDepth && !overflowEmbeddingCount && !overflowIsolateCount) {
375 runBeforeIsolate = -1;
376 appendRun(isIsolate ?
i :
i - 1);
377 BIDI_DEBUG() <<
"pushing new item on stack: level" << (int)newLevel <<
"isOverride" << isOverride <<
"isIsolate" << isIsolate << runBeforeIsolate;
378 stack.push({ newLevel, isOverride, isIsolate, runBeforeIsolate });
379 override = isOverride;
383 ++overflowIsolateCount;
384 else if (!overflowIsolateCount)
385 ++overflowEmbeddingCount;
397 doEmbed(
false,
false,
false);
400 doEmbed(
true,
false,
false);
403 doEmbed(
false,
true,
false);
406 doEmbed(
true,
true,
false);
409 doEmbed(
false,
false,
true);
412 doEmbed(
true,
false,
true);
416 if (isolatePairPosition < isolatePairs.size()) {
417 const auto &pair = isolatePairs.at(isolatePairPosition);
421 doEmbed(isRtl,
false,
true);
430 if (overflowIsolateCount) {
432 }
else if (overflowEmbeddingCount) {
433 --overflowEmbeddingCount;
434 }
else if (!stack.top().isIsolate && stack.depth() >= 2) {
437 override = stack.top().isOverride;
438 level = stack.top().level;
439 BIDI_DEBUG() <<
"popped PDF from stack, level now" << (int)stack.top().level;
443 runHasContent =
true;
444 if (overflowIsolateCount) {
445 --overflowIsolateCount;
446 }
else if (validIsolateCount == 0) {
450 overflowEmbeddingCount = 0;
451 while (!stack.top().isIsolate)
453 continuationFrom = stack.top().runBeforeIsolate;
454 BIDI_DEBUG() <<
"popped PDI from stack, level now" << (int)stack.top().level <<
"continuation from" << continuationFrom;
456 override = stack.top().isOverride;
457 level = stack.top().level;
458 lastRunWithContent = -1;
468 while (stack.counter > 1) {
471 const auto &
t = stack.top();
473 runs[
t.runBeforeIsolate].continuation = -2;
477 continuationFrom = -1;
478 lastRunWithContent = -1;
479 validIsolateCount = 0;
480 overflowIsolateCount = 0;
481 overflowEmbeddingCount = 0;
486 runHasContent =
true;
495 while (stack.counter > 1) {
498 const auto &
t = stack.top();
500 runs[
t.runBeforeIsolate].continuation = -2;
506 void resolveExplicitLevels(Vector<DirectionalRun> &runs)
508 Vector<IsolatePair> isolatePairs;
510 initScriptAnalysisAndIsolatePairs(isolatePairs);
511 generateDirectionalRuns(isolatePairs, runs);
514 struct IsolatedRunSequenceIterator {
519 Position() =
default;
520 Position(
int current,
int pos) : current(current),
pos(
pos) {}
522 bool isValid()
const {
return pos != -1; }
525 IsolatedRunSequenceIterator(
const Vector<DirectionalRun> &runs,
int i)
529 pos = runs.at(current).start;
532 bool atEnd()
const {
return pos < 0; }
535 if (pos > runs.at(current).end) {
536 current = runs.at(current).continuation;
538 pos = runs.at(current).start;
548 return Position(current, pos);
554 const Vector<DirectionalRun> &runs;
560 void resolveW1W2W3(
const Vector<DirectionalRun> &runs,
int i,
QChar::Direction sos)
564 IsolatedRunSequenceIterator
it(runs,
i);
565 while (!
it.atEnd()) {
572 analysis[
pos].bidiDirection = current;
591 analysis[
pos].bidiDirection = current;
596 lastStrong = current;
599 lastStrong = current;
613 IsolatedRunSequenceIterator
it(runs,
i);
619 while (!
it.atEnd()) {
629 analysis[lastPos].bidiDirection = last;
633 analysis[lastPos].bidiDirection = last;
636 analysis[lastPos].bidiDirection = last;
646 void resolveW5(
const Vector<DirectionalRun> &runs,
int i)
649 IsolatedRunSequenceIterator::Position lastETPosition;
651 IsolatedRunSequenceIterator
it(runs,
i);
655 lastETPosition =
it.position();
658 while (!
it.atEnd()) {
668 analysis[
pos].bidiDirection = current;
669 }
else if (!lastETPosition.isValid()) {
670 lastETPosition =
it.position();
672 }
else if (lastETPosition.isValid()) {
674 it.setPosition(lastETPosition);
681 lastETPosition.
clear();
689 void resolveW6W7(
const Vector<DirectionalRun> &runs,
int i,
QChar::Direction sos)
692 IsolatedRunSequenceIterator
it(runs,
i);
693 while (!
it.atEnd()) {
708 lastStrong = current;
710 analysis[
pos].bidiDirection = lastStrong;
720 bool isValid()
const {
return second > 0; }
723 int isolateCounter = 0;
725 for (
int i =
first + 1;
i < second; ++
i) {
727 if (isolateCounter) {
734 if (embeddingDir ==
dir)
743 BIDI_DEBUG() <<
" contained dir for backet pair" <<
first <<
"/" << second <<
"is" << containedDir;
749 struct BracketStack {
753 uint pairedBracked = 0;
758 if (position < MaxDepth)
766 if (stack[
p].pairedBracked == unicode ||
768 (stack[
p].pairedBracked == 0x3009 && unicode == 0x232a) ||
769 (stack[
p].pairedBracked == 0x232a && unicode == 0x3009)) {
771 return stack[
p].position;
778 enum { MaxDepth = 63 };
779 Item stack[MaxDepth];
782 bool overflowed()
const {
return position > MaxDepth; }
789 Vector<BracketPair> bracketPairs;
791 BracketStack bracketStack;
792 IsolatedRunSequenceIterator
it(runs,
i);
793 while (!
it.atEnd()) {
803 bracketStack.push(closingBracked, bracketPairs.size());
804 if (bracketStack.overflowed()) {
805 bracketPairs.clear();
808 bracketPairs.append({
pos, -1 });
810 int pairPos = bracketStack.match(text[
pos].unicode());
812 bracketPairs[pairPos].second =
pos;
820 if (BidiDebugEnabled && bracketPairs.size()) {
822 for (
int i = 0;
i < bracketPairs.size(); ++
i)
823 BIDI_DEBUG() <<
" " << bracketPairs.at(
i).first << bracketPairs.at(
i).second;
827 IsolatedRunSequenceIterator
it(runs,
i);
829 for (
int i = 0;
i < bracketPairs.size(); ++
i) {
830 const auto &pair = bracketPairs.at(
i);
833 QChar::Direction containedDir = pair.containedDirection(analysis, embeddingDir);
835 BIDI_DEBUG() <<
" 3: resolve bracket pair" <<
i <<
"to DirON";
837 }
else if (containedDir == embeddingDir) {
840 BIDI_DEBUG() <<
" 1: resolve bracket pair" <<
i <<
"to" << embeddingDir;
843 while (
it.pos < pair.first) {
845 switch (analysis[
pos].bidiDirection) {
861 BIDI_DEBUG() <<
" 2: resolve bracket pair" <<
i <<
"to" << lastStrong;
863 for (
int i = pair.second + 1;
i <
length; ++
i) {
865 analysis[
i].bidiDirection = analysis[pair.second].bidiDirection;
876 IsolatedRunSequenceIterator::Position niPos;
877 IsolatedRunSequenceIterator
it(runs,
i);
891 if (niPos.isValid()) {
893 if (lastStrong != currentStrong)
895 it.setPosition(niPos);
903 lastStrong = currentStrong;
915 if (!niPos.isValid())
916 niPos =
it.position();
929 void resolveImplicitLevelsForIsolatedRun(
const Vector<DirectionalRun> &runs,
int i)
932 int level = runs.at(
i).level;
934 while (before >= 0 && !runs.at(before).hasContent)
936 int level_before = (before >= 0) ? runs.at(before).level : baseLevel;
938 while (runs.at(after).continuation >= 0)
939 after = runs.at(after).continuation;
940 if (runs.at(after).continuation == -2) {
944 while (after < runs.size() && !runs.at(after).hasContent)
947 int level_after = (after == runs.size()) ? baseLevel : runs.
at(after).
level;
951 if (BidiDebugEnabled) {
952 BIDI_DEBUG() <<
"Isolated run starting at" <<
i <<
"sos/eos" << sos << eos;
953 BIDI_DEBUG() <<
"before implicit level processing:";
954 IsolatedRunSequenceIterator
it(runs,
i);
955 while (!
it.atEnd()) {
961 resolveW1W2W3(runs,
i, sos);
962 resolveW4(runs,
i, sos);
965 if (BidiDebugEnabled) {
967 IsolatedRunSequenceIterator
it(runs,
i);
968 while (!
it.atEnd()) {
974 resolveW6W7(runs,
i, sos);
979 resolveN0(runs,
i, sos);
980 resolveN1N2(runs,
i, sos, eos);
986 IsolatedRunSequenceIterator
it(runs,
i);
987 while (!
it.atEnd()) {
1013 void resolveImplicitLevels(
const Vector<DirectionalRun> &runs)
1015 for (
int i = 0;
i < runs.size(); ++
i) {
1016 if (runs.at(
i).isContinuation)
1019 resolveImplicitLevelsForIsolatedRun(runs,
i);
1023 bool checkForBidi()
const
1028 if (text[
i].unicode() >= 0x590) {
1047 bool hasBidi = checkForBidi();
1052 if (BidiDebugEnabled) {
1059 Vector<DirectionalRun> runs;
1060 resolveExplicitLevels(runs);
1062 if (BidiDebugEnabled) {
1063 BIDI_DEBUG() <<
"resolved explicit levels, nruns" << runs.size();
1064 for (
int i = 0;
i < runs.size(); ++
i)
1065 BIDI_DEBUG() <<
" " <<
i <<
"start/end" << runs.at(
i).start << runs.at(
i).end <<
"level" << (int)runs.at(
i).level <<
"continuation" << runs.at(
i).continuation;
1071 resolveImplicitLevels(runs);
1076 bool resetLevel =
true;
1079 BIDI_DEBUG() <<
"resetting pos" <<
i <<
"to baselevel";
1083 BIDI_DEBUG() <<
"resetting pos" <<
i <<
"to baselevel (maybereset flag)";
1093 int lastLevel = baseLevel;
1102 if (lastBNPos >= 0) {
1103 if (l < lastLevel) {
1104 while (lastBNPos <
i) {
1114 if (lastBNPos >= 0 && baseLevel < lastLevel) {
1115 while (lastBNPos <
length) {
1116 analysis[lastBNPos].
bidiLevel = baseLevel;
1121 if (BidiDebugEnabled) {
1146 while (
i < numItems) {
1160 if (!(levelLow%2)) levelLow++;
1162 BIDI_DEBUG() <<
"reorderLine: lineLow = " << (
uint)levelLow <<
", lineHigh = " << (
uint)levelHigh;
1164 int count = numItems - 1;
1165 for (
i = 0;
i < numItems;
i++)
1168 while(levelHigh >= levelLow) {
1179 int tmp = visualOrder[
start+
j];
1181 visualOrder[
end-
j] = tmp;
1209#if QT_CONFIG(harfbuzz)
1218 while (str_pos <
length) {
1219 int glyph_pos = log_clusters[str_pos];
1221 Q_ASSERT(glyph_pos <
g.numGlyphs &&
g.attributes[glyph_pos].clusterStart);
1223 uint ucs4 =
string[str_pos];
1225 ushort low =
string[str_pos + 1];
1235 }
while (str_pos <
length && log_clusters[str_pos] == glyph_pos);
1238 }
while (glyph_pos <
g.numGlyphs && !
g.attributes[glyph_pos].clusterStart);
1245 g.attributes[glyph_pos].justification = spaceAs;
1253 for (
int glyph_pos = 0; glyph_pos <
g.numGlyphs; ++glyph_pos)
1285 qt_getDefaultJustificationOpportunities(
string,
length,
g, log_clusters, spaceAs);
1334 if (!fontEngine->
symbol) {
1339 const uint engineIndex = glyphs->
glyphs[glyphPosition] & 0xff000000;
1345 glyphs->
glyphs[glyphPosition] = glyph;
1347 glyphs->
glyphs[glyphPosition] |= engineIndex;
1359void QTextEngine::shapeText(
int item)
const
1375 casedString.
resize(itemLength);
1377 for (
int i = 0;
i < itemLength; ++
i) {
1378 uint ucs4 =
string[
i];
1380 uint low =
string[
i + 1];
1387 :
QChar::toUpper(ucs4);
1392 :
QChar::toUpper(ucs4);
1399 Q_UNREACHABLE_RETURN();
1404 bool kerningEnabled;
1405 bool letterSpacingIsAbsolute;
1406 bool shapingEnabled =
false;
1408 QFixed letterSpacing, wordSpacing;
1409#ifndef QT_NO_RAWFONT
1414# if QT_CONFIG(harfbuzz)
1420 letterSpacingIsAbsolute =
true;
1427#if QT_CONFIG(harfbuzz)
1436 if (letterSpacingIsAbsolute && letterSpacing.
value())
1450 QFontEngine::ShaperFlags shaperFlags =
1459 uint lastEngine = ~0u;
1460 for (
int i = 0, glyph_pos = 0;
i < itemLength; ++
i, ++glyph_pos) {
1461 const uint engineIdx = initialGlyphs.
glyphs[glyph_pos] >> 24;
1462 if (lastEngine != engineIdx) {
1464 itemBoundaries.
append(glyph_pos);
1465 itemBoundaries.
append(engineIdx);
1467 if (engineIdx != 0) {
1474 lastEngine = engineIdx;
1481 itemBoundaries.
append(0);
1482 itemBoundaries.
append(0);
1483 itemBoundaries.
append(0);
1486#if QT_CONFIG(harfbuzz)
1502 for (
int i = 0;
i < itemLength; ++
i, ++glyph_pos) {
1503 log_clusters[
i] = glyph_pos;
1506 &&
i + 1 < itemLength
1510 log_clusters[
i] = glyph_pos;
1519 const uint engineIdx = initialGlyphs.
glyphs[glyph_pos] >> 24;
1532 qWarning() <<
"Unable to allocate space for place-holder glyph";
1541 g.attributes[0].clusterStart =
true;
1544 for (
int i = 0;
i < itemLength; ++
i)
1545 log_clusters[
i] = 0;
1554#if QT_CONFIG(harfbuzz)
1555 qt_getJustificationOpportunities(
string, itemLength, si, glyphs,
logClusters(&si));
1558 if (letterSpacing != 0) {
1561 if (letterSpacingIsAbsolute)
1562 glyphs.
advances[
i - 1] += letterSpacing;
1565 advance += (letterSpacing - 100) * advance / 100;
1569 if (letterSpacingIsAbsolute)
1573 advance += (letterSpacing - 100) * advance / 100;
1576 if (wordSpacing != 0) {
1593#if QT_CONFIG(harfbuzz)
1601int QTextEngine::shapeTextWithHarfbuzzNG(
const QScriptItem &si,
1606 bool kerningEnabled,
1607 bool hasLetterSpacing,
1610 uint glyphs_shaped = 0;
1612 hb_buffer_t *
buffer = hb_buffer_create();
1614 hb_buffer_pre_allocate(
buffer, itemLength);
1616 hb_buffer_destroy(
buffer);
1620 hb_segment_properties_t
props = HB_SEGMENT_PROPERTIES_DEFAULT;
1625 props.language = hb_language_get_default();
1627 for (
int k = 0; k < itemBoundaries.
size(); k += 3) {
1628 const uint item_pos = itemBoundaries[k];
1629 const uint item_length = (k + 4 < itemBoundaries.
size() ? itemBoundaries[k + 3] : itemLength) - item_pos;
1630 const uint engineIdx = itemBoundaries[k + 2];
1637 hb_buffer_clear_contents(
buffer);
1638 hb_buffer_add_utf16(
buffer,
reinterpret_cast<const uint16_t *
>(
string) + item_pos, item_length, 0, item_length);
1642 uint buffer_flags = HB_BUFFER_FLAG_DEFAULT;
1646 buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
1647 hb_buffer_set_flags(
buffer, hb_buffer_flags_t(buffer_flags));
1661 bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
1664 features.
insert(HB_TAG(
'k',
'e',
'r',
'n'), !!kerningEnabled);
1666 features.
insert(HB_TAG(
'l',
'i',
'g',
'a'),
false);
1667 features.
insert(HB_TAG(
'c',
'l',
'i',
'g'),
false);
1668 features.
insert(HB_TAG(
'd',
'l',
'i',
'g'),
false);
1669 features.
insert(HB_TAG(
'h',
'l',
'i',
'g'),
false);
1671 features.
insert(fontFeatures);
1677 HB_FEATURE_GLOBAL_START,
1678 HB_FEATURE_GLOBAL_END });
1682 static const char *shaper_list[] = {
1689 bool shapedOk = hb_shape_full(hb_font,
1695 hb_buffer_destroy(
buffer);
1700 hb_buffer_reverse(
buffer);
1703 uint num_glyphs = hb_buffer_get_length(
buffer);
1704 const bool has_glyphs = num_glyphs > 0;
1711 hb_buffer_destroy(
buffer);
1719 hb_glyph_info_t *infos = hb_buffer_get_glyph_infos(
buffer,
nullptr);
1720 hb_glyph_position_t *
positions = hb_buffer_get_glyph_positions(
buffer,
nullptr);
1722 uint last_cluster = ~0u;
1723 uint last_glyph_pos = glyphs_shaped;
1725 g.glyphs[
i] = infos->codepoint;
1731 uint cluster = infos->cluster;
1732 if (
Q_LIKELY(last_cluster != cluster)) {
1733 g.attributes[
i].clusterStart =
true;
1737 while (last_cluster++ < cluster && str_pos < item_length)
1738 log_clusters[str_pos++] = last_glyph_pos;
1739 last_glyph_pos =
i + glyphs_shaped;
1740 last_cluster = cluster;
1745 while (str_pos < item_length)
1746 log_clusters[str_pos++] = last_glyph_pos;
1752 g.attributes[0].clusterStart =
true;
1753 g.attributes[0].dontPrint =
true;
1754 log_clusters[0] = glyphs_shaped;
1759 g.glyphs[
i] |= (engineIdx << 24);
1763 for (
uint i = 0;
i < num_glyphs; ++
i) {
1765 g.offsets[
i].x =
g.offsets[
i].x.
round();
1769 glyphs_shaped += num_glyphs;
1772 hb_buffer_destroy(
buffer);
1774 return glyphs_shaped;
1781 e->ignoreBidi =
false;
1782 e->cacheGlyphs =
false;
1783 e->forceJustification =
false;
1784 e->visualMovement =
false;
1785 e->delayDecorations =
false;
1787 e->layoutData =
nullptr;
1792 e->specialData =
nullptr;
1793 e->stackEngine =
false;
1794#ifndef QT_NO_RAWFONT
1795 e->useRawFont =
false;
1837 scriptItems.
data(), scriptItems.
size(),
1867 fontEngine(li, &li.ascent, &li.descent, &li.leading);
1880 if (fontEngine && !fontEngine->
ref.
deref())
1922 if (specialData && specialData->preeditPosition != -1)
1949 for (
int i = 0;
i < scriptItems.
size(); ++
i) {
1950 const auto &
item = scriptItems.
at(
i);
1953 analysis[
j].script =
item.script;
1964 if (doc_p !=
nullptr
1965 && doc_p->
layout() !=
nullptr
1982 *
const_cast<ushort*
>(uc) = 0x21B5;
2011 SpecialData *
s = specialData;
2017 int preeditPosition =
s ?
s->preeditPosition : INT_MAX;
2018 int prevPosition = 0;
2025 preeditPosition = INT_MAX;
2033 for (
const auto &
range : std::as_const(
s->formats)) {
2037 if (
range.start > prevPosition)
2038 itemizer.generate(prevPosition,
range.start - prevPosition, capitalization);
2039 int newStart = std::max(prevPosition,
range.start);
2041 itemizer.generate(newStart, newEnd - newStart,
range.format.fontCapitalization());
2042 prevPosition = newEnd;
2046 itemizer.generate(prevPosition,
position - prevPosition, capitalization);
2059#ifndef QT_NO_RAWFONT
2062 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2077 addRequiredBoundaries();
2083 switch (
option.textDirection()) {
2106 int left = firstItem + 1;
2112 else if (strPos < layoutData->
items.
at(middle).position)
2122template<
typename InnerFunc>
2128 int ilen = textEngine->
length(
i);
2132 if (
pos + ilen > from) {
2144 unsigned short *logClusters = textEngine->
logClusters(si);
2151 int charFrom = from -
pos;
2154 int glyphStart = logClusters[charFrom];
2155 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)
2156 while (charFrom < ilen && logClusters[charFrom] == glyphStart)
2158 if (charFrom < ilen) {
2159 glyphStart = logClusters[charFrom];
2160 int charEnd = from +
len - 1 -
pos;
2161 if (charEnd >= ilen)
2163 int glyphEnd = logClusters[charEnd];
2164 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)
2166 glyphEnd = (charEnd == ilen) ? si->
num_glyphs : logClusters[charEnd];
2169 innerFunc(glyphStart, glyphEnd, si);
2182 textIterator(
this, from,
len,
w, [
this, &
w](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2184 for (
int j = glyphStart;
j < glyphEnd;
j++)
2197 textIterator(
this, from,
len, gm.
width, [
this, &gm](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2198 if (glyphStart <= glyphEnd) {
2199 QGlyphLayout glyphs = this->shapedGlyphs(si);
2200 QFontEngine *fe = this->fontEngine(*si);
2201 glyph_metrics_t m = fe->boundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));
2202 gm.x = qMin(gm.x, m.x + gm.xoff);
2203 gm.y = qMin(gm.y, m.y + gm.yoff);
2204 gm.width = qMax(gm.width, m.width + gm.xoff);
2205 gm.height = qMax(gm.height, m.height + gm.yoff);
2220 textIterator(
this, from,
len, gm.
width, [
this, &gm](
int glyphStart,
int glyphEnd,
const QScriptItem *si) {
2221 if (glyphStart <= glyphEnd) {
2222 QGlyphLayout glyphs = this->shapedGlyphs(si);
2223 QFontEngine *fe = fontEngine(*si);
2224 glyph_metrics_t m = fe->tightBoundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));
2225 gm.x = qMin(gm.x, m.x + gm.xoff);
2226 gm.y = qMin(gm.y, m.y + gm.yoff);
2227 gm.width = qMax(gm.width, m.width + gm.xoff);
2228 gm.height = qMax(gm.height, m.height + gm.yoff);
2244 if (document_d !=
nullptr && document_d->
layout() !=
nullptr) {
2267QTextEngine::FontEngineCache::FontEngineCache()
2281#ifndef QT_NO_RAWFONT
2283 if (feCache.prevFontEngine && feCache.prevFontEngine->type() ==
QFontEngine::Multi && feCache.prevScript == script) {
2284 engine = feCache.prevFontEngine;
2287 feCache.prevFontEngine =
engine;
2288 feCache.prevScript = script;
2290 if (feCache.prevScaledFontEngine) {
2292 feCache.prevScaledFontEngine =
nullptr;
2296 if (feCache.prevScaledFontEngine) {
2297 scaledEngine = feCache.prevScaledFontEngine;
2309 feCache.prevScaledFontEngine = scaledEngine;
2311 if (!scEngine->ref.deref())
2321 if (feCache.prevFontEngine && feCache.prevPosition == si.
position && feCache.prevLength ==
length(&si) && feCache.prevScript == script) {
2322 engine = feCache.prevFontEngine;
2323 scaledEngine = feCache.prevScaledFontEngine;
2351 if (feCache.prevFontEngine)
2353 feCache.prevFontEngine =
engine;
2355 if (feCache.prevScaledFontEngine)
2357 feCache.prevScaledFontEngine = scaledEngine;
2359 feCache.prevScript = script;
2360 feCache.prevPosition = si.
position;
2361 feCache.prevLength =
length(&si);
2364 if (feCache.prevFontEngine && feCache.prevScript == script && feCache.prevPosition == -1) {
2365 engine = feCache.prevFontEngine;
2370 if (feCache.prevFontEngine)
2372 feCache.prevFontEngine =
engine;
2374 feCache.prevScript = script;
2375 feCache.prevPosition = -1;
2376 feCache.prevLength = -1;
2377 feCache.prevScaledFontEngine =
nullptr;
2383 scaledEngine =
p->engineForScript(script);
2391 *ascent =
engine->ascent();
2392 *descent =
engine->descent();
2393 *leading =
engine->leading();
2397 return scaledEngine;
2412 point->
glyph = glyph;
2415 const char32_t ch = U
'\x640';
2418 if (kashidaGlyph != 0) {
2421 g.glyphs = &kashidaGlyph;
2438 if (
line.gridfitted &&
line.justified)
2441 if (!
line.gridfitted) {
2468 while (line_length &&
a[line_length-1].whiteSpace)
2473 if (line_length <= 0)
2477 int lastItem =
findItem(
line.from + line_length - 1, firstItem);
2478 int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2483 QFixed minKashida = 0x100000;
2488 for (
int i = 0;
i < nItems; ++
i) {
2494 for (
int i = 0;
i < nItems; ++
i) {
2498 int kashida_pos = -1;
2505 int gs = log_clusters[
start];
2512 for (
int i = gs;
i < ge; ++
i) {
2514 g.justifications[
i].nKashidas = 0;
2515 g.justifications[
i].space_18d6 = 0;
2517 justificationPoints.
resize(nPoints+3);
2518 int justification =
g.attributes[
i].justification;
2520 switch(justification) {
2525 if (kashida_pos >= 0) {
2527 set(&justificationPoints[nPoints], kashida_type,
g.mid(kashida_pos),
fontEngine(si));
2528 if (justificationPoints[nPoints].kashidaWidth > 0) {
2529 minKashida =
qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
2530 maxJustify =
qMax(maxJustify, justificationPoints[nPoints].
type);
2538 set(&justificationPoints[nPoints++], justification,
g.mid(
i),
fontEngine(si));
2539 maxJustify =
qMax(maxJustify, justification);
2548 if (justification >= kashida_type) {
2550 kashida_type = justification;
2554 if (kashida_pos >= 0) {
2555 set(&justificationPoints[nPoints], kashida_type,
g.mid(kashida_pos),
fontEngine(si));
2556 if (justificationPoints[nPoints].kashidaWidth > 0) {
2557 minKashida =
qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
2558 maxJustify =
qMax(maxJustify, justificationPoints[nPoints].
type);
2577 while (need >= minKashida) {
2579 for (
int i = 0; need >= minKashida &&
i < nPoints; ++
i) {
2580 if (justificationPoints[
i].
type ==
type && justificationPoints[
i].kashidaWidth <= need) {
2581 justificationPoints[
i].glyph.justifications->nKashidas++;
2583 justificationPoints[
i].glyph.justifications->space_18d6 += justificationPoints[
i].kashidaWidth.
value();
2584 need -= justificationPoints[
i].kashidaWidth;
2596 for (
int type = maxJustify; need != 0 &&
type > 0; --
type) {
2598 for (
int i = 0;
i < nPoints; ++
i) {
2599 if (justificationPoints[
i].
type ==
type)
2608 for (
int i = 0;
i < nPoints; ++
i) {
2609 if (justificationPoints[
i].
type ==
type) {
2612 justificationPoints[
i].glyph.justifications[0].space_18d6 =
add.value();
2640 QFixed other_ascent =
e->ascent();
2641 QFixed other_descent =
e->descent();
2642 QFixed other_leading =
e->leading();
2667 int space_charAttributes = int(
sizeof(
QCharAttributes) *
string.
size() /
sizeof(
void*) + 1);
2668 int space_logClusters = int(
sizeof(
unsigned short) *
string.
size() /
sizeof(
void*) + 1);
2683 void *
m =
memory + space_charAttributes + space_logClusters;
2686 memset(
memory, 0, space_charAttributes*
sizeof(
void *));
2697 if (!memory_on_stack)
2704 Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs);
2705 if (memory_on_stack && available_glyphs >= totalGlyphs) {
2706 glyphLayout.grow(glyphLayout.data(), totalGlyphs);
2710 int space_charAttributes = int(
sizeof(
QCharAttributes) *
string.
size() /
sizeof(
void*) + 1);
2711 int space_logClusters = int(
sizeof(
unsigned short) *
string.
size() /
sizeof(
void*) + 1);
2714 int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
2718 if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {
2723 void **newMem = (
void **)::realloc(memory_on_stack ?
nullptr :
memory, newAllocated*
sizeof(
void *));
2728 if (memory_on_stack)
2729 memcpy(newMem,
memory, allocated*
sizeof(
void *));
2731 memory_on_stack =
false;
2734 m += space_charAttributes;
2735 logClustersPtr = (
unsigned short *)
m;
2736 m += space_logClusters;
2738 const int space_preGlyphLayout = space_charAttributes + space_logClusters;
2739 if (allocated < space_preGlyphLayout)
2740 memset(
memory + allocated, 0, (space_preGlyphLayout - allocated)*
sizeof(
void *));
2742 glyphLayout.grow(
reinterpret_cast<char *
>(
m), totalGlyphs);
2744 allocated = newAllocated;
2782 specialData->resolvedFormats.clear();
2791 if (specialData && !specialData->resolvedFormats.isEmpty()) {
2801 if (specialData && si->
position >= specialData->preeditPosition) {
2802 if (si->
position < specialData->preeditPosition + specialData->preeditText.size())
2805 pos -= specialData->preeditText.size();
2808 return it.value()->format;
2819void QTextEngine::addRequiredBoundaries()
const
2822 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2824 setBoundary(
r.start);
2825 setBoundary(
r.start +
r.length);
2834 switch (
c.unicode()) {
2878 if (specialData->formats.isEmpty()) {
2880 specialData =
nullptr;
2882 specialData->preeditText =
QString();
2883 specialData->preeditPosition = -1;
2887 specialData =
new SpecialData;
2888 specialData->preeditPosition =
position;
2889 specialData->preeditText = preeditText;
2900 if (specialData->preeditText.isEmpty()) {
2902 specialData =
nullptr;
2904 specialData->formats.clear();
2908 specialData =
new SpecialData;
2909 specialData->preeditPosition = -1;
2911 specialData->formats =
formats;
2918void QTextEngine::indexFormats()
2924 collection = specialData->formatCollection.data();
2928 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
2960 return (
c.unicode() >= 0x202a &&
c.unicode() <= 0x202e)
2961 || (
c.unicode() >= 0x200e &&
c.unicode() <= 0x200f)
2962 || (
c.unicode() >= 0x2066 &&
c.unicode() <= 0x2069);
2974 for (
int i=subStringFrom;
i<midStart; ++
i) {
2981 for (
int i=midStart + midLength;
i<subStringTo; ++
i) {
2987 return prefix + ellidePrefix +
QStringView{
string}.
mid(midStart, midLength) + ellideSuffix + suffix;
3039 QChar ellipsisChar = u
'\x2026';
3059 engine->recalcAdvances(&glyphs, { });
3061 ellipsisText = ellipsisChar;
3063 glyph =
engine->glyphIndex(
'.');
3065 engine->recalcAdvances(&glyphs, { });
3072 engine->recalcAdvances(&glyphs, { });
3073 ellipsisText = ellipsisChar;
3078 const QFixed availableWidth =
width - ellipsisWidth;
3079 if (availableWidth < 0)
3086 constexpr char16_t ZWJ = u
'\x200d';
3091 int nextBreak = from;
3097 while (nextBreak < layoutData->
string.
size() && !
attributes[nextBreak].graphemeBoundary)
3100 currentWidth += this->
width(pos, nextBreak -
pos);
3101 }
while (nextBreak < to
3102 && currentWidth < availableWidth);
3120 while (nextBreak > 0 && !
attributes[nextBreak].graphemeBoundary)
3123 currentWidth += this->
width(nextBreak,
pos - nextBreak);
3124 }
while (nextBreak > from
3125 && currentWidth < availableWidth);
3128 ellipsisText.
append(ZWJ);
3139 int nextLeftBreak = from;
3142 int nextRightBreak = to;
3145 leftPos = nextLeftBreak;
3146 rightPos = nextRightBreak;
3149 while (nextLeftBreak < layoutData->
string.
size() && !
attributes[nextLeftBreak].graphemeBoundary)
3153 while (nextRightBreak > from && !
attributes[nextRightBreak].graphemeBoundary)
3156 leftWidth += this->
width(leftPos, nextLeftBreak - leftPos);
3157 rightWidth += this->
width(nextRightBreak, rightPos - nextRightBreak);
3158 }
while (nextLeftBreak < to
3159 && nextRightBreak > from
3160 && leftWidth + rightWidth < availableWidth);
3165 ellipsisText.
append(ZWJ);
3173void QTextEngine::setBoundary(
int strPos)
const
3205 const auto cbegin = tabArray.
cbegin();
3206 const auto cend = tabArray.
cend();
3207 const auto cit = std::find_if(cbegin, cend, isLeftOrRightTab);
3209 const int index = std::distance(cbegin, cit);
3211 const auto end = tabArray.
end();
3232 tabSectionEnd =
item.position;
3255 for (
int i=0;
i <
end;
i++)
3261 switch (tabSpec.type) {
3283 QFixed nextTabPos = ((
x / tab).truncate() + 1) * tab;
3284 QFixed tabWidth = nextTabPos -
x;
3290class FormatRangeComparatorByStart {
3294 bool operator()(
int a,
int b) {
3298class FormatRangeComparatorByEnd {
3302 bool operator()(
int a,
int b) {
3308void QTextEngine::resolveFormats()
const
3310 if (!specialData || specialData->formats.isEmpty())
3312 Q_ASSERT(specialData->resolvedFormats.isEmpty());
3319 formatsSortedByStart.
reserve(specialData->formats.size());
3320 for (
int i = 0;
i < specialData->formats.size(); ++
i) {
3321 if (specialData->formats.at(
i).length >= 0)
3322 formatsSortedByStart.
append(
i);
3325 std::sort(formatsSortedByStart.
begin(), formatsSortedByStart.
end(),
3326 FormatRangeComparatorByStart(specialData->formats));
3327 std::sort(formatsSortedByEnd.
begin(), formatsSortedByEnd.
end(),
3328 FormatRangeComparatorByEnd(specialData->formats));
3331 const int *startIt = formatsSortedByStart.
constBegin();
3332 const int *endIt = formatsSortedByEnd.
constBegin();
3338 while (startIt != formatsSortedByStart.
constEnd() &&
3339 specialData->formats.at(*startIt).start <= si->
position) {
3340 currentFormats.
insert(std::upper_bound(currentFormats.
begin(), currentFormats.
end(), *startIt),
3344 while (endIt != formatsSortedByEnd.
constEnd() &&
3345 specialData->formats.at(*endIt).start + specialData->formats.at(*endIt).length <
end) {
3346 int *currentFormatIterator = std::lower_bound(currentFormats.
begin(), currentFormats.
end(), *endIt);
3347 if (*endIt < *currentFormatIterator)
3348 currentFormatIterator = currentFormats.
end();
3349 currentFormats.
remove(currentFormatIterator - currentFormats.
begin());
3359 if (!currentFormats.
isEmpty()) {
3360 for (
int cur : currentFormats) {
3369 specialData->resolvedFormats = resolvedFormats;
3374 if (!
line.hasTrailingSpaces
3388 int align =
option.alignment();
3404 int offsetInCluster = 0;
3405 for (
int i =
pos - 1;
i >= 0;
i--) {
3414 if (offsetInCluster > 0) {
3415 int clusterLength = 0;
3416 for (
int i =
pos - offsetInCluster;
i < max;
i++) {
3423 return glyphs.
advances[glyph_pos] * offsetInCluster / clusterLength;
3430int QTextEngine::getClusterLength(
unsigned short *
logClusters,
3432 int from,
int to,
int glyph_pos,
int *
start)
3434 int clusterLength = 0;
3435 for (
int i = from;
i < to;
i++) {
3441 else if (clusterLength)
3444 return clusterLength;
3449 bool cursorOnCharacter)
3452 int clusterStart = -1;
3453 int clusterLength = 0;
3462 if (glyph_pos == -1)
3466 for (
i = 0;
i <
end;
i++)
3473 if (glyph_pos == -1 &&
end > 0)
3484 if (clusterLength) {
3488 QFixed perItemWidth = glyphWidth / clusterLength;
3489 if (perItemWidth <= 0)
3490 return si->
position + clusterStart;
3491 QFixed left =
x > edge ? edge : edge - glyphWidth;
3494 int closestItem =
dist > (perItemWidth / 2) ?
n + 1 :
n;
3495 if (cursorOnCharacter && closestItem > 0)
3497 int pos = clusterStart + closestItem;
3512 if (!
attrs || oldPos <= 0 || oldPos >
len)
3516 while (oldPos && !
attrs[oldPos].graphemeBoundary)
3527 if (!
attrs || oldPos < 0 || oldPos >=
len)
3531 while (oldPos <
len && !
attrs[oldPos].graphemeBoundary)
3554 std::vector<int> insertionPoints;
3555 insertionPoints.reserve(
size_t(iterator.line.length));
3557 bool lastLine = lineNum >=
lines.
size() - 1;
3559 while (!iterator.atEnd()) {
3562 int end = iterator.itemEnd;
3563 if (lastLine && iterator.item == iterator.lastItem)
3566 for (
int i =
end - 1;
i >= iterator.itemStart; --
i)
3567 insertionPoints.push_back(
i);
3569 for (
int i = iterator.itemStart;
i <
end; ++
i)
3570 insertionPoints.push_back(
i);
3573 return insertionPoints;
3576int QTextEngine::endOfLine(
int lineNum)
3579 if (insertionPoints.size() > 0)
3580 return insertionPoints.back();
3584int QTextEngine::beginningOfLine(
int lineNum)
3587 if (insertionPoints.size() > 0)
3588 return insertionPoints.front();
3606 for (
size_t i = 0, max = insertionPoints.size();
i < max; ++
i)
3607 if (
pos == insertionPoints[
i]) {
3610 return insertionPoints[
i + 1];
3613 return insertionPoints[
i - 1];
3616 if (moveRight ^ alignRight) {
3618 return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1);
3622 return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);
3659 if (decorationList.isEmpty())
3662 for (
const ItemDecoration &
decoration : decorationList) {
3697 ItemDecorationList::iterator
it =
start;
3704 underlinePos =
qMax(underlinePos,
it->y);
3705 penWidth =
qMax(penWidth,
it->pen.widthF());
3709 underlinePos =
start->y;
3710 penWidth =
start->pen.widthF();
3712 lastLineEnd =
it->x2;
3720 ItemDecorationList::iterator
end,
3724 it->y = underlinePos;
3725 it->pen.setWidthF(penWidth);
3731 _layoutData(
string, _memory, MemSize)
3740 fontEngine(
font->
d->engineForScript(si.analysis.script))
3749 num_chars(numChars),
3771 ||
f->d->underline) {
3846 line(eng->lines[_lineNum]),
3850 firstItem(eng->findItem(
line.from)),
3851 lastItem(eng->findItem(lineEnd - 1, firstItem)),
3852 nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
3855 visualOrder(nItems),
3915 *selectionX = *selectionWidth = 0;
3936 int start_glyph = logClusters[from];
3943 for (
int g = end_glyph - 1;
g >= start_glyph; --
g)
3948 for (
int g = start_glyph;
g < end_glyph; ++
g)
3957 *selectionX =
x + soff + leftOffsetInLigature;
3958 *selectionWidth = swidth - leftOffsetInLigature;
static QAbstractTextDocumentLayoutPrivate * get(QAbstractTextDocumentLayout *layout)
virtual void resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
Sets the size of the inline object item corresponding to the text format.
QPaintDevice * paintDevice() const
Returns the paint device used to render the document's layout.
constexpr bool isLetterOrNumber() const noexcept
Returns true if the character is a letter or number (Letter_* or Number_* categories); otherwise retu...
static constexpr char32_t surrogateToUcs4(char16_t high, char16_t low) noexcept
Converts a UTF16 surrogate pair with the given high and low values to it's UCS-4-encoded code point.
@ ObjectReplacementCharacter
QChar toLower() const noexcept
Returns the lowercase equivalent if the character is uppercase or titlecase; otherwise returns the ch...
Direction
This enum type defines the Unicode direction attributes.
constexpr bool isLowSurrogate() const noexcept
Returns true if the QChar is the low part of a UTF16 surrogate (for example if its code point is in r...
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
bool isPrint() const noexcept
Returns true if the character is a printable character; otherwise returns false.
static constexpr char16_t lowSurrogate(char32_t ucs4) noexcept
Returns the low surrogate part of a UCS-4-encoded code point.
Category category() const noexcept
Returns the character's category.
constexpr bool isSpace() const noexcept
Returns true if the character is a separator character (Separator_* categories or certain code points...
constexpr bool isHighSurrogate() const noexcept
Returns true if the QChar is the high part of a UTF16 surrogate (for example if its code point is in ...
void ensureEngineAt(int at)
static QFontEngine * createMultiFontEngine(QFontEngine *fe, int script)
QFontEngine * engine(int at) const
virtual bool supportsHorizontalSubPixelPositions() const
virtual QFixed descent() const
virtual QFixed ascent() const
virtual QFontEngine * cloneWithSize(qreal) const
static bool scriptRequiresOpenType(QChar::Script script)
virtual glyph_t glyphIndex(uint ucs4) const =0
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
bool letterSpacingIsAbsolute
QHash< quint32, quint32 > features
QFontPrivate * smallCapsFontPrivate() const
QFontEngine * engineForScript(int script) const
QFont smallCapsFont() const
StyleStrategy styleStrategy() const
Returns the StyleStrategy.
void setPointSize(int)
Sets the point size to pointSize.
int pixelSize() const
Returns the pixel size of the font if it was set with setPixelSize().
qreal letterSpacing() const
QFont resolve(const QFont &) const
Returns a new QFont that has attributes copied from other that have not been previously set on this f...
Capitalization capitalization() const
qreal wordSpacing() const
int pointSize() const
Returns the point size of the font.
bool kerning() const
Returns true if kerning should be used when drawing text with this font.
void setPixelSize(int)
Sets the font size to pixelSize pixels, with a maxiumum size of an unsigned 16-bit integer.
virtual int type() const
Returns the type of an item as an int.
GraphicsItemFlags flags() const
Returns this item's flags.
static QInputMethod * inputMethod()
returns the input method.
qsizetype size() const noexcept
Returns the number of items in the hash.
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
constexpr qreal x1() const
Returns the x-coordinate of the line's start point.
constexpr qreal dx() const
Returns the horizontal component of the line's vector.
constexpr qreal dy() const
Returns the vertical component of the line's vector.
constexpr qreal y1() const
Returns the y-coordinate of the line's start point.
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
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.
const QPen & pen() const
Returns the painter's current pen.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawLine(const QLineF &line)
Draws a line defined by line.
\inmodule QtCore\reentrant
constexpr int x() const noexcept
Returns the x coordinate of this point.
qreal pixelSize() const
Returns the pixel size set for this QRawFont.
bool isValid() const
Returns true if the QRawFont is valid and false otherwise.
\inmodule QtCore\reentrant
constexpr int width() const noexcept
Returns the width of the rectangle.
iterator find(const T &value)
QStackTextEngine(const QString &string, const QFont &f)
bool isRightToLeft() const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
const QChar * constData() const
Returns a pointer to the data stored in the QString.
qsizetype size() const
Returns the number of characters in this string.
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QString & insert(qsizetype i, QChar c)
QChar * data()
Returns a pointer to the data stored in the QString.
QString & append(QChar c)
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
bool isRightToLeft() const
Returns true if the string is read right to left.
QString & prepend(QChar c)
qsizetype length() const
Returns the number of characters in this string.
const QChar * unicode() const
Returns a Unicode representation of the string.
void resize(qsizetype size)
Sets the size of the string to size characters.
int length() const
Returns the length of the block in characters.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
QTextCharFormat charFormat() const
Returns the QTextCharFormat that describes the block's character format.
VerticalAlignment
This enum describes the ways that adjacent characters can be vertically aligned.
UnderlineStyle underlineStyle() const
bool fontStrikeOut() const
Returns true if the text format's font is struck out (has a horizontal line drawn through it); otherw...
QFont::Capitalization fontCapitalization() const
bool fontOverline() const
Returns true if the text format's font is overlined; otherwise returns false.
QFont font() const
Returns the font for this character format.
MoveOperation
\value NoMove Keep the cursor where it is
QAbstractTextDocumentLayout * layout() const
static const QTextDocumentPrivate * get(const QTextDocument *document)
FragmentMap::ConstIterator FragmentIterator
QList< ItemDecoration > ItemDecorationList
glyph_metrics_t boundingBox(int from, int len) const
QList< QTextLayout::FormatRange > formats() const
void setPreeditArea(int position, const QString &text)
int lineNumberForTextPosition(int pos)
ItemDecorationList strikeOutList
void justify(const QScriptLine &si)
unsigned short * logClusters(const QScriptItem *si) const
ItemDecorationList underlineList
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
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
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos)
int length(int item) const
QTextFormatCollection * formatCollection() const
QAbstractTextDocumentLayout * docLayout() const
ItemDecorationList overlineList
QString elidedText(Qt::TextElideMode mode, QFixed width, int flags=0, int from=0, int count=-1) const
int indexForFormat(const QTextFormat &f)
QFont defaultFont() const
QTextCharFormat charFormat(int index) const
bool boolProperty(int propertyId) const
Returns the value of the property specified by propertyId.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
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
const T & at(qsizetype idx) const
void resize(qsizetype sz)
void insert(qsizetype i, T &&t)
const_iterator constEnd() const
const T * constData() const
auto constBegin() const -> const_iterator
void reserve(qsizetype sz)
iterator begin() noexcept
const QLoggingCategory & category()
[1]
QSet< QString >::iterator it
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
Combined button and popup list for selecting options.
Q_DECL_CONST_FUNCTION Q_CORE_EXPORT const Properties *QT_FASTCALL properties(char32_t ucs4) noexcept
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
#define QT_WARNING_DISABLE_GCC(text)
constexpr bool operator!=(const timespec &t1, const timespec &t2)
constexpr timespec operator*(const timespec &t1, int mul)
static const QCssKnownValue positions[NumKnownPositionModes - 1]
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
static struct AttrInfo attrs[]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Q_GUI_EXPORT int qt_defaultDpiY()
hb_unicode_funcs_t * hb_qt_get_unicode_funcs()
hb_script_t hb_qt_script_to_script(QChar::Script script)
hb_font_t * hb_qt_font_get_for_engine(QFontEngine *fe)
void hb_qt_font_set_use_design_metrics(hb_font_t *font, uint value)
struct hb_font_t hb_font_t
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
n void setPosition(void) \n\
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]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
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]
static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define QStringLiteral(str)
#define QT_BEGIN_INCLUDE_NAMESPACE
#define QT_END_INCLUDE_NAMESPACE
QTransform qt_true_matrix(qreal w, qreal h, const QTransform &x)
@ 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
static bool isRetainableControlCode(QChar c)
static bool prevCharJoins(const QString &string, int pos)
static QString stringMidRetainingBidiCC(const QString &string, const QString &ellidePrefix, const QString &ellideSuffix, int subStringFrom, int subStringTo, int midStart, int midLength)
static void applyVisibilityRules(ushort ucs, QGlyphLayout *glyphs, uint glyphPosition, QFontEngine *fontEngine)
static bool nextCharJoins(const QString &string, int pos)
static QT_BEGIN_NAMESPACE const float smallCapsFraction
static void releaseCachedFontEngine(QFontEngine *fontEngine)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
QFuture< QSet< QChar > > set
[10]
std::uniform_real_distribution dist(1, 2.5)
[2]
QItemSelection * selection
[0]
static constexpr QFixed fromReal(qreal r)
constexpr QFixed floor() const
static constexpr QFixed fromFixed(int fixed)
constexpr int value() const
constexpr int toInt() const
constexpr QFixed round() const
constexpr qreal toReal() const
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
\inmodule QtCore \reentrant
@ BidiResetToParagraphLevel
@ BidiMaybeResetToParagraphLevel
QChar::Direction bidiDirection
@ LineOrParagraphSeparator
unsigned short num_glyphs
void setDefaultHeight(QTextEngine *eng)
bool reallocate(int totalGlyphs)
unsigned short * logClustersPtr
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