summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qtextengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/qtextengine.cpp')
-rw-r--r--src/gui/text/qtextengine.cpp205
1 files changed, 100 insertions, 105 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index febdaaa86c..ea61f257a2 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -241,7 +241,8 @@ using namespace std;
static const char *directions[] = {
"DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON",
- "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN"
+ "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN",
+ "DirLRI", "DirRLI", "DirFSI", "DirPDI"
};
#endif
@@ -928,21 +929,8 @@ void QTextEngine::shapeText(int item) const
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)) {
- Q_UNREACHABLE(); // ### report OOM error somehow
- return;
- }
- initialGlyphs = availableGlyphs(&si);
- if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
- Q_UNREACHABLE(); // ### if this happens there is a bug in the fontengine
- return;
- }
- }
+ if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
+ Q_UNREACHABLE();
uint lastEngine = ~0u;
for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
@@ -1014,17 +1002,17 @@ void QTextEngine::shapeText(int item) const
for (int i = 1; i < si.num_glyphs; ++i) {
if (glyphs.attributes[i].clusterStart) {
if (letterSpacingIsAbsolute)
- glyphs.advances_x[i-1] += letterSpacing;
+ glyphs.advances[i - 1] += letterSpacing;
else {
- QFixed &advance = glyphs.advances_x[i-1];
+ QFixed &advance = glyphs.advances[i - 1];
advance += (letterSpacing - 100) * advance / 100;
}
}
}
if (letterSpacingIsAbsolute)
- glyphs.advances_x[si.num_glyphs-1] += letterSpacing;
+ glyphs.advances[si.num_glyphs - 1] += letterSpacing;
else {
- QFixed &advance = glyphs.advances_x[si.num_glyphs-1];
+ QFixed &advance = glyphs.advances[si.num_glyphs - 1];
advance += (letterSpacing - 100) * advance / 100;
}
}
@@ -1036,13 +1024,13 @@ void QTextEngine::shapeText(int item) const
if (i + 1 == si.num_glyphs
||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space
&& glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space))
- glyphs.advances_x[i] += wordSpacing;
+ glyphs.advances[i] += wordSpacing;
}
}
}
for (int i = 0; i < si.num_glyphs; ++i)
- si.width += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
}
#ifdef QT_ENABLE_HARFBUZZ_NG
@@ -1139,8 +1127,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
for (uint i = 0; i < num_glyphs; ++i) {
g.glyphs[i] = infos[i].codepoint;
- g.advances_x[i] = QFixed::fromFixed(positions[i].x_advance);
- g.advances_y[i] = QFixed::fromFixed(positions[i].y_advance);
+ g.advances[i] = QFixed::fromFixed(positions[i].x_advance);
g.offsets[i].x = QFixed::fromFixed(positions[i].x_offset);
g.offsets[i].y = QFixed::fromFixed(positions[i].y_offset);
@@ -1163,6 +1150,13 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
g.glyphs[i] |= (engineIdx << 24);
}
+#ifdef Q_OS_MAC
+ if (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (uint i = 0; i < num_glyphs; ++i)
+ g.advances[i] = g.advances[i].round();
+ }
+#endif
+
glyphs_shaped += num_glyphs;
}
@@ -1238,7 +1232,8 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
if (fontEngine->type() == QFontEngine::Multi) {
actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
- shaper_item.glyphIndicesPresent = true;
+ if ((si.analysis.bidiLevel % 2) == 0)
+ shaper_item.glyphIndicesPresent = true;
}
shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();
@@ -1256,7 +1251,7 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs);
shaper_item.attributes = reinterpret_cast<HB_GlyphAttributes *>(g.attributes);
- shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances_x);
+ shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances);
shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);
if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {
@@ -1360,9 +1355,9 @@ void QTextEngine::shape(int item) const
if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) {
ensureSpace(1);
if (block.docHandle()) {
- QTextFormat format = formats()->format(formatIndex(&layoutData->items[item]));
docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)),
- layoutData->items[item].position + block.position(), format);
+ layoutData->items[item].position + block.position(),
+ format(&layoutData->items[item]));
}
} else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) {
// set up at least the ascent/descent/leading of the script item for the tab
@@ -1394,7 +1389,7 @@ void QTextEngine::invalidate()
minWidth = 0;
maxWidth = 0;
if (specialData)
- specialData->resolvedFormatIndices.clear();
+ specialData->resolvedFormats.clear();
resetFontEngineCache();
}
@@ -1468,8 +1463,18 @@ void QTextEngine::itemize() const
{
QVarLengthArray<uchar> scripts(length);
QUnicodeTools::initScripts(string, length, scripts.data());
- for (int i = 0; i < length; ++i)
- analysis[i].script = scripts.at(i);
+ for (int i = 0; i < length; ++i) {
+ ushort script = scripts.at(i);
+ switch (script) {
+ case QChar::Script_Hiragana:
+ case QChar::Script_Katakana:
+ script = QChar::Script_Han;
+ break;
+ default:
+ break;
+ }
+ analysis[i].script = script;
+ }
}
const ushort *uc = string;
@@ -1563,10 +1568,9 @@ void QTextEngine::itemize() const
#ifndef QT_NO_RAWFONT
if (useRawFont && specialData) {
int lastIndex = 0;
- const QTextFormatCollection *collection = formats();
for (int i = 0; i < specialData->addFormats.size(); ++i) {
const QTextLayout::FormatRange &range = specialData->addFormats.at(i);
- const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i));
+ const QTextCharFormat &format = range.format;
if (format.hasProperty(QTextFormat::FontCapitalization)) {
itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);
itemizer.generate(range.start, range.length, format.fontCapitalization());
@@ -1674,7 +1678,7 @@ QFixed QTextEngine::width(int from, int len) const
// qDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd);
for (int i = glyphStart; i < glyphEnd; i++)
- w += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ w += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
}
}
}
@@ -1963,11 +1967,22 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph,
if (type >= QGlyphAttributes::Arabic_Normal) {
QChar ch(0x640); // Kashida character
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
- fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
- if (glyphs.glyphs[0] && glyphs.advances_x[0] != 0) {
- point->kashidaWidth = glyphs.advances_x[0];
+
+ glyph_t kashidaGlyph;
+ QFixed kashidaWidth;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &kashidaGlyph;
+ glyphs.advances = &kashidaWidth;
+
+ int nglyphs = 1;
+ if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ if (kashidaGlyph != 0 && kashidaWidth != 0) {
+ point->kashidaWidth = kashidaWidth;
} else {
point->type = QGlyphAttributes::NoJustification;
point->kashidaWidth = 0;
@@ -2209,7 +2224,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
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);
+ available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::SpaceNeeded;
if (available_glyphs < str.length()) {
// need to allocate on the heap
@@ -2251,7 +2266,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
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;
+ int space_glyphs = (totalGlyphs * QGlyphLayout::SpaceNeeded) / sizeof(void *) + 2;
int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
// These values can be negative if the length of string/glyphs causes overflow,
@@ -2298,8 +2313,7 @@ void QGlyphLayout::grow(char *address, int totalGlyphs)
// move the existing data
memmove(newLayout.attributes, oldLayout.attributes, numGlyphs * sizeof(QGlyphAttributes));
memmove(newLayout.justifications, oldLayout.justifications, numGlyphs * sizeof(QGlyphJustification));
- memmove(newLayout.advances_y, oldLayout.advances_y, numGlyphs * sizeof(QFixed));
- memmove(newLayout.advances_x, oldLayout.advances_x, numGlyphs * sizeof(QFixed));
+ memmove(newLayout.advances, oldLayout.advances, numGlyphs * sizeof(QFixed));
memmove(newLayout.glyphs, oldLayout.glyphs, numGlyphs * sizeof(glyph_t));
}
@@ -2328,8 +2342,12 @@ void QTextEngine::freeMemory()
int QTextEngine::formatIndex(const QScriptItem *si) const
{
- if (specialData && !specialData->resolvedFormatIndices.isEmpty())
- return specialData->resolvedFormatIndices.at(si - &layoutData->items[0]);
+ if (specialData && !specialData->resolvedFormats.isEmpty()) {
+ QTextFormatCollection *collection = formats();
+ Q_ASSERT(collection);
+ return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0]));
+ }
+
QTextDocumentPrivate *p = block.docHandle();
if (!p)
return -1;
@@ -2442,23 +2460,6 @@ void QTextEngine::setPreeditArea(int position, const QString &preeditText)
clearLineData();
}
-QList<QTextLayout::FormatRange> QTextEngine::additionalFormats() const
-{
- QList<QTextLayout::FormatRange> formatList;
- if (!specialData)
- return formatList;
-
- formatList = specialData->addFormats;
- if (!specialData->addFormatIndices.isEmpty()) {
- const QTextFormatCollection *formats = this->formats();
- Q_ASSERT(formats);
- for (int i = 0; i < specialData->addFormatIndices.size(); ++i)
- formatList[i].format = formats->charFormat(specialData->addFormatIndices.at(i));
- }
-
- return formatList;
-}
-
void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList)
{
if (formatList.isEmpty()) {
@@ -2469,7 +2470,6 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo
specialData = 0;
} else {
specialData->addFormats.clear();
- specialData->addFormatIndices.clear();
}
} else {
if (!specialData) {
@@ -2484,19 +2484,17 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo
void QTextEngine::indexAdditionalFormats()
{
- specialData->addFormatIndices.resize(specialData->addFormats.count());
-
- QTextFormatCollection *formats = this->formats();
-
- if (!formats) {
+ QTextFormatCollection *collection = formats();
+ if (!collection) {
Q_ASSERT(!block.docHandle());
specialData->formats.reset(new QTextFormatCollection);
- formats = specialData->formats.data();
+ collection = specialData->formats.data();
}
+ // replace with shared copies
for (int i = 0; i < specialData->addFormats.count(); ++i) {
- specialData->addFormatIndices[i] = formats->indexForFormat(specialData->addFormats.at(i).format);
- specialData->addFormats[i].format = QTextCharFormat();
+ QTextCharFormat &format = specialData->addFormats[i].format;
+ format = collection->charFormat(collection->indexForFormat(format));
}
}
@@ -2510,7 +2508,8 @@ static inline bool nextCharJoins(const QString &string, int pos)
++pos;
if (pos == string.length())
return false;
- return string.at(pos).joining() != QChar::OtherJoining;
+ QChar::JoiningType joining = string.at(pos).joiningType();
+ return joining != QChar::Joining_None && joining != QChar::Joining_Transparent;
}
static inline bool prevCharJoins(const QString &string, int pos)
@@ -2519,19 +2518,15 @@ static inline bool prevCharJoins(const QString &string, int pos)
--pos;
if (pos == 0)
return false;
- QChar::Joining joining = string.at(pos - 1).joining();
- return (joining == QChar::Dual || joining == QChar::Center);
+ QChar::JoiningType joining = string.at(pos - 1).joiningType();
+ return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing;
}
static inline bool isRetainableControlCode(QChar c)
{
- return (c.unicode() == 0x202a // LRE
- || c.unicode() == 0x202b // LRE
- || c.unicode() == 0x202c // PDF
- || c.unicode() == 0x202d // LRO
- || c.unicode() == 0x202e // RLO
- || c.unicode() == 0x200e // LRM
- || c.unicode() == 0x200f); // RLM
+ return (c.unicode() >= 0x202a && c.unicode() <= 0x202e) // LRE, RLE, PDF, LRO, RLO
+ || (c.unicode() >= 0x200e && c.unicode() <= 0x200f) // LRM, RLM
+ || (c.unicode() >= 0x2066 && c.unicode() <= 0x2069); // LRM, RLM
}
static QString stringMidRetainingBidiCC(const QString &string,
@@ -2619,14 +2614,14 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (feForEllipsis->type() == QFontEngine::Mac)
feForEllipsis = fe;
- if (feForEllipsis->canRender(&ellipsisChar, 1)) {
- int nGlyphs = 1;
- feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0);
- }
+ int nGlyphs = 1;
+ if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nGlyphs == 1);
}
if (ellipsisGlyph.glyphs[0]) {
- ellipsisWidth = ellipsisGlyph.advances_x[0];
+ ellipsisWidth = ellipsisGlyph.advances[0];
ellipsisText = ellipsisChar;
} else {
QString dotDotDot(QLatin1String("..."));
@@ -2634,10 +2629,11 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
QGlyphLayoutArray<3> glyphs;
int nGlyphs = 3;
if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0))
- // should never happen...
- return layoutData->string;
+ Q_UNREACHABLE();
+ Q_ASSERT(nGlyphs == 3);
+
for (int i = 0; i < nGlyphs; ++i)
- ellipsisWidth += glyphs.advances_x[i];
+ ellipsisWidth += glyphs.advances[i];
ellipsisText = dotDotDot;
}
}
@@ -2786,7 +2782,7 @@ void QTextEngine::splitItem(int item, int pos) const
QFixed w = 0;
const QGlyphLayout g = shapedGlyphs(&oldItem);
for(int j = 0; j < breakGlyph; ++j)
- w += g.advances_x[j] * !g.attributes[j].dontPrint;
+ w += g.advances[j] * !g.attributes[j].dontPrint;
newItem.width = oldItem.width - w;
oldItem.width = w;
@@ -2859,9 +2855,9 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
QGlyphLayout glyphs = this->shapedGlyphs(&item);
const int end = qMin(item.position + item.num_glyphs, tabSectionEnd) - item.position;
for (int i=0; i < end; i++)
- length += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ length += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
if (end + item.position == tabSectionEnd && tabSpec.type == QTextOption::DelimiterTab) // remove half of matching char
- length -= glyphs.advances_x[end] / 2 * !glyphs.attributes[end].dontPrint;
+ length -= glyphs.advances[end] / 2 * !glyphs.attributes[end].dontPrint;
}
switch (tabSpec.type) {
@@ -2915,14 +2911,12 @@ public:
void QTextEngine::resolveAdditionalFormats() const
{
if (!specialData || specialData->addFormats.isEmpty()
- || !specialData->resolvedFormatIndices.isEmpty())
+ || !specialData->resolvedFormats.isEmpty())
return;
QTextFormatCollection *collection = formats();
- specialData->resolvedFormatIndices.clear();
- QVector<int> indices(layoutData->items.count());
-
+ specialData->resolvedFormats.resize(layoutData->items.count());
QVarLengthArray<int, 64> addFormatSortedByStart;
addFormatSortedByStart.reserve(specialData->addFormats.count());
@@ -2958,21 +2952,22 @@ void QTextEngine::resolveAdditionalFormats() const
currentFormats.remove(currentFormatIterator - currentFormats.begin());
++endIt;
}
- QTextCharFormat format;
+
+ QTextCharFormat &format = specialData->resolvedFormats[i];
if (block.docHandle()) {
// when we have a docHandle, formatIndex might still return a valid index based
// on the preeditPosition. for all other cases, we cleared the resolved format indices
format = collection->charFormat(formatIndex(si));
}
-
- foreach (int cur, currentFormats) {
- Q_ASSERT(specialData->addFormats.at(cur).start <= si->position
- && specialData->addFormats.at(cur).start + specialData->addFormats.at(cur).length >= end);
- format.merge(collection->format(specialData->addFormatIndices.at(cur)));
+ if (!currentFormats.isEmpty()) {
+ foreach (int cur, currentFormats) {
+ const QTextLayout::FormatRange &range = specialData->addFormats.at(cur);
+ Q_ASSERT(range.start <= si->position && range.start + range.length >= end);
+ format.merge(range.format);
+ }
+ format = collection->charFormat(collection->indexForFormat(format)); // get shared copy
}
- indices[i] = collection->indexForFormat(format);
}
- specialData->resolvedFormatIndices = indices;
}
QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)
@@ -3026,7 +3021,7 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in
break;
}
if (clusterLength)
- return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength;
+ return glyphs.advances[glyph_pos] * offsetInCluster / clusterLength;
}
return 0;