diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp | 4 | ||||
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-khmer.c | 4 | ||||
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-myanmar.c | 6 | ||||
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-shaper.h | 19 | ||||
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-thai.c | 20 | ||||
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-tibetan.c | 4 | ||||
-rw-r--r-- | src/corelib/tools/qharfbuzz_p.h | 3 | ||||
-rw-r--r-- | src/corelib/tools/qtextboundaryfinder.cpp | 62 | ||||
-rw-r--r-- | src/corelib/tools/qunicodetools.cpp | 76 | ||||
-rw-r--r-- | src/corelib/tools/qunicodetools_p.h | 24 | ||||
-rw-r--r-- | src/gui/text/qharfbuzz_copy_p.h | 18 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 60 | ||||
-rw-r--r-- | src/gui/text/qtextengine_p.h | 6 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 25 |
14 files changed, 171 insertions, 160 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp index bbf479e774..0dcddc4f7d 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp +++ b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp @@ -1880,12 +1880,12 @@ void HB_IndicAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from while (i < len) { bool invalid; hb_uint32 boundary = indic_nextSyllableBoundary(script, text, from+i, end, &invalid) - from; - attributes[i].charStop = true; + attributes[i].graphemeBoundary = true; if (boundary > len-1) boundary = len; i++; while (i < boundary) { - attributes[i].charStop = false; + attributes[i].graphemeBoundary = false; ++uc; ++i; } diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-khmer.c b/src/3rdparty/harfbuzz/src/harfbuzz-khmer.c index 958069e866..1f3c7e2bce 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-khmer.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-khmer.c @@ -652,12 +652,12 @@ void HB_KhmerAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from HB_Bool invalid; hb_uint32 boundary = khmer_nextSyllableBoundary( text, from+i, end, &invalid ) - from; - attributes[i].charStop = TRUE; + attributes[i].graphemeBoundary = TRUE; if ( boundary > len-1 ) boundary = len; i++; while ( i < boundary ) { - attributes[i].charStop = FALSE; + attributes[i].graphemeBoundary = FALSE; ++uc; ++i; } diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-myanmar.c b/src/3rdparty/harfbuzz/src/harfbuzz-myanmar.c index 1327b185b0..b18b83054d 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-myanmar.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-myanmar.c @@ -520,14 +520,14 @@ void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 fr HB_Bool invalid; hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &invalid) - from; - attributes[i].charStop = TRUE; - attributes[i].lineBreakType = HB_Break; + attributes[i].graphemeBoundary = TRUE; + attributes[i].lineBreak = TRUE; if (boundary > len-1) boundary = len; i++; while (i < boundary) { - attributes[i].charStop = FALSE; + attributes[i].graphemeBoundary = FALSE; ++uc; ++i; } diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h index 6dfcdd20a7..2ff52eaf30 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h @@ -126,21 +126,14 @@ typedef struct hb_uint8 bidiLevel; } HB_ScriptItem; -typedef enum { - HB_NoBreak, - HB_SoftHyphen, - HB_Break, - HB_ForcedBreak -} HB_LineBreakType; - typedef struct { - /*HB_LineBreakType*/ hb_bitfield lineBreakType :2; - /*HB_Bool*/ hb_bitfield whiteSpace :1; /* A unicode whitespace character, except NBSP, ZWNBSP */ - /*HB_Bool*/ hb_bitfield charStop :1; /* Valid cursor position (for left/right arrow) */ - /*HB_Bool*/ hb_bitfield wordBoundary :1; - /*HB_Bool*/ hb_bitfield sentenceBoundary :1; - hb_bitfield unused :2; + hb_bitfield graphemeBoundary : 1; /* Valid cursor position (for left/right arrow) */ + hb_bitfield wordBreak : 1; + hb_bitfield sentenceBoundary : 1; + hb_bitfield lineBreak : 1; + hb_bitfield whiteSpace : 1; /* A unicode whitespace character */ + hb_bitfield unused : 3; } HB_CharAttributes; void HB_GetTailoredCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength, diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-thai.c b/src/3rdparty/harfbuzz/src/harfbuzz-thai.c index ecb722d984..70c1d57ff1 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-thai.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-thai.c @@ -395,8 +395,8 @@ static void HB_ThaiAssignAttributes(const HB_UChar16 *string, hb_uint32 len, HB_ to_tis620(string, len, cstr); for (i = 0; i < len; ++i) { - attributes[i].lineBreakType = HB_NoBreak; - attributes[i].wordBoundary = FALSE; + attributes[i].lineBreak = FALSE; + attributes[i].wordBreak = FALSE; } if (len > 128) { @@ -410,29 +410,29 @@ static void HB_ThaiAssignAttributes(const HB_UChar16 *string, hb_uint32 len, HB_ } if (break_positions) { - attributes[0].wordBoundary = TRUE; + attributes[0].wordBreak = TRUE; numbreaks = th_brk((const unsigned char *)cstr, break_positions, brp_size); for (i = 0; i < numbreaks; ++i) { - attributes[break_positions[i]].wordBoundary = TRUE; - attributes[break_positions[i]].lineBreakType = HB_Break; + attributes[break_positions[i]].wordBreak = TRUE; + attributes[break_positions[i]].lineBreak = TRUE; } if (break_positions != brp) free(break_positions); } - /* manage charStop */ + /* manage grapheme boundaries */ i = 0; while (i < len) { cell_length = th_next_cell((const unsigned char *)cstr + i, len - i, &tis_cell, true); - attributes[i].charStop = true; + attributes[i].graphemeBoundary = true; for (j = 1; j < cell_length; j++) - attributes[i + j].charStop = false; + attributes[i + j].graphemeBoundary = false; - /* Set charStop for SARA AM */ + /* Set graphemeBoundary for SARA AM */ if (cstr[i + cell_length - 1] == (char)0xd3) - attributes[i + cell_length - 1].charStop = true; + attributes[i + cell_length - 1].graphemeBoundary = true; i += cell_length; } diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-tibetan.c b/src/3rdparty/harfbuzz/src/harfbuzz-tibetan.c index e0c263d426..c3570974b3 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-tibetan.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-tibetan.c @@ -260,12 +260,12 @@ void HB_TibetanAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 fr HB_Bool invalid; hb_uint32 boundary = tibetan_nextSyllableBoundary(text, from+i, end, &invalid) - from; - attributes[i].charStop = TRUE; + attributes[i].graphemeBoundary = TRUE; if (boundary > len-1) boundary = len; i++; while (i < boundary) { - attributes[i].charStop = FALSE; + attributes[i].graphemeBoundary = FALSE; ++uc; ++i; } diff --git a/src/corelib/tools/qharfbuzz_p.h b/src/corelib/tools/qharfbuzz_p.h index 23de3efa16..72d5bda77f 100644 --- a/src/corelib/tools/qharfbuzz_p.h +++ b/src/corelib/tools/qharfbuzz_p.h @@ -65,9 +65,6 @@ Q_CORE_EXPORT HB_Face qHBNewFace(void *font, HB_GetFontTableFunc tableFunc); Q_CORE_EXPORT void qHBFreeFace(HB_Face); Q_CORE_EXPORT HB_Face qHBLoadFace(HB_Face face); -Q_DECLARE_TYPEINFO(HB_CharAttributes, Q_PRIMITIVE_TYPE); -Q_DECLARE_TYPEINFO(HB_ScriptItem, Q_PRIMITIVE_TYPE); - Q_DECLARE_TYPEINFO(HB_GlyphAttributes, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(HB_FixedPoint, Q_PRIMITIVE_TYPE); diff --git a/src/corelib/tools/qtextboundaryfinder.cpp b/src/corelib/tools/qtextboundaryfinder.cpp index c3d44da042..f928932548 100644 --- a/src/corelib/tools/qtextboundaryfinder.cpp +++ b/src/corelib/tools/qtextboundaryfinder.cpp @@ -49,12 +49,12 @@ QT_BEGIN_NAMESPACE class QTextBoundaryFinderPrivate { public: - HB_CharAttributes attributes[1]; + QCharAttributes attributes[1]; }; -static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int length, HB_CharAttributes *attributes) +static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int length, QCharAttributes *attributes) { - QVarLengthArray<HB_ScriptItem> scriptItems; + QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems; const ushort *string = reinterpret_cast<const ushort *>(chars); const ushort *unicode = string; @@ -72,11 +72,9 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int script = QUnicodeTables::Common; if (script != lastScript) { if (uc != start) { - HB_ScriptItem item; - item.pos = start - string; - item.length = uc - start; - item.script = (HB_Script)lastScript; - item.bidiLevel = 0; // ### what's the proper value? + QUnicodeTools::ScriptItem item; + item.position = start - string; + item.script = lastScript; scriptItems.append(item); start = uc; } @@ -85,11 +83,9 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int ++uc; } if (uc != start) { - HB_ScriptItem item; - item.pos = start - string; - item.length = uc - start; - item.script = (HB_Script)lastScript; - item.bidiLevel = 0; // ### what's the proper value? + QUnicodeTools::ScriptItem item; + item.position = start - string; + item.script = lastScript; scriptItems.append(item); } @@ -193,9 +189,9 @@ QTextBoundaryFinder::QTextBoundaryFinder(const QTextBoundaryFinder &other) , pos(other.pos) , freePrivate(true) { - d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes)); + d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(QCharAttributes)); Q_CHECK_PTR(d); - memcpy(d, other.d, length*sizeof(HB_CharAttributes)); + memcpy(d, other.d, length*sizeof(QCharAttributes)); } /*! @@ -213,11 +209,11 @@ QTextBoundaryFinder &QTextBoundaryFinder::operator=(const QTextBoundaryFinder &o pos = other.pos; QTextBoundaryFinderPrivate *newD = (QTextBoundaryFinderPrivate *) - realloc(freePrivate ? d : 0, length*sizeof(HB_CharAttributes)); + realloc(freePrivate ? d : 0, length*sizeof(QCharAttributes)); Q_CHECK_PTR(newD); freePrivate = true; d = newD; - memcpy(d, other.d, length*sizeof(HB_CharAttributes)); + memcpy(d, other.d, length*sizeof(QCharAttributes)); return *this; } @@ -242,7 +238,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QString &strin , pos(0) , freePrivate(true) { - d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes)); + d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(QCharAttributes)); Q_CHECK_PTR(d); init(t, chars, length, d->attributes); } @@ -266,11 +262,11 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QChar *chars, , length(length) , pos(0) { - if (buffer && (uint)bufferSize >= length*sizeof(HB_CharAttributes)) { + if (buffer && (uint)bufferSize >= length*sizeof(QCharAttributes)) { d = (QTextBoundaryFinderPrivate *)buffer; freePrivate = false; } else { - d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes)); + d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(QCharAttributes)); Q_CHECK_PTR(d); freePrivate = true; } @@ -368,11 +364,11 @@ int QTextBoundaryFinder::toNextBoundary() switch(t) { case Grapheme: - while (pos < length && !d->attributes[pos].charStop) + while (pos < length && !d->attributes[pos].graphemeBoundary) ++pos; break; case Word: - while (pos < length && !d->attributes[pos].wordBoundary) + while (pos < length && !d->attributes[pos].wordBreak) ++pos; break; case Sentence: @@ -380,7 +376,7 @@ int QTextBoundaryFinder::toNextBoundary() ++pos; break; case Line: - while (pos < length && d->attributes[pos].lineBreakType == HB_NoBreak) + while (pos < length && !d->attributes[pos].lineBreak) ++pos; break; } @@ -410,11 +406,11 @@ int QTextBoundaryFinder::toPreviousBoundary() switch(t) { case Grapheme: - while (pos > 0 && !d->attributes[pos].charStop) + while (pos > 0 && !d->attributes[pos].graphemeBoundary) --pos; break; case Word: - while (pos > 0 && !d->attributes[pos].wordBoundary) + while (pos > 0 && !d->attributes[pos].wordBreak) --pos; break; case Sentence: @@ -422,7 +418,7 @@ int QTextBoundaryFinder::toPreviousBoundary() --pos; break; case Line: - while (pos > 0 && d->attributes[pos].lineBreakType == HB_NoBreak) + while (pos > 0 && !d->attributes[pos].lineBreak) --pos; break; } @@ -443,11 +439,11 @@ bool QTextBoundaryFinder::isAtBoundary() const switch(t) { case Grapheme: - return d->attributes[pos].charStop; + return d->attributes[pos].graphemeBoundary; case Word: - return d->attributes[pos].wordBoundary; + return d->attributes[pos].wordBreak; case Line: - return pos == 0 || d->attributes[pos].lineBreakType != HB_NoBreak; + return pos == 0 || d->attributes[pos].lineBreak; case Sentence: return d->attributes[pos].sentenceBoundary; } @@ -463,8 +459,6 @@ QTextBoundaryFinder::BoundaryReasons QTextBoundaryFinder::boundaryReasons() cons return NotAtBoundary; if (! isAtBoundary()) return NotAtBoundary; - if (t == Line && pos < length && d->attributes[pos].lineBreakType == HB_SoftHyphen) - return SoftHyphen; if (pos == 0) { if (d->attributes[pos].whiteSpace) return NotAtBoundary; @@ -476,6 +470,12 @@ QTextBoundaryFinder::BoundaryReasons QTextBoundaryFinder::boundaryReasons() cons return EndWord; } + if (t == Line && chars[pos - 1].unicode() == QChar::SoftHyphen) + return SoftHyphen; + + if (t != Word) + return BoundaryReasons(StartWord | EndWord); + const bool nextIsSpace = d->attributes[pos].whiteSpace; const bool prevIsSpace = d->attributes[pos - 1].whiteSpace; diff --git a/src/corelib/tools/qunicodetools.cpp b/src/corelib/tools/qunicodetools.cpp index f8db6cbac3..ffb9512229 100644 --- a/src/corelib/tools/qunicodetools.cpp +++ b/src/corelib/tools/qunicodetools.cpp @@ -42,6 +42,9 @@ #include "qunicodetools_p.h" #include "qunicodetables_p.h" +#include "qvarlengtharray.h" + +#include <harfbuzz-shaper.h> #define FLAG(x) (1 << (x)) @@ -77,7 +80,7 @@ static const uchar breakTable[QUnicodeTables::GraphemeBreak_LVT + 1][QUnicodeTab } // namespace GB -static void getGraphemeBreaks(const ushort *string, quint32 len, HB_CharAttributes *attributes) +static void getGraphemeBreaks(const ushort *string, quint32 len, QCharAttributes *attributes) { QUnicodeTables::GraphemeBreakClass lcls = QUnicodeTables::GraphemeBreak_LF; // to meet GB1 for (quint32 i = 0; i != len; ++i) { @@ -94,7 +97,8 @@ static void getGraphemeBreaks(const ushort *string, quint32 len, HB_CharAttribut const QUnicodeTables::Properties *prop = QUnicodeTables::properties(ucs4); QUnicodeTables::GraphemeBreakClass cls = (QUnicodeTables::GraphemeBreakClass) prop->graphemeBreakClass; - attributes[pos].charStop = GB::breakTable[lcls][cls]; + if (Q_LIKELY(GB::breakTable[lcls][cls])) + attributes[pos].graphemeBoundary = true; lcls = cls; } @@ -127,7 +131,7 @@ static const uchar breakTable[QUnicodeTables::WordBreak_ExtendNumLet + 1][QUnico } // namespace WB -static void getWordBreaks(const ushort *string, quint32 len, HB_CharAttributes *attributes) +static void getWordBreaks(const ushort *string, quint32 len, QCharAttributes *attributes) { QUnicodeTables::WordBreakClass cls = QUnicodeTables::WordBreak_LF; // to meet WB1 for (quint32 i = 0; i != len; ++i) { @@ -175,7 +179,7 @@ static void getWordBreaks(const ushort *string, quint32 len, HB_CharAttributes * } cls = ncls; if (action == WB::Break) - attributes[pos].wordBoundary = true; + attributes[pos].wordBreak = true; } } @@ -217,7 +221,7 @@ static const uchar breakTable[BAfter + 1][QUnicodeTables::SentenceBreak_Close + } // namespace SB -static void getSentenceBreaks(const ushort *string, quint32 len, HB_CharAttributes *attributes) +static void getSentenceBreaks(const ushort *string, quint32 len, QCharAttributes *attributes) { uchar state = SB::BAfter; // to meet SB1 for (quint32 i = 0; i != len; ++i) { @@ -402,12 +406,11 @@ static const uchar breakTable[QUnicodeTables::LineBreak_CB + 1][QUnicodeTables:: } // namespace LB -static void getLineBreaks(const ushort *string, quint32 len, HB_CharAttributes *attributes) +static void getLineBreaks(const ushort *string, quint32 len, QCharAttributes *attributes) { quint32 nestart = 0; LB::NS::Class nelast = LB::NS::XX; - uint lucs4 = 0; QUnicodeTables::LineBreakClass lcls = QUnicodeTables::LineBreak_LF; // to meet LB10 QUnicodeTables::LineBreakClass cls = lcls; for (quint32 i = 0; i != len; ++i) { @@ -443,7 +446,7 @@ static void getLineBreaks(const ushort *string, quint32 len, HB_CharAttributes * case LB::NS::Break: // do not change breaks before and after the expression for (quint32 j = nestart + 1; j < pos; ++j) - attributes[j].lineBreakType = HB_NoBreak; + attributes[j].lineBreak = false; // fall through case LB::NS::None: nelast = LB::NS::XX; // reset state @@ -457,12 +460,10 @@ static void getLineBreaks(const ushort *string, quint32 len, HB_CharAttributes * } } - HB_LineBreakType lineBreakType = HB_NoBreak; - if (Q_UNLIKELY(lcls >= QUnicodeTables::LineBreak_CR)) { // LB4: BK!, LB5: (CRxLF|CR|LF|NL)! if (lcls > QUnicodeTables::LineBreak_CR || ncls != QUnicodeTables::LineBreak_LF) - lineBreakType = HB_ForcedBreak; + attributes[pos].lineBreak = true; goto next; } @@ -479,18 +480,16 @@ static void getLineBreaks(const ushort *string, quint32 len, HB_CharAttributes * switch (LB::breakTable[cls][ncls < QUnicodeTables::LineBreak_SA ? ncls : QUnicodeTables::LineBreak_AL]) { case LB::DirectBreak: - lineBreakType = HB_Break; - if (lucs4 == QChar::SoftHyphen) - lineBreakType = HB_SoftHyphen; + attributes[pos].lineBreak = true; break; case LB::IndirectBreak: if (lcls == QUnicodeTables::LineBreak_SP) - lineBreakType = HB_Break; + attributes[pos].lineBreak = true; break; case LB::CombiningIndirectBreak: if (lcls != QUnicodeTables::LineBreak_SP) goto next_no_cls_update; - lineBreakType = HB_Break; + attributes[pos].lineBreak = true; break; case LB::CombiningProhibitedBreak: if (lcls != QUnicodeTables::LineBreak_SP) @@ -504,24 +503,21 @@ static void getLineBreaks(const ushort *string, quint32 len, HB_CharAttributes * next: cls = ncls; - lucs4 = ucs4; next_no_cls_update: lcls = ncls; - if (Q_LIKELY(lineBreakType != HB_NoBreak)) - attributes[pos].lineBreakType = lineBreakType; } if (Q_UNLIKELY(LB::NS::actionTable[nelast][LB::NS::XX] == LB::NS::Break)) { // LB25: do not break lines inside numbers for (quint32 j = nestart + 1; j < len; ++j) - attributes[j].lineBreakType = HB_NoBreak; + attributes[j].lineBreak = false; } - attributes[0].lineBreakType = HB_NoBreak; // LB2 + attributes[0].lineBreak = false; // LB2 } -static void getWhiteSpaces(const ushort *string, quint32 len, HB_CharAttributes *attributes) +static void getWhiteSpaces(const ushort *string, quint32 len, QCharAttributes *attributes) { for (quint32 i = 0; i != len; ++i) { uint ucs4 = string[i]; @@ -540,14 +536,14 @@ static void getWhiteSpaces(const ushort *string, quint32 len, HB_CharAttributes Q_CORE_EXPORT void initCharAttributes(const ushort *string, int length, - const HB_ScriptItem *items, int numItems, - HB_CharAttributes *attributes, CharAttributeOptions options) + const ScriptItem *items, int numItems, + QCharAttributes *attributes, CharAttributeOptions options) { if (length <= 0) return; if (!(options & DontClearAttributes)) - ::memset(attributes, 0, length * sizeof(HB_CharAttributes)); + ::memset(attributes, 0, length * sizeof(QCharAttributes)); if (options & GraphemeBreaks) getGraphemeBreaks(string, length, attributes); @@ -562,8 +558,34 @@ Q_CORE_EXPORT void initCharAttributes(const ushort *string, int length, if (!items || numItems <= 0) return; - if (!qt_initcharattributes_default_algorithm_only) - HB_GetTailoredCharAttributes(string, length, items, numItems, attributes); + if (!qt_initcharattributes_default_algorithm_only) { + QVarLengthArray<HB_ScriptItem, 64> scriptItems; + scriptItems.reserve(numItems); + int start = 0; + for (int i = start + 1; i < numItems; ++i) { + if (items[i].script == items[start].script) + continue; + HB_ScriptItem item; + item.pos = items[start].position; + item.length = items[i].position - items[start].position; + item.script = (HB_Script)items[start].script; + item.bidiLevel = 0; // unused + scriptItems.append(item); + start = i; + } + if (items[start].position + 1 < length) { + HB_ScriptItem item; + item.pos = items[start].position; + item.length = length - items[start].position; + item.script = (HB_Script)items[start].script; + item.bidiLevel = 0; // unused + scriptItems.append(item); + } + Q_STATIC_ASSERT(sizeof(QCharAttributes) == sizeof(HB_CharAttributes)); + HB_GetTailoredCharAttributes(string, length, + scriptItems.constData(), scriptItems.size(), + reinterpret_cast<HB_CharAttributes *>(attributes)); + } } } // namespace QUnicodeTools diff --git a/src/corelib/tools/qunicodetools_p.h b/src/corelib/tools/qunicodetools_p.h index ea407e7ddc..3396c33230 100644 --- a/src/corelib/tools/qunicodetools_p.h +++ b/src/corelib/tools/qunicodetools_p.h @@ -53,12 +53,30 @@ // We mean it. // -#include <private/qharfbuzz_p.h> +#include <QtCore/qchar.h> QT_BEGIN_NAMESPACE +struct Q_PACKED QCharAttributes +{ + uchar graphemeBoundary : 1; + uchar wordBreak : 1; + uchar sentenceBoundary : 1; + uchar lineBreak : 1; + uchar whiteSpace : 1; + uchar unused : 3; +}; +Q_DECLARE_TYPEINFO(QCharAttributes, Q_PRIMITIVE_TYPE); + namespace QUnicodeTools { +// ### temporary +struct ScriptItem +{ + int position; + int script; +}; + enum CharAttributeOption { GraphemeBreaks = 0x01, WordBreaks = 0x02, @@ -72,8 +90,8 @@ enum CharAttributeOption { Q_DECLARE_FLAGS(CharAttributeOptions, CharAttributeOption) Q_CORE_EXPORT void initCharAttributes(const ushort *string, int length, - const HB_ScriptItem *items, int numItems, - HB_CharAttributes *attributes, CharAttributeOptions options = DefaultOptionsCompat); + const ScriptItem *items, int numItems, + QCharAttributes *attributes, CharAttributeOptions options = DefaultOptionsCompat); } // namespace QUnicodeTools diff --git a/src/gui/text/qharfbuzz_copy_p.h b/src/gui/text/qharfbuzz_copy_p.h index aa48667e2e..75b1240c3d 100644 --- a/src/gui/text/qharfbuzz_copy_p.h +++ b/src/gui/text/qharfbuzz_copy_p.h @@ -66,13 +66,6 @@ typedef enum { HB_Err_Out_Of_Memory = 0xDEAD } HB_Error; -typedef enum { - HB_NoBreak, - HB_SoftHyphen, - HB_Break, - HB_ForcedBreak -} HB_LineBreakType; - typedef QT_PREPEND_NAMESPACE(quint32) HB_Glyph; typedef void * HB_Font; typedef void * HB_Face; @@ -95,17 +88,6 @@ typedef struct { hb_bitfield combiningClass :8; } HB_GlyphAttributes; -// This struct is strictly not needed, but we replicate it completely in -// case the compiler tries to get clever with padding. -typedef struct { - /*HB_LineBreakType*/ hb_bitfield lineBreakType :2; - /*HB_Bool*/ hb_bitfield whiteSpace :1; /* A unicode whitespace character, except NBSP, ZWNBSP */ - /*HB_Bool*/ hb_bitfield charStop :1; /* Valid cursor position (for left/right arrow) */ - /*HB_Bool*/ hb_bitfield wordBoundary :1; - /*HB_Bool*/ hb_bitfield sentenceBoundary :1; - hb_bitfield unused :2; -} HB_CharAttributes; - } #endif // ifdef QT_BUILD_GUI_LIB diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index e4572e77a2..b2f760029e 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -52,7 +52,6 @@ #include "qfontengine_p.h" #include "qstring.h" #include <private/qunicodetables_p.h> -#include <private/qunicodetools_p.h> #include "qtextdocument_p.h" #include "qrawfont.h" #include "qrawfont_p.h" @@ -1198,33 +1197,30 @@ QTextEngine::~QTextEngine() resetFontEngineCache(); } -const HB_CharAttributes *QTextEngine::attributes() const +const QCharAttributes *QTextEngine::attributes() const { if (layoutData && layoutData->haveCharAttributes) - return (HB_CharAttributes *) layoutData->memory; + return (QCharAttributes *) layoutData->memory; itemize(); if (! ensureSpace(layoutData->string.length())) return NULL; - QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size()); - + QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size()); for (int i = 0; i < layoutData->items.size(); ++i) { const QScriptItem &si = layoutData->items[i]; - hbScriptItems[i].pos = si.position; - hbScriptItems[i].length = length(i); - hbScriptItems[i].bidiLevel = si.analysis.bidiLevel; - hbScriptItems[i].script = (HB_Script)si.analysis.script; + scriptItems[i].position = si.position; + scriptItems[i].script = si.analysis.script; } QUnicodeTools::initCharAttributes(reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData()), layoutData->string.length(), - hbScriptItems.data(), hbScriptItems.size(), - (HB_CharAttributes *)layoutData->memory); + scriptItems.data(), scriptItems.size(), + (QCharAttributes *)layoutData->memory); layoutData->haveCharAttributes = true; - return (HB_CharAttributes *) layoutData->memory; + return (QCharAttributes *) layoutData->memory; } void QTextEngine::shape(int item) const @@ -1858,7 +1854,7 @@ void QTextEngine::justify(const QScriptLine &line) // don't include trailing white spaces when doing justification int line_length = line.length; - const HB_CharAttributes *a = attributes(); + const QCharAttributes *a = attributes(); if (! a) return; a += line.from; @@ -2058,7 +2054,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int { allocated = _allocated; - int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1; + int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1; int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::spaceNeededForGlyphLayout(1); @@ -2100,7 +2096,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs) return true; } - int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1; + int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1; int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2; @@ -2371,7 +2367,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (flags & Qt::TextShowMnemonic) { itemize(); - HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes()); + QCharAttributes *attributes = const_cast<QCharAttributes *>(this->attributes()); if (!attributes) return QString(); for (int i = 0; i < layoutData->items.size(); ++i) { @@ -2387,9 +2383,9 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (layoutData->string.at(i) == QLatin1Char('&')) { const int gp = logClusters[i - si.position]; glyphs.attributes[gp].dontPrint = true; - attributes[i + 1].charStop = false; + attributes[i + 1].graphemeBoundary = false; + attributes[i + 1].lineBreak = false; attributes[i + 1].whiteSpace = false; - attributes[i + 1].lineBreakType = HB_NoBreak; if (layoutData->string.at(i + 1) == QLatin1Char('&')) ++i; } @@ -2451,7 +2447,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (availableWidth < 0) return QString(); - const HB_CharAttributes *attributes = this->attributes(); + const QCharAttributes *attributes = this->attributes(); if (!attributes) return QString(); @@ -2464,7 +2460,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int pos = nextBreak; ++nextBreak; - while (nextBreak < layoutData->string.length() && !attributes[nextBreak].charStop) + while (nextBreak < layoutData->string.length() && !attributes[nextBreak].graphemeBoundary) ++nextBreak; currentWidth += this->width(pos, nextBreak - pos); @@ -2487,7 +2483,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int pos = nextBreak; --nextBreak; - while (nextBreak > 0 && !attributes[nextBreak].charStop) + while (nextBreak > 0 && !attributes[nextBreak].graphemeBoundary) --nextBreak; currentWidth += this->width(nextBreak, pos - nextBreak); @@ -2516,11 +2512,11 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int rightPos = nextRightBreak; ++nextLeftBreak; - while (nextLeftBreak < layoutData->string.length() && !attributes[nextLeftBreak].charStop) + while (nextLeftBreak < layoutData->string.length() && !attributes[nextLeftBreak].graphemeBoundary) ++nextLeftBreak; --nextRightBreak; - while (nextRightBreak > from && !attributes[nextRightBreak].charStop) + while (nextRightBreak > from && !attributes[nextRightBreak].graphemeBoundary) --nextRightBreak; leftWidth += this->width(leftPos, nextLeftBreak - leftPos); @@ -2833,12 +2829,12 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in // Scan in logClusters[from..to-1] for glyph_pos int QTextEngine::getClusterLength(unsigned short *logClusters, - const HB_CharAttributes *attributes, + const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start) { int clusterLength = 0; for (int i = from; i < to; i++) { - if (logClusters[i] == glyph_pos && attributes[i].charStop) { + if (logClusters[i] == glyph_pos && attributes[i].graphemeBoundary) { if (*start < 0) *start = i; clusterLength++; @@ -2877,7 +2873,7 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, glyph_pos--; } - const HB_CharAttributes *attrs = attributes(); + const QCharAttributes *attrs = attributes(); logClusters = this->logClusters(si); clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart); @@ -2895,8 +2891,8 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, if (cursorOnCharacter && closestItem > 0) closestItem--; int pos = si->position + clusterStart + closestItem; - // Jump to the next charStop - while (pos < end && !attrs[pos].charStop) + // Jump to the next grapheme boundary + while (pos < end && !attrs[pos].graphemeBoundary) pos++; return pos; } @@ -2905,21 +2901,21 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, int QTextEngine::previousLogicalPosition(int oldPos) const { - const HB_CharAttributes *attrs = attributes(); + const QCharAttributes *attrs = attributes(); if (!attrs || oldPos < 0) return oldPos; if (oldPos <= 0) return 0; oldPos--; - while (oldPos && !attrs[oldPos].charStop) + while (oldPos && !attrs[oldPos].graphemeBoundary) oldPos--; return oldPos; } int QTextEngine::nextLogicalPosition(int oldPos) const { - const HB_CharAttributes *attrs = attributes(); + const QCharAttributes *attrs = attributes(); int len = block.isValid() ? block.length() - 1 : layoutData->string.length(); Q_ASSERT(len <= layoutData->string.length()); @@ -2927,7 +2923,7 @@ int QTextEngine::nextLogicalPosition(int oldPos) const return oldPos; oldPos++; - while (oldPos < len && !attrs[oldPos].charStop) + while (oldPos < len && !attrs[oldPos].graphemeBoundary) oldPos++; return oldPos; } diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index c2362e6dc5..ac4bc273c0 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -75,6 +75,8 @@ #include "private/qfixed_p.h" +#include <private/qunicodetools_p.h> + #include <stdlib.h> QT_BEGIN_NAMESPACE @@ -468,7 +470,7 @@ public: bool isRightToLeft() const; static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder); - const HB_CharAttributes *attributes() const; + const QCharAttributes *attributes() const; void shape(int item) const; @@ -672,7 +674,7 @@ private: void resolveAdditionalFormats() const; int endOfLine(int lineNum); int beginningOfLine(int lineNum); - int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start); + int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start); }; class Q_GUI_EXPORT QStackTextEngine : public QTextEngine { diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index a49b4112d4..7591b46547 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -683,7 +683,7 @@ void QTextLayout::clearLayout() */ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const { - const HB_CharAttributes *attributes = d->attributes(); + const QCharAttributes *attributes = d->attributes(); int len = d->block.isValid() ? d->block.length() - 1 : d->layoutData->string.length(); Q_ASSERT(len <= d->layoutData->string.length()); @@ -692,7 +692,7 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const if (mode == SkipCharacters) { oldPos++; - while (oldPos < len && !attributes[oldPos].charStop) + while (oldPos < len && !attributes[oldPos].graphemeBoundary) oldPos++; } else { if (oldPos < len && d->atWordSeparator(oldPos)) { @@ -719,13 +719,13 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const */ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const { - const HB_CharAttributes *attributes = d->attributes(); + const QCharAttributes *attributes = d->attributes(); if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length()) return oldPos; if (mode == SkipCharacters) { oldPos--; - while (oldPos && !attributes[oldPos].charStop) + while (oldPos && !attributes[oldPos].graphemeBoundary) oldPos--; } else { while (oldPos && d->atSpace(oldPos-1)) @@ -789,10 +789,10 @@ int QTextLayout::leftCursorPosition(int oldPos) const */ bool QTextLayout::isValidCursorPosition(int pos) const { - const HB_CharAttributes *attributes = d->attributes(); + const QCharAttributes *attributes = d->attributes(); if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length()) return false; - return attributes[pos].charStop; + return attributes[pos].graphemeBoundary; } /*! @@ -1770,7 +1770,7 @@ void QTextLine::layout_helper(int maxGlyphs) Qt::Alignment alignment = eng->option.alignment(); - const HB_CharAttributes *attributes = eng->attributes(); + const QCharAttributes *attributes = eng->attributes(); if (!attributes) return; lbh.currentPosition = line.from; @@ -1875,17 +1875,18 @@ void QTextLine::layout_helper(int maxGlyphs) if (lbh.currentPosition >= eng->layoutData->string.length() || attributes[lbh.currentPosition].whiteSpace - || attributes[lbh.currentPosition].lineBreakType != HB_NoBreak) { + || attributes[lbh.currentPosition].lineBreak) { sb_or_ws = true; break; - } else if (breakany && attributes[lbh.currentPosition].charStop) { + } else if (breakany && attributes[lbh.currentPosition].graphemeBoundary) { break; } } while (lbh.currentPosition < end); lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); if (lbh.currentPosition > 0 && lbh.currentPosition < end - && attributes[lbh.currentPosition].lineBreakType == HB_SoftHyphen) { + && attributes[lbh.currentPosition].lineBreak + && eng->layoutData->string.at(lbh.currentPosition - 1).unicode() == QChar::SoftHyphen) { // if we are splitting up a word because of // a soft hyphen then we ... // @@ -2605,12 +2606,12 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const int lineEnd = line.from + line.length + line.trailingSpaces; int pos = *cursorPos; int itm; - const HB_CharAttributes *attributes = eng->attributes(); + const QCharAttributes *attributes = eng->attributes(); if (!attributes) { *cursorPos = 0; return x.toReal(); } - while (pos < lineEnd && !attributes[pos].charStop) + while (pos < lineEnd && !attributes[pos].graphemeBoundary) pos++; if (pos == lineEnd) { // end of line ensure we have the last item on the line |