summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
authorKonstantin Ritt <ritt.ks@gmail.com>2013-09-06 07:12:20 +0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-08 04:21:47 +0200
commit7b8f33fb78939a7564ce4d06cdbb6a13f00743ca (patch)
tree5a2acb24b0bcb776c75634ce938e39d313ad62e3 /src/gui/text
parent149f3efc39bebbe8fceacf2553836f90d2e1c383 (diff)
QTextEngine::shapeTextWithHarfbuzz() code simplification
Move (sub-)item boundaries calculation (aka fallback font items) outside to be shared with HarfBuzz-NG based shaping a bit later. This implementation might silently break words or even graphemes so it needs to be reworked anyways; keeping it in a single place would make futher work some cheaper. Change-Id: Id9ca82b40e90b07ca29363fd43247c5fa9897eff Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qtextengine.cpp133
-rw-r--r--src/gui/text/qtextengine_p.h2
2 files changed, 69 insertions, 66 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 7a12b241e8..90f5ddbeba 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -883,9 +883,6 @@ void QTextEngine::shapeText(int item) const
const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.constData()) + si.position;
const int itemLength = length(item);
- if (!ensureSpace(itemLength))
- return; // ### report OOM error somehow
-
QString casedString;
if (si.analysis.flags && si.analysis.flags <= QScriptAnalysis::SmallCaps) {
casedString.resize(itemLength);
@@ -910,8 +907,61 @@ void QTextEngine::shapeText(int item) const
string = reinterpret_cast<const ushort *>(casedString.constData());
}
+ if (!ensureSpace(itemLength)) {
+ // ### report OOM error somehow
+ return;
+ }
+
QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading);
+ // split up the item into parts that come from different font engines
+ QVector<uint> itemBoundaries;
+ itemBoundaries.reserve(16);
+ // k * 2 entries, array[k] == index in string, array[k + 1] == index in glyphs
+ itemBoundaries.append(0);
+ itemBoundaries.append(0);
+
+ if (fontEngine->type() == QFontEngine::Multi) {
+ // ask the font engine to find out which glyphs (as an index in the specific font)
+ // to use for the text in one item.
+ QGlyphLayout initialGlyphs = availableGlyphs(&si);
+
+ int nGlyphs = initialGlyphs.numGlyphs;
+ QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
+ if (si.analysis.bidiLevel % 2)
+ shaperFlags |= QFontEngine::RightToLeft;
+
+ if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
+ nGlyphs = qMax(nGlyphs, itemLength); // ### needed for QFontEngine::stringToCMap() to not fail twice
+ if (!ensureSpace(nGlyphs)) {
+ // ### report OOM error somehow
+ return;
+ }
+ initialGlyphs = availableGlyphs(&si);
+ if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
+ // ### if this happens there is a bug in the fontengine
+ return;
+ }
+ }
+
+ uint lastEngine = 0;
+ for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
+ const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;
+ if (lastEngine != engineIdx && glyph_pos > 0) {
+ itemBoundaries.append(i);
+ itemBoundaries.append(glyph_pos);
+
+ lastEngine = engineIdx;
+ QFontEngine *actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
+ si.ascent = qMax(actualFontEngine->ascent(), si.ascent);
+ si.descent = qMax(actualFontEngine->descent(), si.descent);
+ si.leading = qMax(actualFontEngine->leading(), si.leading);
+ }
+ if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))
+ ++i;
+ }
+ }
+
bool kerningEnabled;
bool letterSpacingIsAbsolute;
QFixed letterSpacing, wordSpacing;
@@ -935,9 +985,13 @@ void QTextEngine::shapeText(int item) const
letterSpacing *= font.d->dpi / qt_defaultDpiY();
}
- si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, kerningEnabled);
- if (!si.num_glyphs)
- return; // ### report shaping errors somehow
+ si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
+ if (si.num_glyphs == 0) {
+ // ### report shaping errors somehow
+ return;
+ }
+
+
layoutData->used += si.num_glyphs;
QGlyphLayout glyphs = shapedGlyphs(&si);
@@ -998,22 +1052,7 @@ Q_STATIC_ASSERT(sizeof(HB_GlyphAttributes) == sizeof(QGlyphAttributes));
Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint));
-// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item.
-static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine)
-{
- int nGlyphs = item->num_glyphs;
-
- QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
- if (item->item.bidiLevel % 2)
- shaperFlags |= QFontEngine::RightToLeft;
-
- bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags);
- item->num_glyphs = nGlyphs;
- glyphs->numGlyphs = nGlyphs;
- return result;
-}
-
-int QTextEngine::shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const
+int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const
{
HB_ShaperItem entire_shaper_item;
memset(&entire_shaper_item, 0, sizeof(entire_shaper_item));
@@ -1030,45 +1069,13 @@ int QTextEngine::shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, in
if (option.useDesignMetrics())
entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics;
- entire_shaper_item.num_glyphs = itemLength;
-
- QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
-
- if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) {
- if (!ensureSpace(entire_shaper_item.num_glyphs))
- return 0;
- initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
- if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) {
- // ############ if this happens there's a bug in the fontengine
- return 0;
- }
+ // ensure we are not asserting in HB_HeuristicSetGlyphAttributes()
+ entire_shaper_item.num_glyphs = 0;
+ for (int i = 0; i < itemLength; ++i, ++entire_shaper_item.num_glyphs) {
+ if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))
+ ++i;
}
- // split up the item into parts that come from different font engines.
- QVarLengthArray<int> itemBoundaries(2);
- // k * 2 entries, array[k] == index in string, array[k + 1] == index in glyphs
- itemBoundaries[0] = entire_shaper_item.item.pos;
- itemBoundaries[1] = 0;
-
- if (fontEngine->type() == QFontEngine::Multi) {
- uint lastEngine = 0;
- int charIdx = entire_shaper_item.item.pos;
- const int stringEnd = charIdx + entire_shaper_item.item.length;
- for (quint32 i = 0; i < entire_shaper_item.num_glyphs; ++i, ++charIdx) {
- uint engineIdx = initialGlyphs.glyphs[i] >> 24;
- if (engineIdx != lastEngine && i > 0) {
- itemBoundaries.append(charIdx);
- itemBoundaries.append(i);
- }
- lastEngine = engineIdx;
- if (QChar::isHighSurrogate(entire_shaper_item.string[charIdx])
- && charIdx < stringEnd - 1
- && QChar::isLowSurrogate(entire_shaper_item.string[charIdx + 1]))
- ++charIdx;
- }
- }
-
-
int remaining_glyphs = entire_shaper_item.num_glyphs;
int glyph_pos = 0;
@@ -1093,18 +1100,14 @@ int QTextEngine::shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, in
uint engineIdx = 0;
if (fontEngine->type() == QFontEngine::Multi) {
engineIdx = uint(availableGlyphs(&si).glyphs[glyph_pos] >> 24);
-
actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
- si.ascent = qMax(actualFontEngine->ascent(), si.ascent);
- si.descent = qMax(actualFontEngine->descent(), si.descent);
- si.leading = qMax(actualFontEngine->leading(), si.leading);
+
+ shaper_item.glyphIndicesPresent = true;
}
shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();
shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace();
- shaper_item.glyphIndicesPresent = true;
-
remaining_glyphs -= shaper_item.initialGlyphCount;
do {
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index b3ab9a42d8..2ec33c2497 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -668,7 +668,7 @@ private:
void setBoundary(int strPos) const;
void addRequiredBoundaries() const;
void shapeText(int item) const;
- int shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const;
+ int shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const;
void splitItem(int item, int pos) const;
int endOfLine(int lineNum);