diff options
Diffstat (limited to 'src/gui/text')
30 files changed, 733 insertions, 466 deletions
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index e584b66a25..f2b88c4692 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -739,13 +739,19 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine) if (!fe) return false; - QGlyphLayout glyphs; + const QChar uc(QLatin1Char('O')); + glyph_t glyph; - glyphs.glyphs = &glyph; + + QGlyphLayout glyphs; glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; int numGlyphs = 1; - QChar uc = QLatin1Char('O'); - fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly); + + if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); + QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform()); Q_ASSERT(fe->ref.load() == 0); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 49b5a9ba46..83f2d7190b 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2073,6 +2073,18 @@ QString QFont::toString() const QString::number((int) rawMode()); } +/*! + Returns the hash value for \a font. If specified, \a seed is used + to initialize the hash. + + \relates QFont + \since 5.3 +*/ +uint qHash(const QFont &font, uint seed) Q_DECL_NOTHROW +{ + return qHash(QFontPrivate::get(font)->request, seed); +} + /*! Sets this font to match the description \a descrip. The description @@ -2533,8 +2545,10 @@ bool QFontInfo::fixedPitch() const QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') }; QGlyphLayoutArray<2> g; int l = 2; - engine->stringToCMap(ch, 2, &g, &l, 0); - engine->fontDef.fixedPitch = g.advances_x[0] == g.advances_x[1]; + if (!engine->stringToCMap(ch, 2, &g, &l, 0)) + Q_UNREACHABLE(); + Q_ASSERT(l == 2); + engine->fontDef.fixedPitch = g.advances[0] == g.advances[1]; engine->fontDef.fixedPitchComputed = true; } #endif diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 6d36f7839b..a207a1d60e 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -315,6 +315,8 @@ private: Q_DECLARE_SHARED(QFont) +Q_GUI_EXPORT uint qHash(const QFont &font, uint seed = 0) Q_DECL_NOTHROW; + inline bool QFont::bold() const { return weight() > Normal; } diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 5b7f918e21..6165554388 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -55,6 +55,7 @@ #include "QtGui/qfont.h" #include "QtCore/qmap.h" +#include "QtCore/qhash.h" #include "QtCore/qobject.h" #include "QtCore/qstringlist.h" #include <QtGui/qfontdatabase.h> @@ -133,6 +134,22 @@ struct QFontDef } }; +inline uint qHash(const QFontDef &fd, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(qRound64(fd.pixelSize*10000)) // use only 4 fractional digits + ^ qHash(fd.weight) + ^ qHash(fd.style) + ^ qHash(fd.stretch) + ^ qHash(fd.styleHint) + ^ qHash(fd.styleStrategy) + ^ qHash(fd.ignorePitch) + ^ qHash(fd.fixedPitch) + ^ qHash(fd.family, seed) + ^ qHash(fd.styleName) + ^ qHash(fd.hintingPreference) + ; +} + class QFontEngineData { public: diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 708b8cbd58..9986ef6c60 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -167,8 +167,6 @@ private: friend class QFontPrivate; friend class QFontDialog; friend class QFontDialogPrivate; - friend class QFontEngineMultiXLFD; - friend class QFontEngineMultiQWS; friend class QFontEngineMultiQPA; QFontDatabasePrivate *d; diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index 6f4971e267..1972f5d58c 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -182,10 +182,17 @@ QFontEngine *loadSingleEngine(int script, QFontCache::Key key(def,script); QFontEngine *engine = QFontCache::instance()->findEngine(key); if (!engine) { - engine = pfdb->fontEngine(def, QChar::Script(script), size->handle); + engine = pfdb->fontEngine(def, size->handle); if (engine) { - QFontCache::Key key(def,script); - QFontCache::instance()->instance()->insertEngine(key,engine); + // Also check for OpenType tables when using complex scripts + if (!engine->supportsScript(QChar::Script(script))) { + qWarning(" OpenType support missing for script %d", script); + if (engine->ref.load() == 0) + delete engine; + return 0; + } + + QFontCache::instance()->insertEngine(key, engine); } } return engine; @@ -221,10 +228,10 @@ QFontEngine *loadEngine(int script, const QFontDef &request, pfMultiEngine->setFallbackFamiliesList(fallbacks); engine = pfMultiEngine; - // Cache Multi font engine as well in case we got the FT single + // Cache Multi font engine as well in case we got the single // font engine when we are actually looking for a Multi one QFontCache::Key key(request, script, 1); - QFontCache::instance()->instance()->insertEngine(key, engine); + QFontCache::instance()->insertEngine(key, engine); } return engine; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 9eea2e786f..14ce5d2396 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -48,6 +48,7 @@ #include "qvarlengtharray.h" #include <qmath.h> #include <qendian.h> +#include <private/qstringiterator_p.h> #ifdef QT_ENABLE_HARFBUZZ_NG # include "qharfbuzzng_p.h" @@ -89,18 +90,48 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint { QFontEngine *fe = (QFontEngine *)font->userData; + const QChar *str = reinterpret_cast<const QChar *>(string); + QGlyphLayout qglyphs; qglyphs.numGlyphs = *numGlyphs; qglyphs.glyphs = glyphs; - - QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (rightToLeft) - shaperFlags |= QFontEngine::RightToLeft; - int nGlyphs = *numGlyphs; - bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags); + bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly); *numGlyphs = nGlyphs; + if (rightToLeft && result && !fe->symbol) { + uint glyph_pos = 0; + for (uint i = 0; i < length; ++i, ++glyph_pos) { + uint ucs4 = str[i].unicode(); + if (Q_UNLIKELY(QChar::isHighSurrogate(ucs4) && i + 1 < length)) { + uint low = str[i + 1].unicode(); + if (Q_LIKELY(QChar::isLowSurrogate(low))) { + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ++i; + } + } + + uint mirrored = QChar::mirroredChar(ucs4); + if (Q_UNLIKELY(mirrored != ucs4)) { + QChar chars[2]; + uint numChars = 0; + if (Q_UNLIKELY(QChar::requiresSurrogates(mirrored))) { + chars[numChars++] = QChar(QChar::highSurrogate(mirrored)); + chars[numChars++] = QChar(QChar::lowSurrogate(mirrored)); + } else { + chars[numChars++] = QChar(mirrored); + } + + qglyphs.numGlyphs = numChars; + qglyphs.glyphs = glyphs + glyph_pos; + nGlyphs = numChars; + if (!fe->stringToCMap(chars, numChars, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 1); + } + } + } + return result; } @@ -108,13 +139,10 @@ static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGl { QFontEngine *fe = (QFontEngine *)font->userData; - QVarLengthArray<QFixed> advances_y(numGlyphs); - QGlyphLayout qglyphs; qglyphs.numGlyphs = numGlyphs; qglyphs.glyphs = const_cast<glyph_t *>(glyphs); - qglyphs.advances_x = reinterpret_cast<QFixed *>(advances); - qglyphs.advances_y = advances_y.data(); // not used + qglyphs.advances = reinterpret_cast<QFixed *>(advances); fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0)); } @@ -278,6 +306,10 @@ void *QFontEngine::harfbuzzFont() const return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this)); #endif if (!font_) { + HB_Face hbFace = (HB_Face)harfbuzzFace(); + if (hbFace->font_for_init != 0) + q_check_ptr(qHBLoadFace(hbFace)); + HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec)); Q_CHECK_PTR(hbFont); hbFont->klass = &hb_fontClass; @@ -308,8 +340,6 @@ void *QFontEngine::harfbuzzFace() const if (!face_) { HB_Face hbFace = qHBNewFace(const_cast<QFontEngine *>(this), hb_getSFntTable); Q_CHECK_PTR(hbFace); - if (hbFace->font_for_init != 0) - hbFace = qHBLoadFace(hbFace); hbFace->isSymbolFont = symbol; face_ = (void *)hbFace; @@ -349,6 +379,8 @@ bool QFontEngine::supportsScript(QChar::Script script) const } #endif HB_Face hbFace = (HB_Face)harfbuzzFace(); + if (hbFace->font_for_init != 0) + q_check_ptr(qHBLoadFace(hbFace)); return hbFace->supported_scripts[script_to_hbscript(script)]; } @@ -364,23 +396,39 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix QFixed QFontEngine::xHeight() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.height; } QFixed QFontEngine::averageCharWidth() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.xoff; } @@ -411,8 +459,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform while(i--) { if (glyphs.attributes[i].dontPrint) continue; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); totalKashidas += glyphs.justifications[i].nKashidas; } positions.resize(glyphs.numGlyphs+totalKashidas); @@ -424,8 +471,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform ++i; continue; } - xpos -= glyphs.advances_x[i]; - ypos -= glyphs.advances_y[i]; + xpos -= glyphs.advances[i]; QFixed gpos_x = xpos + glyphs.offsets[i].x; QFixed gpos_y = ypos + glyphs.offsets[i].y; @@ -441,12 +487,22 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform ++current; if (glyphs.justifications[i].nKashidas) { QChar ch(0x640); // Kashida character - QGlyphLayoutArray<8> g; - int nglyphs = 7; - stringToCMap(&ch, 1, &g, &nglyphs, 0); + + glyph_t kashidaGlyph; + QFixed kashidaWidth; + + QGlyphLayout g; + g.numGlyphs = 1; + g.glyphs = &kashidaGlyph; + g.advances = &kashidaWidth; + + int nglyphs = 1; + if (!stringToCMap(&ch, 1, &g, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) { - xpos -= g.advances_x[0]; - ypos -= g.advances_y[0]; + xpos -= kashidaWidth; QFixed gpos_x = xpos + glyphs.offsets[i].x; QFixed gpos_y = ypos + glyphs.offsets[i].y; @@ -458,7 +514,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform } positions[current].x = gpos_x; positions[current].y = gpos_y; - glyphs_out[current] = g.glyphs[0]; + glyphs_out[current] = kashidaGlyph; ++current; } } else { @@ -476,8 +532,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform positions[current].x = xpos + glyphs.offsets[i].x; positions[current].y = ypos + glyphs.offsets[i].y; glyphs_out[current] = glyphs.glyphs[i]; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); ++current; } ++i; @@ -492,8 +547,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform positions[current].x = QFixed::fromReal(gpos.x()); positions[current].y = QFixed::fromReal(gpos.y()); glyphs_out[current] = glyphs.glyphs[i]; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); ++current; } ++i; @@ -656,8 +710,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp for (int i=0; i < glyphs.numGlyphs; ++i) { glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]); if (metrics.width.value() == 0 || metrics.height.value() == 0) { - advanceX += glyphs.advances_x[i]; - advanceY += glyphs.advances_y[i]; + advanceX += glyphs.advances[i]; continue; } const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]); @@ -692,8 +745,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp advanceX += offset.x; advanceY += offset.y; qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path); - advanceX += glyphs.advances_x[i]; - advanceY += glyphs.advances_y[i]; + advanceX += glyphs.advances[i]; } } @@ -704,16 +756,12 @@ void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int n qreal y = positions[0].y.toReal(); QVarLengthGlyphLayoutArray g(nGlyphs); - for (int i = 0; i < nGlyphs; ++i) { + for (int i = 0; i < nGlyphs - 1; ++i) { g.glyphs[i] = glyphs[i]; - if (i < nGlyphs - 1) { - g.advances_x[i] = positions[i+1].x - positions[i].x; - g.advances_y[i] = positions[i+1].y - positions[i].y; - } else { - g.advances_x[i] = QFixed::fromReal(maxCharWidth()); - g.advances_y[i] = 0; - } + g.advances[i] = positions[i + 1].x - positions[i].x; } + g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1]; + g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth()); addBitmapFontToPath(x, y, g, path, flags); } @@ -973,10 +1021,10 @@ void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags if (flags & DesignMetrics) { for(int i = 0; i < glyphs->numGlyphs - 1; ++i) - glyphs->advances_x[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs); + glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs); } else { for(int i = 0; i < glyphs->numGlyphs - 1; ++i) - glyphs->advances_x[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs)); + glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs)); } } @@ -1320,17 +1368,22 @@ QFontEngineBox::~QFontEngineBox() { } -bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const +bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { if (*nglyphs < len) { *nglyphs = len; return false; } - memset(glyphs->glyphs, 0, len * sizeof(glyph_t)); + int ucs4Length = 0; + QStringIterator it(str, str + len); + while (it.hasNext()) { + it.advance(); + glyphs->glyphs[ucs4Length++] = 0; + } - *nglyphs = len; - glyphs->numGlyphs = len; + *nglyphs = ucs4Length; + glyphs->numGlyphs = ucs4Length; if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); @@ -1340,10 +1393,8 @@ bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { - for (int i = 0; i < glyphs->numGlyphs; i++) { - glyphs->advances_x[i] = _size; - glyphs->advances_y[i] = 0; - } + for (int i = 0; i < glyphs->numGlyphs; i++) + glyphs->advances[i] = _size; } void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) @@ -1503,11 +1554,9 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()); uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode(); if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) { - QFixedPoint tmpAdvance; - if (!(flags & GlyphIndicesOnly)) { - tmpAdvance.x = glyphs->advances_x[glyph_pos]; - tmpAdvance.y = glyphs->advances_y[glyph_pos]; - } + QFixed tmpAdvance; + if (!(flags & GlyphIndicesOnly)) + tmpAdvance = glyphs->advances[glyph_pos]; for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) { if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4)) continue; @@ -1522,11 +1571,12 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, continue; if (!(flags & GlyphIndicesOnly)) - glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0; + glyphs->advances[glyph_pos] = QFixed(); int num = 2; - QGlyphLayout offs = glyphs->mid(glyph_pos, num); - engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags); - Q_ASSERT(num == 1); // surrogates only give 1 glyph + QGlyphLayout g = glyphs->mid(glyph_pos, num); + if (!engine->stringToCMap(str + i, surrogate ? 2 : 1, &g, &num, flags)) + Q_UNREACHABLE(); + Q_ASSERT(num == 1); if (glyphs->glyphs[glyph_pos]) { // set the high byte to indicate which engine the glyph came from glyphs->glyphs[glyph_pos] |= (x << 24); @@ -1535,10 +1585,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, } // ensure we use metrics from the 1st font when we use the fallback image. - if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) { - glyphs->advances_x[glyph_pos] = tmpAdvance.x; - glyphs->advances_y[glyph_pos] = tmpAdvance.y; - } + if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) + glyphs->advances[glyph_pos] = tmpAdvance; } if (surrogate) @@ -1639,10 +1687,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl int start = 0; int end, i; if (flags & QTextItem::RightToLeft) { - for (int gl = 0; gl < glyphs.numGlyphs; gl++) { - x += glyphs.advances_x[gl].toReal(); - y += glyphs.advances_y[gl].toReal(); - } + for (int gl = 0; gl < glyphs.numGlyphs; gl++) + x += glyphs.advances[gl].toReal(); } for (end = 0; end < glyphs.numGlyphs; ++end) { const int e = highByte(glyphs.glyphs[end]); @@ -1650,10 +1696,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl continue; if (flags & QTextItem::RightToLeft) { - for (i = start; i < end; ++i) { - x -= glyphs.advances_x[i].toReal(); - y -= glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x -= glyphs.advances[i].toReal(); } // set the high byte to zero @@ -1666,10 +1710,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl glyphs.glyphs[i] = hi | glyphs.glyphs[i]; if (!(flags & QTextItem::RightToLeft)) { - for (i = start; i < end; ++i) { - x += glyphs.advances_x[i].toReal(); - y += glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x += glyphs.advances[i].toReal(); } // change engine @@ -1678,10 +1720,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl } if (flags & QTextItem::RightToLeft) { - for (i = start; i < end; ++i) { - x -= glyphs.advances_x[i].toReal(); - y -= glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x -= glyphs.advances[i].toReal(); } // set the high byte to zero @@ -1847,16 +1887,11 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) QGlyphLayout g; g.numGlyphs = nglyphs; g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) { - glyphs.resize(nglyphs); - g.numGlyphs = nglyphs; - g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); for (int i = 0; i < nglyphs; i++) { - if (g.glyphs[i] == 0) + if (glyphs[i] == 0) return false; } diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 05bd014bd7..665932e4a5 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -723,7 +723,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, FT_Set_Transform(face, &matrix, 0); freetype->matrix = matrix; // fake bold - if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) + if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) embolden = true; // underline metrics line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)); @@ -1196,7 +1196,7 @@ int QFontEngineFT::synthesized() const int s = 0; if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)) s = SynthesizedItalic; - if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD)) + if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD)) s |= SynthesizedBold; if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face)) s |= SynthesizedStretch; @@ -1283,13 +1283,22 @@ qreal QFontEngineFT::minRightBearing() const { if (rbearing == SHRT_MIN) { lbearing = rbearing = 0; - const QChar *ch = (const QChar *)(const void*)char_table; - QGlyphLayoutArray<char_table_entries> glyphs; + + const QChar *ch = reinterpret_cast<const QChar *>(char_table); + + glyph_t glyphs[char_table_entries]; + + QGlyphLayout g; + g.glyphs = glyphs; + g.numGlyphs = char_table_entries; int ng = char_table_entries; - stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly); + if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(ng == char_table_entries); + while (--ng) { - if (glyphs.glyphs[ng]) { - glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]); + if (glyphs[ng]) { + glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]); lbearing = qMin(lbearing, gi.x); rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width)); } @@ -1525,7 +1534,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs return false; } - bool mirrored = flags & QFontEngine::RightToLeft; int glyph_pos = 0; if (freetype->symbol_map) { FT_Face face = freetype->face; @@ -1561,8 +1569,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs FT_Face face = freetype->face; for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0; if (!glyphs->glyphs[glyph_pos]) { { @@ -1607,24 +1613,23 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono; if (g && g->format == acceptableFormat) { - glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); + glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); } else { if (!face) face = lockFace(); g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true); - glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) - : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round(); + glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) + : QFixed::fromFixed(face->glyph->metrics.horiAdvance); if (!cacheEnabled) delete g; } - glyphs->advances_y[i] = 0; } if (face) unlockFace(); if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances[i] = glyphs->advances[i].round(); } } diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index a04f4bd0ac..532ebaf8ff 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -121,7 +121,6 @@ public: }; enum ShaperFlag { - RightToLeft = 0x0001, DesignMetrics = 0x0002, GlyphIndicesOnly = 0x0004 }; diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp index 28b95bd509..cb40a5388a 100644 --- a/src/gui/text/qfontengine_qpa.cpp +++ b/src/gui/text/qfontengine_qpa.cpp @@ -353,13 +353,10 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); - bool mirrored = flags & QFontEngine::RightToLeft; int glyph_pos = 0; if (symbol) { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); @@ -368,8 +365,6 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph } else { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); @@ -399,8 +394,7 @@ void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFla glyphs->glyphs[i] = 0; continue; } - glyphs->advances_x[i] = g->advance; - glyphs->advances_y[i] = 0; + glyphs->advances[i] = g->advance; } } diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 1a66657cbd..2f4709afe4 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -458,12 +458,19 @@ int QFontMetrics::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return qRound(lb); } @@ -493,12 +500,19 @@ int QFontMetrics::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return qRound(rb); } @@ -538,15 +552,12 @@ int QFontMetrics::width(const QString &text, int len, int flags) const int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(numGlyphs); QFontEngine *engine = d->engineForScript(QChar::Script_Common); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) { - glyphs.resize(numGlyphs); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) + Q_UNREACHABLE(); QFixed width; for (int i = 0; i < numGlyphs; ++i) - width += glyphs.advances_x[i]; + width += glyphs.advances[i]; return qRound(width); } @@ -594,10 +605,20 @@ int QFontMetrics::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return qRound(glyphs.advances_x[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return qRound(advance); } /*! \obsolete @@ -639,10 +660,20 @@ int QFontMetrics::charWidth(const QString &text, int pos) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - width = qRound(glyphs.advances_x[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + width = qRound(advance); } return width; } @@ -708,10 +739,18 @@ QRect QFontMetrics::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height)); } @@ -1326,12 +1365,19 @@ qreal QFontMetricsF::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return lb; } @@ -1361,12 +1407,19 @@ qreal QFontMetricsF::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return rb; } @@ -1431,10 +1484,20 @@ qreal QFontMetricsF::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return glyphs.advances_x[0].toReal(); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return advance.toReal(); } /*! @@ -1496,10 +1559,18 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal()); } diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp index 152e15a54d..2109b16bb5 100644 --- a/src/gui/text/qfontsubset.cpp +++ b/src/gui/text/qfontsubset.cpp @@ -201,12 +201,22 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges) QVector<int> QFontSubset::getReverseMap() const { QVector<int> reverseMap(0x10000, 0); - QGlyphLayoutArray<10> glyphs; + + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.glyphs = &glyph; + glyphs.numGlyphs = 1; + for (uint uc = 0; uc < 0x10000; ++uc) { QChar ch(uc); - int nglyphs = 10; - fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - int idx = glyph_indices.indexOf(glyphs.glyphs[0]); + + int nglyphs = 1; + if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + int idx = glyph_indices.indexOf(glyph); if (idx >= 0 && !reverseMap.at(idx)) reverseMap[idx] = uc; } diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index d2e7df9c10..c09f27b665 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -397,13 +397,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, QFontEngine *fe = (QFontEngine *)font_data; Q_ASSERT(fe); - glyph_t glyphs[2] = { 0, 0 }; - - QGlyphLayout g; - g.numGlyphs = 2; - g.glyphs = glyphs; - - QChar chars[4]; + QChar chars[2]; int numChars = 0; if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) { chars[numChars++] = QChar(QChar::highSurrogate(unicode)); @@ -422,11 +416,14 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, } #endif - int numGlyphs = g.numGlyphs; - bool ok = fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly); - Q_ASSERT(ok); Q_UNUSED(ok) + QGlyphLayout g; + g.numGlyphs = numChars; + g.glyphs = glyph; - *glyph = g.glyphs[0]; + int numGlyphs = numChars; + if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); return true; } @@ -439,18 +436,16 @@ _hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data, QFontEngine *fe = (QFontEngine *)font_data; Q_ASSERT(fe); - QFixed advance_x; - QFixed advance_y; + QFixed advance; QGlyphLayout g; g.numGlyphs = 1; g.glyphs = &glyph; - g.advances_x = &advance_x; - g.advances_y = &advance_y; + g.advances = &advance; fe->recalcAdvances(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances_x[0].value(); + return advance.value(); } static hb_position_t @@ -490,18 +485,16 @@ _hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data, Q_ASSERT(fe); glyph_t glyphs[2] = { first_glyph, second_glyph }; - QFixed advance_x; - QFixed advance_y; + QFixed advance; QGlyphLayout g; g.numGlyphs = 2; g.glyphs = glyphs; - g.advances_x = &advance_x; - g.advances_y = &advance_y; + g.advances = &advance; fe->doKerning(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances_x[0].value(); + return advance.value(); } static hb_position_t @@ -710,7 +703,11 @@ _hb_qt_font_create(QFontEngine *fe) const int x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100; hb_font_set_funcs(font, hb_qt_get_font_funcs(), (void *)fe, NULL); +#ifdef Q_OS_MAC + hb_font_set_scale(font, QFixed(x_ppem).value(), QFixed(y_ppem).value()); +#else hb_font_set_scale(font, QFixed(x_ppem).value(), -QFixed(y_ppem).value()); +#endif hb_font_set_ppem(font, x_ppem, y_ppem); return font; diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 37610a9099..7936831e13 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -289,13 +289,11 @@ QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine Returns the font engine that can be used to render the font described by the font definition, \a fontDef, in the specified \a script. */ -QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) +QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - Q_UNUSED(script); - Q_UNUSED(handle); QByteArray *fileDataPtr = static_cast<QByteArray *>(handle); QFontEngineQPA *engine = new QFontEngineQPA(fontDef,*fileDataPtr); - //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family << script; + //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family; return engine; } diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index 6053f11051..5f2c9a74ba 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -97,7 +97,7 @@ public: virtual ~QPlatformFontDatabase(); virtual void populateFontDatabase(); virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual void releaseHandle(void *handle); diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index b1b910422c..449278df06 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -479,16 +479,8 @@ QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const QGlyphLayout glyphs; glyphs.numGlyphs = numGlyphs; glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - glyphIndexes.resize(numGlyphs); - - glyphs.numGlyphs = numGlyphs; - glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - return QVector<quint32>(); - } - } + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); glyphIndexes.resize(numGlyphs); return glyphIndexes; @@ -565,13 +557,12 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv if (!d->isValid() || numGlyphs <= 0) return false; + QVarLengthArray<QFixed> tmpAdvances(numGlyphs); + QGlyphLayout glyphs; glyphs.glyphs = const_cast<glyph_t *>(glyphIndexes); glyphs.numGlyphs = numGlyphs; - QVarLengthArray<QFixed> advances_x(numGlyphs); - QVarLengthArray<QFixed> advances_y(numGlyphs); - glyphs.advances_x = advances_x.data(); - glyphs.advances_y = advances_y.data(); + glyphs.advances = tmpAdvances.data(); bool design = layoutFlags & UseDesignMetrics; @@ -580,7 +571,7 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv d->fontEngine->doKerning(&glyphs, design ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlag(0)); for (int i=0; i<numGlyphs; ++i) - advances[i] = QPointF(glyphs.advances_x[i].toReal(), glyphs.advances_y[i].toReal()); + advances[i] = QPointF(tmpAdvances[i].toReal(), 0.0); return true; } diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index d12f3cccd8..ac9762b183 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -174,7 +174,6 @@ void QTextCursorPrivate::remove() } else { priv->remove(pos1, pos2-pos1, op); adjusted_anchor = anchor = position; - priv->finishEdit(); } } diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 4a34f0d3c3..fa54776b6d 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -551,6 +551,39 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option) } /*! + \property QTextDocument::baseUrl + \since 5.3 + \brief the base URL used to resolve relative resource URLs within the document. + + Resource URLs are resolved to be within the same directory as the target of the base + URL meaning any portion of the path after the last '/' will be ignored. + + \table + \header \li Base URL \li Relative URL \li Resolved URL + \row \li file:///path/to/content \li images/logo.png \li file:///path/to/images/logo.png + \row \li file:///path/to/content/ \li images/logo.png \li file:///path/to/content/images/logo.png + \row \li file:///path/to/content/index.html \li images/logo.png \li file:///path/to/content/images/logo.png + \row \li file:///path/to/content/images/ \li ../images/logo.png \li file:///path/to/content/images/logo.png + \endtable +*/ +QUrl QTextDocument::baseUrl() const +{ + Q_D(const QTextDocument); + return d->baseUrl; +} + +void QTextDocument::setBaseUrl(const QUrl &url) +{ + Q_D(QTextDocument); + if (d->baseUrl != url) { + d->baseUrl = url; + if (d->lout) + d->lout->documentChanged(0, 0, d->length()); + emit baseUrlChanged(url); + } +} + +/*! \since 4.8 The default cursor movement style is used by all QTextCursor objects @@ -1849,11 +1882,12 @@ void QTextDocument::print(QPagedPaintDevice *printer) const QVariant QTextDocument::resource(int type, const QUrl &name) const { Q_D(const QTextDocument); - QVariant r = d->resources.value(name); + const QUrl url = d->baseUrl.resolved(name); + QVariant r = d->resources.value(url); if (!r.isValid()) { - r = d->cachedResources.value(name); + r = d->cachedResources.value(url); if (!r.isValid()) - r = const_cast<QTextDocument *>(this)->loadResource(type, name); + r = const_cast<QTextDocument *>(this)->loadResource(type, url); } return r; } @@ -1924,27 +1958,29 @@ QVariant QTextDocument::loadResource(int type, const QUrl &name) } // if resource was not loaded try to load it here - if (!qobject_cast<QTextDocument *>(p) && r.isNull() && name.isRelative()) { - QUrl currentURL = d->url; + if (!qobject_cast<QTextDocument *>(p) && r.isNull()) { QUrl resourceUrl = name; - // For the second case QUrl can merge "#someanchor" with "foo.html" - // correctly to "foo.html#someanchor" - if (!(currentURL.isRelative() - || (currentURL.scheme() == QLatin1String("file") - && !QFileInfo(currentURL.toLocalFile()).isAbsolute())) - || (name.hasFragment() && name.path().isEmpty())) { - resourceUrl = currentURL.resolved(name); - } else { - // this is our last resort when current url and new url are both relative - // we try to resolve against the current working directory in the local - // file system. - QFileInfo fi(currentURL.toLocalFile()); - if (fi.exists()) { - resourceUrl = - QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name); - } else if (currentURL.isEmpty()) { - resourceUrl.setScheme(QLatin1String("file")); + if (name.isRelative()) { + QUrl currentURL = d->url; + // For the second case QUrl can merge "#someanchor" with "foo.html" + // correctly to "foo.html#someanchor" + if (!(currentURL.isRelative() + || (currentURL.scheme() == QLatin1String("file") + && !QFileInfo(currentURL.toLocalFile()).isAbsolute())) + || (name.hasFragment() && name.path().isEmpty())) { + resourceUrl = currentURL.resolved(name); + } else { + // this is our last resort when current url and new url are both relative + // we try to resolve against the current working directory in the local + // file system. + QFileInfo fi(currentURL.toLocalFile()); + if (fi.exists()) { + resourceUrl = + QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name); + } else if (currentURL.isEmpty()) { + resourceUrl.setScheme(QLatin1String("file")); + } } } @@ -2124,13 +2160,21 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format) html += QLatin1String("pt;"); attributesEmitted = true; } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) { - static const char * const sizeNames[] = { - "small", "medium", "large", "x-large", "xx-large" + static const char sizeNameData[] = + "small" "\0" + "medium" "\0" + "xx-large" ; + static const quint8 sizeNameOffsets[] = { + 0, // "small" + sizeof("small"), // "medium" + sizeof("small") + sizeof("medium") + 3, // "large" ) + sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large" + sizeof("small") + sizeof("medium"), // "xx-large" ) }; const char *name = 0; const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1; if (idx >= 0 && idx <= 4) { - name = sizeNames[idx]; + name = sizeNameData + sizeNameOffsets[idx]; } if (name) { html += QLatin1String(" font-size:"); diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index d8f52e9f98..854cb29ed9 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -47,6 +47,7 @@ #include <QtCore/qrect.h> #include <QtCore/qvariant.h> #include <QtGui/qfont.h> +#include <QtCore/qurl.h> QT_BEGIN_NAMESPACE @@ -63,7 +64,6 @@ class QTextFormat; class QTextFrame; class QTextBlock; class QTextCodec; -class QUrl; class QVariant; class QRectF; class QTextOption; @@ -116,6 +116,7 @@ class Q_GUI_EXPORT QTextDocument : public QObject Q_PROPERTY(int maximumBlockCount READ maximumBlockCount WRITE setMaximumBlockCount) Q_PROPERTY(qreal documentMargin READ documentMargin WRITE setDocumentMargin) QDOC_PROPERTY(QTextOption defaultTextOption READ defaultTextOption WRITE setDefaultTextOption) + Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged) public: explicit QTextDocument(QObject *parent = 0); @@ -258,6 +259,9 @@ public: QTextOption defaultTextOption() const; void setDefaultTextOption(const QTextOption &option); + QUrl baseUrl() const; + void setBaseUrl(const QUrl &url); + Qt::CursorMoveStyle defaultCursorMoveStyle() const; void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style); @@ -270,7 +274,7 @@ Q_SIGNALS: void modificationChanged(bool m); void cursorPositionChanged(const QTextCursor &cursor); void blockCountChanged(int newBlockCount); - + void baseUrlChanged(const QUrl &url); void documentLayoutChanged(); public Q_SLOTS: diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index 8d4cab30ae..fa22131c9e 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -355,6 +355,7 @@ public: QString url; qreal indentWidth; qreal documentMargin; + QUrl baseUrl; void mergeCachedResources(const QTextDocumentPrivate *priv); diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index df67fb581a..3bd1e2a801 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -489,7 +489,7 @@ void QTextHtmlImporter::import() && currentNode->id != Html_unknown) { hasBlock = false; - } else if (hasBlock) { + } else if (blockTagClosed && hasBlock) { // when collapsing subsequent block tags we need to clear the block format QTextBlockFormat blockFormat = currentNode->blockFormat; blockFormat.setIndent(indent); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index febdaaa86c..eb31c520ed 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,13 @@ 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.clear(); + QVector<QTextCharFormat> resolvedFormats(layoutData->items.count()); QVarLengthArray<int, 64> addFormatSortedByStart; addFormatSortedByStart.reserve(specialData->addFormats.count()); @@ -2958,21 +2953,24 @@ void QTextEngine::resolveAdditionalFormats() const currentFormats.remove(currentFormatIterator - currentFormats.begin()); ++endIt; } - QTextCharFormat format; + + QTextCharFormat &format = 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; + + specialData->resolvedFormats = resolvedFormats; } QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) @@ -3026,7 +3024,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; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index fb71ab40b8..1616a78937 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -190,11 +190,15 @@ Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE); struct QGlyphLayout { + enum { + SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint) + + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification) + }; + // init to 0 not needed, done when shaping QFixedPoint *offsets; // 8 bytes per element glyph_t *glyphs; // 4 bytes per element - QFixed *advances_x; // 4 bytes per element - QFixed *advances_y; // 4 bytes per element + QFixed *advances; // 4 bytes per element QGlyphJustification *justifications; // 4 bytes per element QGlyphAttributes *attributes; // 2 bytes per element @@ -208,9 +212,7 @@ struct QGlyphLayout int offset = totalGlyphs * sizeof(QFixedPoint); glyphs = reinterpret_cast<glyph_t *>(address + offset); offset += totalGlyphs * sizeof(glyph_t); - advances_x = reinterpret_cast<QFixed *>(address + offset); - offset += totalGlyphs * sizeof(QFixed); - advances_y = reinterpret_cast<QFixed *>(address + offset); + advances = reinterpret_cast<QFixed *>(address + offset); offset += totalGlyphs * sizeof(QFixed); justifications = reinterpret_cast<QGlyphJustification *>(address + offset); offset += totalGlyphs * sizeof(QGlyphJustification); @@ -221,8 +223,7 @@ struct QGlyphLayout inline QGlyphLayout mid(int position, int n = -1) const { QGlyphLayout copy = *this; copy.glyphs += position; - copy.advances_x += position; - copy.advances_y += position; + copy.advances += position; copy.offsets += position; copy.justifications += position; copy.attributes += position; @@ -233,27 +234,20 @@ struct QGlyphLayout return copy; } - static inline int spaceNeededForGlyphLayout(int totalGlyphs) { - return totalGlyphs * (sizeof(glyph_t) + sizeof(QGlyphAttributes) - + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint) - + sizeof(QGlyphJustification)); - } - inline QFixed effectiveAdvance(int item) const - { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } + { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } inline void clear(int first = 0, int last = -1) { if (last == -1) last = numGlyphs; if (first == 0 && last == numGlyphs && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) { - memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs)); + memset(offsets, 0, (numGlyphs * SpaceNeeded)); } else { const int num = last - first; memset(offsets + first, 0, num * sizeof(QFixedPoint)); memset(glyphs + first, 0, num * sizeof(glyph_t)); - memset(advances_x + first, 0, num * sizeof(QFixed)); - memset(advances_y + first, 0, num * sizeof(QFixed)); + memset(advances + first, 0, num * sizeof(QFixed)); memset(justifications + first, 0, num * sizeof(QGlyphJustification)); memset(attributes + first, 0, num * sizeof(QGlyphAttributes)); } @@ -272,7 +266,7 @@ private: typedef QVarLengthArray<void *> Array; public: QVarLengthGlyphLayoutArray(int totalGlyphs) - : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1) + : Array((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1) , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs) { memset(Array::data(), 0, Array::size() * sizeof(void *)); @@ -280,7 +274,7 @@ public: void resize(int totalGlyphs) { - Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1); + Array::resize((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1); *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs); memset(Array::data(), 0, Array::size() * sizeof(void *)); @@ -297,10 +291,7 @@ public: } private: - void *buffer[(N * (sizeof(glyph_t) + sizeof(QGlyphAttributes) - + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint) - + sizeof(QGlyphJustification))) - / sizeof(void *) + 1]; + void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1]; }; struct QScriptItem; @@ -449,7 +440,6 @@ public: typedef QList<ItemDecoration> ItemDecorationList; - QTextEngine(LayoutData *data); QTextEngine(); QTextEngine(const QString &str, const QFont &f); ~QTextEngine(); @@ -553,6 +543,7 @@ public: mutable QScriptLineArray lines; +private: struct FontEngineCache { FontEngineCache(); mutable QFontEngine *prevFontEngine; @@ -570,6 +561,7 @@ public: }; mutable FontEngineCache feCache; +public: QString text; mutable QFont fnt; #ifndef QT_NO_RAWFONT @@ -611,7 +603,8 @@ public: void setPreeditArea(int position, const QString &text); inline bool hasFormats() const { return block.docHandle() || (specialData && !specialData->addFormats.isEmpty()); } - QList<QTextLayout::FormatRange> additionalFormats() const; + inline QList<QTextLayout::FormatRange> additionalFormats() const + { return specialData ? specialData->addFormats : QList<QTextLayout::FormatRange>(); } void setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList); private: @@ -621,8 +614,7 @@ private: int preeditPosition; QString preeditText; QList<QTextLayout::FormatRange> addFormats; - QVector<int> addFormatIndices; - QVector<int> resolvedFormatIndices; + QVector<QTextCharFormat> resolvedFormats; // only used when no docHandle is available QScopedPointer<QTextFormatCollection> formats; }; diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 2389427da0..4854af0d01 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -524,7 +524,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) \value BlockFormat The object formats a text block \value CharFormat The object formats a single character \value ListFormat The object formats a list - \value TableFormat The object formats a table + \omitvalue TableFormat Unused Value, a table's FormatType is FrameFormat. \value FrameFormat The object formats a frame \value UserFormat @@ -706,6 +706,15 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) */ /*! + \fn bool QTextFormat::isEmpty() const + \since 5.3 + + Returns true if the format does not store any properties; false otherwise. + + \sa propertyCount(), properties() +*/ + +/*! \fn bool QTextFormat::isCharFormat() const Returns \c true if this text format is a \c CharFormat; otherwise @@ -1870,36 +1879,93 @@ QStringList QTextCharFormat::anchorNames() const */ /*! + \enum QTextCharFormat::FontPropertiesInheritanceBehavior + \since 5.3 + + This enum specifies how the setFont() function should behave with + respect to unset font properties. + + \value FontPropertiesSpecifiedOnly If a property is not explicitly set, do not + change the text format's property value. + \value FontPropertiesAll If a property is not explicitly set, override the + text format's property with a default value. + + \sa setFont() +*/ + +/*! + \overload + Sets the text format's \a font. + + \sa font() */ void QTextCharFormat::setFont(const QFont &font) { - setFontFamily(font.family()); + setFont(font, FontPropertiesAll); +} - const qreal pointSize = font.pointSizeF(); - if (pointSize > 0) { - setFontPointSize(pointSize); - } else { - const int pixelSize = font.pixelSize(); - if (pixelSize > 0) - setProperty(QTextFormat::FontPixelSize, pixelSize); +/*! + \since 5.3 + + Sets the text format's \a font. + + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is treated like as it were set with default value; + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is ignored and the respective property value + remains unchanged. + + \sa font() +*/ +void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior) +{ + const uint mask = behavior == FontPropertiesAll ? uint(QFont::AllPropertiesResolved) + : font.resolve(); + + if (mask & QFont::FamilyResolved) + setFontFamily(font.family()); + if (mask & QFont::SizeResolved) { + const qreal pointSize = font.pointSizeF(); + if (pointSize > 0) { + setFontPointSize(pointSize); + } else { + const int pixelSize = font.pixelSize(); + if (pixelSize > 0) + setProperty(QTextFormat::FontPixelSize, pixelSize); + } } - setFontWeight(font.weight()); - setFontItalic(font.italic()); - setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); - setFontOverline(font.overline()); - setFontStrikeOut(font.strikeOut()); - setFontFixedPitch(font.fixedPitch()); - setFontCapitalization(font.capitalization()); - setFontWordSpacing(font.wordSpacing()); - setFontLetterSpacingType(font.letterSpacingType()); - setFontLetterSpacing(font.letterSpacing()); - setFontStretch(font.stretch()); - setFontStyleHint(font.styleHint()); - setFontStyleStrategy(font.styleStrategy()); - setFontHintingPreference(font.hintingPreference()); - setFontKerning(font.kerning()); + if (mask & QFont::WeightResolved) + setFontWeight(font.weight()); + if (mask & QFont::StyleResolved) + setFontItalic(font.style() != QFont::StyleNormal); + if (mask & QFont::UnderlineResolved) + setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); + if (mask & QFont::OverlineResolved) + setFontOverline(font.overline()); + if (mask & QFont::StrikeOutResolved) + setFontStrikeOut(font.strikeOut()); + if (mask & QFont::FixedPitchResolved) + setFontFixedPitch(font.fixedPitch()); + if (mask & QFont::CapitalizationResolved) + setFontCapitalization(font.capitalization()); + if (mask & QFont::LetterSpacingResolved) + setFontWordSpacing(font.wordSpacing()); + if (mask & QFont::LetterSpacingResolved) { + setFontLetterSpacingType(font.letterSpacingType()); + setFontLetterSpacing(font.letterSpacing()); + } + if (mask & QFont::StretchResolved) + setFontStretch(font.stretch()); + if (mask & QFont::StyleHintResolved) + setFontStyleHint(font.styleHint()); + if (mask & QFont::StyleStrategyResolved) + setFontStyleStrategy(font.styleStrategy()); + if (mask & QFont::HintingPreferenceResolved) + setFontHintingPreference(font.hintingPreference()); + if (mask & QFont::KerningResolved) + setFontKerning(font.kerning()); } /*! @@ -3376,19 +3442,6 @@ bool QTextFormatCollection::hasFormatCached(const QTextFormat &format) const return false; } -QTextFormat QTextFormatCollection::objectFormat(int objectIndex) const -{ - if (objectIndex == -1) - return QTextFormat(); - return format(objFormats.at(objectIndex)); -} - -void QTextFormatCollection::setObjectFormat(int objectIndex, const QTextFormat &f) -{ - const int formatIndex = indexForFormat(f); - objFormats[objectIndex] = formatIndex; -} - int QTextFormatCollection::objectFormatIndex(int objectIndex) const { if (objectIndex == -1) diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index 2098369811..5369001a03 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -141,7 +141,9 @@ public: BlockFormat = 1, CharFormat = 2, ListFormat = 3, +#if QT_DEPRECATED_SINCE(5, 3) TableFormat = 4, +#endif FrameFormat = 5, UserFormat = 100 @@ -295,6 +297,7 @@ public: void merge(const QTextFormat &other); inline bool isValid() const { return type() != InvalidFormat; } + inline bool isEmpty() const { return propertyCount() == 0; } int type() const; @@ -407,7 +410,13 @@ public: QTextCharFormat(); bool isValid() const { return isCharFormat(); } - void setFont(const QFont &font); + + enum FontPropertiesInheritanceBehavior { + FontPropertiesSpecifiedOnly, + FontPropertiesAll + }; + void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior); + void setFont(const QFont &font); // ### Qt6: Merge with above QFont font() const; inline void setFontFamily(const QString &family) diff --git a/src/gui/text/qtextformat_p.h b/src/gui/text/qtextformat_p.h index 6b2958a4b6..e3998d4f3f 100644 --- a/src/gui/text/qtextformat_p.h +++ b/src/gui/text/qtextformat_p.h @@ -68,8 +68,10 @@ public: QTextFormatCollection(const QTextFormatCollection &rhs); QTextFormatCollection &operator=(const QTextFormatCollection &rhs); - QTextFormat objectFormat(int objectIndex) const; - void setObjectFormat(int objectIndex, const QTextFormat &format); + inline QTextFormat objectFormat(int objectIndex) const + { return format(objectFormatIndex(objectIndex)); } + inline void setObjectFormat(int objectIndex, const QTextFormat &format) + { setObjectFormatIndex(objectIndex, indexForFormat(format)); } int objectFormatIndex(int objectIndex) const; void setObjectFormatIndex(int objectIndex, int formatIndex); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 3cb61b9eae..e8a02c44b2 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1361,33 +1361,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration> QFont f; int adjustment = -255; extractor.extractFont(&f, &adjustment); - if (f.resolve() & QFont::SizeResolved) { - if (f.pointSize() > 0) { - charFormat.setFontPointSize(f.pointSize()); - } else if (f.pixelSize() > 0) { - charFormat.setProperty(QTextFormat::FontPixelSize, f.pixelSize()); - } - } - if (f.resolve() & QFont::StyleResolved) - charFormat.setFontItalic(f.style() != QFont::StyleNormal); - - if (f.resolve() & QFont::WeightResolved) - charFormat.setFontWeight(f.weight()); - - if (f.resolve() & QFont::FamilyResolved) - charFormat.setFontFamily(f.family()); - - if (f.resolve() & QFont::UnderlineResolved) - charFormat.setUnderlineStyle(f.underline() ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline); - - if (f.resolve() & QFont::OverlineResolved) - charFormat.setFontOverline(f.overline()); - - if (f.resolve() & QFont::StrikeOutResolved) - charFormat.setFontStrikeOut(f.strikeOut()); - - if (f.resolve() & QFont::CapitalizationResolved) - charFormat.setFontCapitalization(f.capitalization()); + charFormat.setFont(f, QTextCharFormat::FontPropertiesSpecifiedOnly); if (adjustment >= -1) charFormat.setProperty(QTextFormat::FontSizeAdjustment, adjustment); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 66341e186a..0c9866c6cf 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -239,9 +239,7 @@ int QTextInlineObject::formatIndex() const */ QTextFormat QTextInlineObject::format() const { - if (!eng->block.docHandle()) - return QTextFormat(); - return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm])); + return eng->format(&eng->layoutData->items[itm]); } /*! @@ -1693,7 +1691,7 @@ static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &gly } while (pos < end && logClusters[pos] == glyphPosition); do { // calculate the textWidth for the rest of the current cluster. if (!glyphs.attributes[glyphPosition].dontPrint) - line.textWidth += glyphs.advances_x[glyphPosition]; + line.textWidth += glyphs.advances[glyphPosition]; ++glyphPosition; } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); @@ -1812,9 +1810,10 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.whiteSpaceOrObject = true; lbh.tmpData.length++; - QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); - if (eng->block.docHandle()) - eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); + if (eng->block.docHandle()) { + QTextInlineObject inlineObject(item, eng); + eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format()); + } lbh.tmpData.textWidth += current.width; @@ -1871,9 +1870,9 @@ void QTextLine::layout_helper(int maxGlyphs) // and thus become invisible again. // if (line.length) - lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]]; + lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; else if (breakany) - lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]]; + lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; } // The actual width of the text needs to take the right bearing into account. The @@ -2249,14 +2248,12 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const if (relativeFrom != (iterator.itemStart - si.position) && !rtl) { for (int i=itemGlyphsStart; i<glyphsStart; ++i) { QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); - pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(), - glyphLayout.advances_y[i].toReal()); + pos.rx() += (glyphLayout.advances[i] + justification).toReal(); } } else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) { for (int i=itemGlyphsEnd; i>glyphsEnd; --i) { QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); - pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(), - glyphLayout.advances_y[i].toReal()); + pos.rx() += (glyphLayout.advances[i] + justification).toReal(); } } @@ -2295,10 +2292,8 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which), subLayout, pos, subFlags, x, width)); - for (int i = 0; i < subLayout.numGlyphs; i++) { - pos += QPointF(subLayout.advances_x[i].toReal(), - subLayout.advances_y[i].toReal()); - } + for (int i = 0; i < subLayout.numGlyphs; ++i) + pos.rx() += subLayout.advances[i].toReal(); if (rtl) end = start; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index d1a39c6ab6..bd1e970583 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1233,6 +1233,56 @@ QString QTextBlock::text() const return text; } +/*! + \since 5.3 + + Returns the block's text format options as a list of continuous ranges + of QTextCharFormat. The range's character format is used when inserting text + within the range boundaries. + + \sa charFormat(), blockFormat() +*/ +QList<QTextLayout::FormatRange> QTextBlock::textFormats() const +{ + QList<QTextLayout::FormatRange> formats; + if (!p || !n) + return formats; + + const QTextFormatCollection *formatCollection = p->formatCollection(); + + int start = 0; + int cur = start; + int format = -1; + + const int pos = position(); + QTextDocumentPrivate::FragmentIterator it = p->find(pos); + QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char + for (; it != end; ++it) { + const QTextFragmentData * const frag = it.value(); + if (format != it.value()->format) { + if (cur - start > 0) { + QTextLayout::FormatRange range; + range.start = start; + range.length = cur - start; + range.format = formatCollection->charFormat(format); + formats.append(range); + } + + format = frag->format; + start = cur; + } + cur += frag->size_array[0]; + } + if (cur - start > 0) { + QTextLayout::FormatRange range; + range.start = start; + range.length = cur - start; + range.format = formatCollection->charFormat(format); + formats.append(range); + } + + return formats; +} /*! Returns the text document this text block belongs to, or 0 if the diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index 87f2cf6197..6a127f0315 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -44,6 +44,7 @@ #include <QtCore/qobject.h> #include <QtGui/qtextformat.h> +#include <QtGui/qtextlayout.h> #include <QtGui/qglyphrun.h> QT_BEGIN_NAMESPACE @@ -55,7 +56,6 @@ class QTextDocumentPrivate; class QTextCursor; class QTextBlock; class QTextFragment; -class QTextLayout; class QTextList; class Q_GUI_EXPORT QTextObject : public QObject @@ -223,6 +223,8 @@ public: QString text() const; + QList<QTextLayout::FormatRange> textFormats() const; + const QTextDocument *document() const; QTextList *textList() const; |