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.cpp194
1 files changed, 118 insertions, 76 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index f0776c6098..2fa7f0232d 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -51,7 +51,6 @@
#include "qfont_p.h"
#include "qfontengine_p.h"
#include "qstring.h"
-#include <private/qunicodetables_p.h>
#include "qtextdocument_p.h"
#include "qrawfont.h"
#include "qrawfont_p.h"
@@ -62,6 +61,8 @@
#include "qfontengine_qpa_p.h"
+#include <private/qharfbuzz_p.h>
+
QT_BEGIN_NAMESPACE
static const float smallCapsFraction = 0.7f;
@@ -837,13 +838,6 @@ void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrd
#endif
}
-QT_BEGIN_INCLUDE_NAMESPACE
-
-
-#include <private/qharfbuzz_p.h>
-
-QT_END_INCLUDE_NAMESPACE
-
// 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)
{
@@ -972,19 +966,21 @@ static inline bool hasCaseChange(const QScriptItem &si)
static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num)
{
if (num > 0 && destination.glyphs != source.glyphs) {
- memmove(destination.glyphs, source.glyphs, num * sizeof(HB_Glyph));
- memmove(destination.attributes, source.attributes, num * sizeof(HB_GlyphAttributes));
- memmove(destination.advances_x, source.advances_x, num * sizeof(HB_Fixed));
- memmove(destination.offsets, source.offsets, num * sizeof(HB_FixedPoint));
+ memmove(destination.glyphs, source.glyphs, num * sizeof(glyph_t));
+ memmove(destination.attributes, source.attributes, num * sizeof(QGlyphAttributes));
+ memmove(destination.advances_x, source.advances_x, num * sizeof(QFixed));
+ memmove(destination.offsets, source.offsets, num * sizeof(QFixedPoint));
}
}
+Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));
+Q_STATIC_ASSERT(sizeof(HB_GlyphAttributes) == sizeof(QGlyphAttributes));
+Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
+Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint));
+
/// take the item from layoutData->items and
void QTextEngine::shapeTextWithHarfbuzz(int item) const
{
- Q_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
- Q_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint));
-
QScriptItem &si = layoutData->items[item];
si.glyph_data_offset = layoutData->used;
@@ -1004,7 +1000,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
memset(&entire_shaper_item, 0, sizeof(entire_shaper_item));
entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData());
entire_shaper_item.stringLength = layoutData->string.length();
- entire_shaper_item.item.script = (HB_Script)si.analysis.script;
+ entire_shaper_item.item.script = script_to_hbscript(si.analysis.script);
entire_shaper_item.item.pos = si.position;
entire_shaper_item.item.length = length(item);
entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;
@@ -1075,9 +1071,9 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
itemBoundaries.append(i);
}
lastEngine = engineIdx;
- if (HB_IsHighSurrogate(entire_shaper_item.string[charIdx])
+ if (QChar::isHighSurrogate(entire_shaper_item.string[charIdx])
&& charIdx < stringEnd - 1
- && HB_IsLowSurrogate(entire_shaper_item.string[charIdx + 1]))
+ && QChar::isLowSurrogate(entire_shaper_item.string[charIdx + 1]))
++charIdx;
}
}
@@ -1115,8 +1111,8 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
si.descent = qMax(actualFontEngine->descent(), si.descent);
si.leading = qMax(actualFontEngine->leading(), si.leading);
- shaper_item.font = actualFontEngine->harfbuzzFont();
- shaper_item.face = actualFontEngine->initializedHarfbuzzFace();
+ shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();
+ shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace();
shaper_item.glyphIndicesPresent = true;
@@ -1130,13 +1126,13 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
if (shaper_item.num_glyphs > shaper_item.item.length)
moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
- shaper_item.glyphs = g.glyphs;
- shaper_item.attributes = g.attributes;
+ 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.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);
if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {
- for (hb_uint32 i = 0; i < shaper_item.initialGlyphCount; ++i)
+ for (quint32 i = 0; i < shaper_item.initialGlyphCount; ++i)
shaper_item.glyphs[i] &= 0x00ffffff;
}
@@ -1148,14 +1144,14 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs);
moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
- for (hb_uint32 i = 0; i < shaper_item.item.length; ++i)
+ for (quint32 i = 0; i < shaper_item.item.length; ++i)
shaper_item.log_clusters[i] += glyph_pos;
if (kerningEnabled && !shaper_item.kerning_applied)
actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0));
if (engineIdx != 0) {
- for (hb_uint32 i = 0; i < shaper_item.num_glyphs; ++i)
+ for (quint32 i = 0; i < shaper_item.num_glyphs; ++i)
g.glyphs[i] |= (engineIdx << 24);
}
@@ -1168,7 +1164,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
layoutData->used += si.num_glyphs;
}
-static void init(QTextEngine *e)
+void QTextEngine::init(QTextEngine *e)
{
e->ignoreBidi = false;
e->cacheGlyphs = false;
@@ -1225,7 +1221,7 @@ const QCharAttributes *QTextEngine::attributes() const
scriptItems[i].script = si.analysis.script;
}
- QUnicodeTools::initCharAttributes(reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData()),
+ QUnicodeTools::initCharAttributes(reinterpret_cast<const ushort *>(layoutData->string.constData()),
layoutData->string.length(),
scriptItems.data(), scriptItems.size(),
(QCharAttributes *)layoutData->memory);
@@ -1257,11 +1253,8 @@ void QTextEngine::shape(int item) const
static inline void releaseCachedFontEngine(QFontEngine *fontEngine)
{
- if (fontEngine) {
- fontEngine->ref.deref();
- if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0)
- delete fontEngine;
- }
+ if (fontEngine && !fontEngine->ref.deref())
+ delete fontEngine;
}
void QTextEngine::resetFontEngineCache()
@@ -1313,6 +1306,8 @@ void QTextEngine::itemize() const
if (!length)
return;
+ const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.unicode());
+
bool ignore = ignoreBidi;
bool rtl = isRightToLeft();
@@ -1346,44 +1341,48 @@ void QTextEngine::itemize() const
layoutData->hasBidi = bidiItemize(const_cast<QTextEngine *>(this), analysis, control);
}
- const ushort *uc = reinterpret_cast<const ushort *>(layoutData->string.unicode());
+ {
+ QVarLengthArray<uchar> scripts(length);
+ QUnicodeTools::initScripts(string, length, scripts.data());
+ for (int i = 0; i < length; ++i)
+ analysis[i].script = scripts.at(i);
+ }
+
+ const ushort *uc = string;
const ushort *e = uc + length;
- int lastScript = QUnicodeTables::Common;
while (uc < e) {
switch (*uc) {
case QChar::ObjectReplacementCharacter:
- analysis->script = QUnicodeTables::Common;
+ analysis->script = QChar::Script_Common;
analysis->flags = QScriptAnalysis::Object;
break;
case QChar::LineSeparator:
if (analysis->bidiLevel % 2)
--analysis->bidiLevel;
- analysis->script = QUnicodeTables::Common;
+ analysis->script = QChar::Script_Common;
analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;
if (option.flags() & QTextOption::ShowLineAndParagraphSeparators)
*const_cast<ushort*>(uc) = 0x21B5; // visual line separator
break;
case QChar::Tabulation:
- analysis->script = QUnicodeTables::Common;
+ analysis->script = QChar::Script_Common;
analysis->flags = QScriptAnalysis::Tab;
analysis->bidiLevel = control.baseLevel();
break;
case QChar::Space:
case QChar::Nbsp:
if (option.flags() & QTextOption::ShowTabsAndSpaces) {
- analysis->script = QUnicodeTables::Common;
+ analysis->script = QChar::Script_Common;
analysis->flags = QScriptAnalysis::Space;
analysis->bidiLevel = control.baseLevel();
break;
}
// fall through
default:
- int script = QUnicodeTables::script(*uc);
- analysis->script = script == QUnicodeTables::Inherited ? lastScript : script;
analysis->flags = QScriptAnalysis::None;
break;
}
- lastScript = analysis->script;
+ analysis->script = hbscript_to_script(script_to_hbscript(analysis->script)); // retain the old behavior
++uc;
++analysis;
}
@@ -1431,11 +1430,13 @@ 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);
- if (range.format.fontCapitalization()) {
+ const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i));
+ if (format.hasProperty(QTextFormat::FontCapitalization)) {
itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);
- itemizer.generate(range.start, range.length, range.format.fontCapitalization());
+ itemizer.generate(range.start, range.length, format.fontCapitalization());
lastIndex = range.start + range.length;
}
}
@@ -2035,9 +2036,9 @@ void QScriptLine::setDefaultHeight(QTextEngine *eng)
QPaintDevice *pdev = eng->block.docHandle()->layout()->paintDevice();
if (pdev)
f = QFont(f, pdev);
- e = f.d->engineForScript(QUnicodeTables::Common);
+ e = f.d->engineForScript(QChar::Script_Common);
} else {
- e = eng->fnt.d->engineForScript(QUnicodeTables::Common);
+ e = eng->fnt.d->engineForScript(QChar::Script_Common);
}
QFixed other_ascent = e->ascent();
@@ -2155,11 +2156,11 @@ void QGlyphLayout::grow(char *address, int totalGlyphs)
if (numGlyphs) {
// move the existing data
- memmove(newLayout.attributes, oldLayout.attributes, numGlyphs * sizeof(HB_GlyphAttributes));
+ 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.glyphs, oldLayout.glyphs, numGlyphs * sizeof(HB_Glyph));
+ memmove(newLayout.glyphs, oldLayout.glyphs, numGlyphs * sizeof(glyph_t));
}
// clear the new data
@@ -2206,25 +2207,9 @@ int QTextEngine::formatIndex(const QScriptItem *si) const
QTextCharFormat QTextEngine::format(const QScriptItem *si) const
{
- QTextCharFormat format;
- const QTextFormatCollection *formats = this->formats();
-
- if (formats)
- format = formats->charFormat(formatIndex(si));
-
- if (specialData && specialData->resolvedFormatIndices.isEmpty()) {
- int end = si->position + length(si);
- for (int i = 0; i < specialData->addFormats.size(); ++i) {
- const QTextLayout::FormatRange &r = specialData->addFormats.at(i);
- if (r.start <= si->position && r.start + r.length >= end) {
- if (!specialData->addFormatIndices.isEmpty())
- format.merge(formats->format(specialData->addFormatIndices.at(i)));
- else
- format.merge(r.format);
- }
- }
- }
- return format;
+ if (const QTextFormatCollection *formats = this->formats())
+ return formats->charFormat(formatIndex(si));
+ return QTextCharFormat();
}
void QTextEngine::addRequiredBoundaries() const
@@ -2295,6 +2280,67 @@ bool QTextEngine::atSpace(int position) const
return false;
}
+void QTextEngine::setPreeditArea(int position, const QString &preeditText)
+{
+ if (preeditText.isEmpty()) {
+ if (!specialData)
+ return;
+ if (specialData->addFormats.isEmpty()) {
+ delete specialData;
+ specialData = 0;
+ } else {
+ specialData->preeditText = QString();
+ specialData->preeditPosition = -1;
+ }
+ } else {
+ if (!specialData)
+ specialData = new SpecialData;
+ specialData->preeditPosition = position;
+ specialData->preeditText = preeditText;
+ }
+ invalidate();
+ 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()) {
+ if (!specialData)
+ return;
+ if (specialData->preeditText.isEmpty()) {
+ delete specialData;
+ specialData = 0;
+ } else {
+ specialData->addFormats.clear();
+ specialData->addFormatIndices.clear();
+ }
+ } else {
+ if (!specialData) {
+ specialData = new SpecialData;
+ specialData->preeditPosition = -1;
+ }
+ specialData->addFormats = formatList;
+ indexAdditionalFormats();
+ }
+ resetFontEngineCache();
+}
void QTextEngine::indexAdditionalFormats()
{
@@ -2421,7 +2467,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
{
QChar ellipsisChar(0x2026);
- QFontEngine *fe = fnt.d->engineForScript(QUnicodeTables::Common);
+ QFontEngine *fe = fnt.d->engineForScript(QChar::Script_Common);
QGlyphLayoutArray<1> ellipsisGlyph;
{
@@ -2772,13 +2818,9 @@ void QTextEngine::resolveAdditionalFormats() const
}
foreach (int cur, currentFormats) {
- const QTextLayout::FormatRange &r = specialData->addFormats.at(cur);
- Q_ASSERT (r.start <= si->position && r.start + r.length >= end);
- if (!specialData->addFormatIndices.isEmpty()) {
- format.merge(collection->format(specialData->addFormatIndices.at(cur)));
- } else {
- format.merge(r.format);
- }
+ 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)));
}
indices[i] = collection->indexForFormat(format);
}
@@ -2868,8 +2910,8 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
int clusterStart = -1;
int clusterLength = 0;
- if (si->analysis.script != QUnicodeTables::Common &&
- si->analysis.script != QUnicodeTables::Greek) {
+ if (si->analysis.script != QChar::Script_Common &&
+ si->analysis.script != QChar::Script_Greek) {
if (glyph_pos == -1)
return si->position + end;
else {