Introduce QCharAttributes and use it instead of HB_CharAttributes everywhere in Qt
(in Harfbuzz, the HB_CharAttributes is only used in the text segmentation algorithm
which has been moved from HB to Qt (well, most of it)).
Rename some members to better reflect their meaning,
remember to keep HB_CharAttributes in sync with QCharAttributes.
Also replace HB_ScriptItem with a (temporary) QUnicodeTools::ScriptItem struct
that will be replaced with a more efficient/friendly solution a bit later.
The soft hyphen and the mandatory break detection has been factored out
of the default text breaking algorithm to a higher level in order to refactor
the QCharAttributes bitfields and to optimize the implementation for the common case.
Change-Id: Ieb365623ae954430f1c8b2dfcd65c82973143eec
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
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;
}
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;
}
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;
}
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,
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) {
}
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;
}
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;
}
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);
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;
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;
}
++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);
}
, 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));
}
/*!
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;
}
, 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);
}
, 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;
}
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:
++pos;
break;
case Line:
- while (pos < length && d->attributes[pos].lineBreakType == HB_NoBreak)
+ while (pos < length && !d->attributes[pos].lineBreak)
++pos;
break;
}
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:
--pos;
break;
case Line:
- while (pos > 0 && d->attributes[pos].lineBreakType == HB_NoBreak)
+ while (pos > 0 && !d->attributes[pos].lineBreak)
--pos;
break;
}
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;
}
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;
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;
#include "qunicodetools_p.h"
#include "qunicodetables_p.h"
+#include "qvarlengtharray.h"
+
+#include <harfbuzz-shaper.h>
#define FLAG(x) (1 << (x))
} // 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) {
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;
}
} // 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) {
}
cls = ncls;
if (action == WB::Break)
- attributes[pos].wordBoundary = true;
+ attributes[pos].wordBreak = true;
}
}
} // 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) {
} // 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) {
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
}
}
- 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;
}
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)
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];
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);
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
// 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,
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
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;
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
#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"
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
// 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;
{
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);
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;
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) {
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;
}
if (availableWidth < 0)
return QString();
- const HB_CharAttributes *attributes = this->attributes();
+ const QCharAttributes *attributes = this->attributes();
if (!attributes)
return QString();
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);
pos = nextBreak;
--nextBreak;
- while (nextBreak > 0 && !attributes[nextBreak].charStop)
+ while (nextBreak > 0 && !attributes[nextBreak].graphemeBoundary)
--nextBreak;
currentWidth += this->width(nextBreak, pos - nextBreak);
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);
// 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++;
glyph_pos--;
}
- const HB_CharAttributes *attrs = attributes();
+ const QCharAttributes *attrs = attributes();
logClusters = this->logClusters(si);
clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart);
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;
}
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());
return oldPos;
oldPos++;
- while (oldPos < len && !attrs[oldPos].charStop)
+ while (oldPos < len && !attrs[oldPos].graphemeBoundary)
oldPos++;
return oldPos;
}
#include "private/qfixed_p.h"
+#include <private/qunicodetools_p.h>
+
#include <stdlib.h>
QT_BEGIN_NAMESPACE
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;
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 {
*/
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());
if (mode == SkipCharacters) {
oldPos++;
- while (oldPos < len && !attributes[oldPos].charStop)
+ while (oldPos < len && !attributes[oldPos].graphemeBoundary)
oldPos++;
} else {
if (oldPos < len && d->atWordSeparator(oldPos)) {
*/
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))
*/
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;
}
/*!
Qt::Alignment alignment = eng->option.alignment();
- const HB_CharAttributes *attributes = eng->attributes();
+ const QCharAttributes *attributes = eng->attributes();
if (!attributes)
return;
lbh.currentPosition = line.from;
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 ...
//
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
void charWordStopOnLineSeparator();
void xToCursorAtEndOfLine();
void boundingRectTopLeft();
- void charStopForSurrogatePairs();
+ void graphemeBoundaryForSurrogatePairs();
void tabStops();
void integerOverflow();
void testDefaultTabs();
while (b->utf8) {
QString str = QString::fromUtf8(b->utf8);
QTextEngine engine(str, QFont());
- const HB_CharAttributes *attrs = engine.attributes();
- QVERIFY(attrs[0].lineBreakType == HB_NoBreak);
+ const QCharAttributes *attrs = engine.attributes();
+ QVERIFY(!attrs[0].lineBreak);
int i;
for (i = 0; i < (int)str.length() - 1; ++i) {
QVERIFY(b->breaks[i] != 0xff);
- if ( (attrs[i + 1].lineBreakType != HB_NoBreak) != (bool)b->breaks[i] ) {
- qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i + 1].lineBreakType);
- QCOMPARE( (attrs[i + 1].lineBreakType != HB_NoBreak), (bool)b->breaks[i] );
+ if ( attrs[i + 1].lineBreak != (bool)b->breaks[i] ) {
+ qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i + 1].lineBreak);
+ QCOMPARE( attrs[i + 1].lineBreak, (bool)b->breaks[i] );
}
}
QCOMPARE(b->breaks[i], (uchar)0xff);
txt.append(lineSeparator);
QTextLayout layout(txt, testFont);
QTextEngine *engine = layout.engine();
- const HB_CharAttributes *attrs = engine->attributes();
+ const QCharAttributes *attrs = engine->attributes();
QVERIFY(attrs);
- QVERIFY(attrs[1].charStop);
+ QVERIFY(attrs[1].graphemeBoundary);
}
void tst_QTextLayout::xToCursorAtEndOfLine()
QCOMPARE(layout.boundingRect().topLeft(), firstLine.position());
}
-void tst_QTextLayout::charStopForSurrogatePairs()
+void tst_QTextLayout::graphemeBoundaryForSurrogatePairs()
{
QString txt;
txt.append("a");
txt.append("b");
QTextLayout layout(txt, testFont);
QTextEngine *engine = layout.engine();
- const HB_CharAttributes *attrs = engine->attributes();
+ const QCharAttributes *attrs = engine->attributes();
QVERIFY(attrs);
- QVERIFY(attrs[0].charStop);
- QVERIFY(attrs[1].charStop);
- QVERIFY(!attrs[2].charStop);
- QVERIFY(attrs[3].charStop);
+ QVERIFY(attrs[0].graphemeBoundary);
+ QVERIFY(attrs[1].graphemeBoundary);
+ QVERIFY(!attrs[2].graphemeBoundary);
+ QVERIFY(attrs[3].graphemeBoundary);
}
void tst_QTextLayout::tabStops()