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