diff options
Diffstat (limited to 'src/gui/text')
-rw-r--r-- | src/gui/text/qabstracttextdocumentlayout.cpp | 24 | ||||
-rw-r--r-- | src/gui/text/qabstracttextdocumentlayout.h | 1 | ||||
-rw-r--r-- | src/gui/text/qfontdatabase.cpp | 56 | ||||
-rw-r--r-- | src/gui/text/qfontdatabase.h | 10 | ||||
-rw-r--r-- | src/gui/text/qfontdatabase_qpa.cpp | 2 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 97 | ||||
-rw-r--r-- | src/gui/text/qfontengine_ft.cpp | 63 | ||||
-rw-r--r-- | src/gui/text/qfontengine_ft_p.h | 9 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 9 | ||||
-rw-r--r-- | src/gui/text/qfontengine_qpf.cpp | 3 | ||||
-rw-r--r-- | src/gui/text/qfontsubset.cpp | 6 | ||||
-rw-r--r-- | src/gui/text/qplatformfontdatabase.cpp | 13 | ||||
-rw-r--r-- | src/gui/text/qplatformfontdatabase.h | 2 | ||||
-rw-r--r-- | src/gui/text/qtextdocument.h | 2 | ||||
-rw-r--r-- | src/gui/text/qtextdocumentwriter.cpp | 4 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 242 | ||||
-rw-r--r-- | src/gui/text/qtextengine_p.h | 47 |
17 files changed, 322 insertions, 268 deletions
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp index b7b8e919ad..b8f5aa70a9 100644 --- a/src/gui/text/qabstracttextdocumentlayout.cpp +++ b/src/gui/text/qabstracttextdocumentlayout.cpp @@ -412,8 +412,6 @@ QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout() } /*! - \fn void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component) - Registers the given \a component as a handler for items of the given \a objectType. \note registerHandler() has to be called once for each object type. This @@ -422,7 +420,7 @@ QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout() The text document layout does not take ownership of \c component. */ -void QAbstractTextDocumentLayout::registerHandler(int formatType, QObject *component) +void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component) { Q_D(QAbstractTextDocumentLayout); @@ -435,7 +433,25 @@ void QAbstractTextDocumentLayout::registerHandler(int formatType, QObject *compo QTextObjectHandler h; h.iface = iface; h.component = component; - d->handlers.insert(formatType, h); + d->handlers.insert(objectType, h); +} + +/*! + \since 5.2 + + Unregisters the given \a component as a handler for items of the given \a objectType, or + any handler if the \a component is not specified. +*/ +void QAbstractTextDocumentLayout::unregisterHandler(int objectType, QObject *component) +{ + Q_D(QAbstractTextDocumentLayout); + + HandlerHash::iterator it = d->handlers.find(objectType); + if (it != d->handlers.end() && (!component || component == it->component)) { + if (component) + disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*))); + d->handlers.erase(it); + } } /*! diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h index 95733f5da7..4bae631b9c 100644 --- a/src/gui/text/qabstracttextdocumentlayout.h +++ b/src/gui/text/qabstracttextdocumentlayout.h @@ -98,6 +98,7 @@ public: QTextDocument *document() const; void registerHandler(int objectType, QObject *component); + void unregisterHandler(int objectType, QObject *component = 0); QTextObjectInterface *handlerForObject(int objectType) const; Q_SIGNALS: diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 54b4629ca0..6da103e931 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -53,9 +53,11 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformfontdatabase.h> +#include <qpa/qplatformtheme.h> #include <stdlib.h> #include <limits.h> +#include <algorithm> // #define QFONTDATABASE_DEBUG @@ -1082,6 +1084,17 @@ QFontDatabase::QFontDatabase() */ /*! + \enum QFontDatabase::SystemFont + + \value GeneralFont The default system font. + \value FixedFont The fixed font that the system recommends. + \value TitleFont The system standard font for titles. + \value SmallestReadableFont The smallest readable system font. + + \since 5.2 +*/ + +/*! Returns a sorted list of the available writing systems. This is list generated from information about all installed fonts on the system. @@ -1107,7 +1120,7 @@ QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const list.append(writingSystem); } } - qSort(list); + std::sort(list.begin(), list.end()); return list; } @@ -1399,7 +1412,7 @@ QList<int> QFontDatabase::pointSizes(const QString &family, if (smoothScalable) return standardSizes(); - qSort(sizes); + std::sort(sizes.begin(), sizes.end()); return sizes; } @@ -1502,7 +1515,7 @@ QList<int> QFontDatabase::smoothSizes(const QString &family, if (smoothScalable) return QFontDatabase::standardSizes(); - qSort(sizes); + std::sort(sizes.begin(), sizes.end()); return sizes; } @@ -2090,6 +2103,43 @@ QStringList QFontDatabase::applicationFontFamilies(int id) } /*! + \since 5.2 + + Returns the most adequate font for a given \a type case for proper integration + with the system's look and feel. + + \sa QGuiApplication::font() +*/ + +QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type) +{ + const QFont *font = 0; + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + switch (type) { + case GeneralFont: + font = theme->font(QPlatformTheme::SystemFont); + break; + case FixedFont: + font = theme->font(QPlatformTheme::FixedFont); + break; + case TitleFont: + font = theme->font(QPlatformTheme::TitleBarFont); + break; + case SmallestReadableFont: + font = theme->font(QPlatformTheme::MiniFont); + break; + } + } + + if (font) + return *font; + else if (QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration()) + return integration->fontDatabase()->defaultFont(); + else + return QFont(); +} + +/*! \fn bool QFontDatabase::removeApplicationFont(int id) \since 4.2 diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 05f1a85f24..bd603c3c4a 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -60,6 +60,7 @@ class Q_GUI_EXPORT QFontDatabase { Q_GADGET Q_ENUMS(WritingSystem) + Q_ENUMS(SystemFont) public: // do not re-order or delete entries from this enum without updating the // QPF2 format and makeqpf!! @@ -106,6 +107,13 @@ public: WritingSystemsCount }; + enum SystemFont { + GeneralFont, + FixedFont, + TitleFont, + SmallestReadableFont + }; + static QList<int> standardSizes(); QFontDatabase(); @@ -144,6 +152,8 @@ public: static bool supportsThreadedFontRendering(); + static QFont systemFont(SystemFont type); + private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index 62b99968bc..8e6ad7cd97 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -85,7 +85,7 @@ Q_GUI_EXPORT void qt_registerFont(const QString &familyName, const QString &sty size->handle = handle; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias) +void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias) { if (alias.isEmpty()) return; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 1ce70c6d83..9e6b8d6ffd 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -50,6 +50,8 @@ #include <qendian.h> #include <private/qharfbuzz_p.h> +#include <algorithm> + QT_BEGIN_NAMESPACE static inline bool qtransform_equals_no_translate(const QTransform &a, const QTransform &b) @@ -71,11 +73,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr // Harfbuzz helper functions +Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t)); +Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed)); + static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft) { QFontEngine *fe = (QFontEngine *)font->userData; - QVarLengthGlyphLayoutArray qglyphs(*numGlyphs); + QGlyphLayout qglyphs; + qglyphs.numGlyphs = *numGlyphs; + qglyphs.glyphs = glyphs; QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); if (rightToLeft) @@ -84,28 +91,23 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint int nGlyphs = *numGlyphs; bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags); *numGlyphs = nGlyphs; - if (!result) - return false; - - for (hb_uint32 i = 0; i < *numGlyphs; ++i) - glyphs[i] = qglyphs.glyphs[i]; - return true; + return result; } static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags) { QFontEngine *fe = (QFontEngine *)font->userData; - QVarLengthGlyphLayoutArray qglyphs(numGlyphs); + QVarLengthArray<QFixed> advances_y(numGlyphs); - for (hb_uint32 i = 0; i < numGlyphs; ++i) - qglyphs.glyphs[i] = glyphs[i]; + 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 fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0)); - - for (hb_uint32 i = 0; i < numGlyphs; ++i) - advances[i] = qglyphs.advances_x[i].value(); } static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length) @@ -143,7 +145,7 @@ int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFix Q_UNUSED(xpos) Q_UNUSED(ypos) Q_UNUSED(nPoints) - return HB_Err_Not_Covered; + return Err_Not_Covered; } static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints) @@ -203,17 +205,6 @@ QFontEngine::QFontEngine() fsType = 0; symbol = false; - { - HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec)); - Q_CHECK_PTR(hbFont); - memset(hbFont, 0, sizeof(HB_FontRec)); - hbFont->klass = &hb_fontClass; - hbFont->userData = this; - - font_ = (void *)hbFont; - font_destroy_func = free; - } - glyphFormat = -1; m_subPixelPositionCount = 0; @@ -262,8 +253,12 @@ QFixed QFontEngine::underlinePosition() const void *QFontEngine::harfbuzzFont() const { - HB_FontRec *hbFont = (HB_FontRec *)font_; - if (!hbFont->x_ppem) { + if (!font_) { + HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec)); + Q_CHECK_PTR(hbFont); + hbFont->klass = &hb_fontClass; + hbFont->userData = const_cast<QFontEngine *>(this); + qint64 emSquare = emSquareSize().truncate(); Q_ASSERT(emSquare == emSquareSize().toInt()); // ensure no truncation if (emSquare == 0) @@ -273,6 +268,9 @@ void *QFontEngine::harfbuzzFont() const // same as QFixed(x)/QFixed(emSquare) but without int32 overflow for x hbFont->x_scale = (((qint64)hbFont->x_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare; hbFont->y_scale = (((qint64)hbFont->y_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare; + + font_ = (void *)hbFont; + font_destroy_func = free; } return font_; } @@ -973,7 +971,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor) } } end: - qSort(kerning_pairs); + std::sort(kerning_pairs.begin(), kerning_pairs.end()); // for (int i = 0; i < kerning_pairs.count(); ++i) // qDebug() << 'i' << i << "left_right" << hex << kerning_pairs.at(i).left_right; } @@ -1439,10 +1437,12 @@ 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) { - QGlyphLayoutInstance tmp; - if (!(flags & GlyphIndicesOnly)) - tmp = glyphs->instance(glyph_pos); - for (int x=1; x < engines.size(); ++x) { + QFixedPoint tmpAdvance; + if (!(flags & GlyphIndicesOnly)) { + tmpAdvance.x = glyphs->advances_x[glyph_pos]; + tmpAdvance.y = glyphs->advances_y[glyph_pos]; + } + for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) { if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4)) continue; @@ -1455,10 +1455,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, if (engine->type() == Box) continue; - if (!(flags & GlyphIndicesOnly)) { + if (!(flags & GlyphIndicesOnly)) glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0; - glyphs->offsets[glyph_pos] = QFixedPoint(); - } int num = 2; QGlyphLayout offs = glyphs->mid(glyph_pos, num); engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags); @@ -1471,8 +1469,10 @@ 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]) - glyphs->setInstance(glyph_pos, tmp); + if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) { + glyphs->advances_x[glyph_pos] = tmpAdvance.x; + glyphs->advances_y[glyph_pos] = tmpAdvance.y; + } } if (surrogate) @@ -1774,22 +1774,27 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) if (engine(0)->canRender(string, len)) return true; - QVarLengthGlyphLayoutArray glyphs(len); int nglyphs = len; - if (!stringToCMap(string, len, &glyphs, &nglyphs, GlyphIndicesOnly)) { + + QVarLengthArray<glyph_t> glyphs(nglyphs); + + QGlyphLayout g; + g.numGlyphs = nglyphs; + g.glyphs = glyphs.data(); + if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) { glyphs.resize(nglyphs); - stringToCMap(string, len, &glyphs, &nglyphs, GlyphIndicesOnly); + 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"); } - bool allExist = true; for (int i = 0; i < nglyphs; i++) { - if (!glyphs.glyphs[i]) { - allExist = false; - break; - } + if (g.glyphs[i] == 0) + return false; } - return allExist; + return true; } /* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code. diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 7b4925a9c8..cad9b02f41 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -46,8 +46,6 @@ #include "qfontengine_ft_p.h" #include "private/qimage_p.h" -#include <private/qharfbuzz_p.h> - #ifndef QT_NO_FREETYPE #include "qfile.h" @@ -118,24 +116,6 @@ QT_BEGIN_NAMESPACE #define TRUNC(x) ((x) >> 6) #define ROUND(x) (((x)+32) & -64) -static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length) -{ -#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103 - FT_Face face = (FT_Face)font; - FT_ULong ftlen = *length; - FT_Error error = 0; - - if ( !FT_IS_SFNT(face) ) - return HB_Err_Invalid_Argument; - - error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen); - *length = ftlen; - return (HB_Error)error; -#else - return HB_Err_Invalid_Argument; -#endif -} - // -------------------------- Freetype support ------------------------------ class QtFreetypeData @@ -191,19 +171,19 @@ int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QF return error; if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) - return HB_Err_Invalid_SubTable; + return Err_Invalid_SubTable; *nPoints = face->glyph->outline.n_points; if (!(*nPoints)) - return HB_Err_Ok; + return Err_Ok; if (point > *nPoints) - return HB_Err_Invalid_SubTable; + return Err_Invalid_SubTable; *xpos = QFixed::fromFixed(face->glyph->outline.points[point].x); *ypos = QFixed::fromFixed(face->glyph->outline.points[point].y); - return HB_Err_Ok; + return Err_Ok; } extern QByteArray qt_fontdata_from_index(int); @@ -260,11 +240,8 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, } newFreetype->face = face; - HB_Face hbFace = qHBNewFace(face, hb_getSFntTable); - Q_CHECK_PTR(hbFace); - if (hbFace->font_for_init != 0) - hbFace = qHBLoadFace(hbFace); - newFreetype->hbFace = (void *)hbFace; + newFreetype->hbFace = 0; + newFreetype->hbFace_destroy_func = 0; newFreetype->ref.store(1); newFreetype->xsize = 0; @@ -319,7 +296,10 @@ void QFreetypeFace::release(const QFontEngine::FaceId &face_id) { QtFreetypeData *freetypeData = qt_getFreetypeData(); if (!ref.deref()) { - qHBFreeFace((HB_Face)hbFace); + if (hbFace && hbFace_destroy_func) { + hbFace_destroy_func(hbFace); + hbFace = 0; + } FT_Done_Face(face); if(freetypeData->faces.contains(face_id)) freetypeData->faces.take(face_id); @@ -695,8 +675,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) { symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive)); } - // ##### - ((HB_Face)freetype->hbFace)->isSymbolFont = symbol; lbearing = rbearing = SHRT_MIN; freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing); @@ -734,18 +712,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, if (line_thickness < 1) line_thickness = 1; - HB_FontRec *hbFont = (HB_FontRec *)font_; - hbFont->x_ppem = face->size->metrics.x_ppem; - hbFont->y_ppem = face->size->metrics.y_ppem; - hbFont->x_scale = face->size->metrics.x_scale; - hbFont->y_scale = face->size->metrics.y_scale; - - // ### - if (face_ && face_destroy_func) - face_destroy_func(face_); - face_ = freetype->hbFace; - face_destroy_func = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it - metrics = face->size->metrics; /* @@ -773,6 +739,15 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, fontDef.styleName = QString::fromUtf8(face->style_name); + if (!freetype->hbFace) { + freetype->hbFace = harfbuzzFace(); + freetype->hbFace_destroy_func = face_destroy_func; + } else { + Q_ASSERT(!face_); + face_ = freetype->hbFace; + } + face_destroy_func = 0; // we share the HB face in QFreeTypeFace, so do not let ~QFontEngine() destroy it + unlockFace(); fsType = freetype->fsType(); diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index bd4c855b91..084ef6cea3 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -75,11 +75,12 @@ class QFontEngineFTRawFont; class QFontconfigDatabase; /* - * This struct represents one font file on disk (like Arial.ttf) and is shared between all the font engines + * This class represents one font file on disk (like Arial.ttf) and is shared between all the font engines * that show this font file (at different pixel sizes). */ -struct QFreetypeFace +class QFreetypeFace { +public: void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing); QFontEngine::Properties properties() const; bool getSfntTable(uint tag, uchar *buffer, uint *length) const; @@ -99,7 +100,6 @@ struct QFreetypeFace } FT_Face face; - void *hbFace; int xsize; // 26.6 int ysize; // 26.6 FT_Matrix matrix; @@ -124,6 +124,9 @@ private: QAtomicInt ref; QMutex _lock; QByteArray fontData; + + void *hbFace; + qt_destroy_func_t hbFace_destroy_func; }; // If this is exported this breaks compilation of the windows diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 855f0099ff..4427000d03 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -75,6 +75,15 @@ struct QGlyphLayout; ((quint32)(ch4)) \ ) +// ### this only used in getPointInOutline(), refactor it and then remove these magic numbers +enum HB_Compat_Error { + Err_Ok = 0x0000, + Err_Not_Covered = 0xFFFF, + Err_Invalid_Argument = 0x1A66, + Err_Invalid_SubTable_Format = 0x157F, + Err_Invalid_SubTable = 0x1570 +}; + typedef void (*qt_destroy_func_t) (void *user_data); class Q_GUI_EXPORT QFontEngine : public QObject diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp index def671c62f..78bc3f871a 100644 --- a/src/gui/text/qfontengine_qpf.cpp +++ b/src/gui/text/qfontengine_qpf.cpp @@ -50,7 +50,6 @@ #include <QtCore/qbuffer.h> #if !defined(QT_NO_FREETYPE) #include "private/qfontengine_ft_p.h" -#include <private/qharfbuzz_p.h> #endif #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -858,7 +857,7 @@ void QFontEngineQPF::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) int QFontEngineQPF::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) { if (!freetype) - return HB_Err_Not_Covered; + return Err_Not_Covered; lockFace(); int result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints); unlockFace(); diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp index 3c39272d11..01ae5888e2 100644 --- a/src/gui/text/qfontsubset.cpp +++ b/src/gui/text/qfontsubset.cpp @@ -48,6 +48,8 @@ #include "qfontsubset_agl.cpp" +#include <algorithm> + QT_BEGIN_NAMESPACE // This map is used for symbol fonts to get the correct glyph names for the latin range @@ -998,7 +1000,7 @@ static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QLis { const int max_size_small = 65536*2; QList<QTtfGlyph> glyphs = _glyphs; - qSort(glyphs); + std::sort(glyphs.begin(), glyphs.end()); Q_ASSERT(tables.maxp.numGlyphs == glyphs.at(glyphs.size()-1).index + 1); int nGlyphs = tables.maxp.numGlyphs; @@ -1076,7 +1078,7 @@ static QByteArray bindFont(const QList<QTtfTable>& _tables) { QList<QTtfTable> tables = _tables; - qSort(tables); + std::sort(tables.begin(), tables.end()); QByteArray font; const int header_size = sizeof(qint32) + 4*sizeof(quint16); diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 4399aff9da..293535a2e1 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -53,6 +53,8 @@ extern void qt_registerFont(const QString &familyname, const QString &stylename, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *hanlde); +void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); + /*! \fn void QPlatformFontDatabase::registerQPF2Font(const QByteArray &dataArray, void *handle) @@ -517,6 +519,17 @@ QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromTrueTypeBits(q } /*! + Helper function that register the \a alias for the \a familyName. + + \since 5.2 +*/ + +void QPlatformFontDatabase::registerAliasToFontFamily(const QString &familyName, const QString &alias) +{ + qt_registerAliasToFontFamily(familyName, alias); +} + +/*! \class QPlatformFontDatabase \since 5.0 \internal diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index 6e53eba98b..6053f11051 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -122,6 +122,8 @@ public: QFont::Style style, QFont::Stretch stretch, bool antialiased, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *handle); + + static void registerAliasToFontFamily(const QString &familyName, const QString &alias); }; QT_END_NAMESPACE diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 9d9cbcf6c1..a85e9c86c9 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -260,7 +260,7 @@ public: void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style); Q_SIGNALS: - void contentsChange(int from, int charsRemoves, int charsAdded); + void contentsChange(int from, int charsRemoved, int charsAdded); void contentsChanged(); void undoAvailable(bool); void redoAvailable(bool); diff --git a/src/gui/text/qtextdocumentwriter.cpp b/src/gui/text/qtextdocumentwriter.cpp index b4a4a07c42..a294bceacc 100644 --- a/src/gui/text/qtextdocumentwriter.cpp +++ b/src/gui/text/qtextdocumentwriter.cpp @@ -52,6 +52,8 @@ #include "qtextdocumentfragment_p.h" #include "qtextodfwriter_p.h" +#include <algorithm> + QT_BEGIN_NAMESPACE class QTextDocumentWriterPrivate @@ -366,7 +368,7 @@ QList<QByteArray> QTextDocumentWriter::supportedDocumentFormats() answer << "ODF"; #endif // QT_NO_TEXTODFWRITER - qSort(answer); + std::sort(answer.begin(), answer.end()); return answer; } diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 2fa7f0232d..7a12b241e8 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -59,9 +59,9 @@ #include <algorithm> #include <stdlib.h> +#ifndef QT_NO_RAWFONT #include "qfontengine_qpa_p.h" - -#include <private/qharfbuzz_p.h> +#endif QT_BEGIN_NAMESPACE @@ -838,21 +838,6 @@ void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrd #endif } -// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item. -static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine) -{ - int nGlyphs = item->num_glyphs; - - QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (item->item.bidiLevel % 2) - shaperFlags |= QFontEngine::RightToLeft; - - bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags); - item->num_glyphs = nGlyphs; - glyphs->numGlyphs = nGlyphs; - return result; -} - // shape all the items that intersect with the line, taking tab widths into account to find out what text actually fits in the line. void QTextEngine::shapeLine(const QScriptLine &line) { @@ -892,19 +877,48 @@ void QTextEngine::shapeText(int item) const if (si.num_glyphs) return; - shapeTextWithHarfbuzz(item); - si.width = 0; + si.glyph_data_offset = layoutData->used; - if (!si.num_glyphs) - return; - QGlyphLayout glyphs = shapedGlyphs(&si); + const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.constData()) + si.position; + const int itemLength = length(item); + + if (!ensureSpace(itemLength)) + return; // ### report OOM error somehow + + QString casedString; + if (si.analysis.flags && si.analysis.flags <= QScriptAnalysis::SmallCaps) { + casedString.resize(itemLength); + ushort *uc = reinterpret_cast<ushort *>(casedString.data()); + for (int i = 0; i < itemLength; ++i) { + uint ucs4 = string[i]; + if (QChar::isHighSurrogate(ucs4) && i + 1 < itemLength) { + uint low = string[i + 1]; + if (QChar::isLowSurrogate(low)) { + ++i; + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + // high part never changes in simple casing + uc[i] = QChar::lowSurrogate(ucs4); + } + } else { + uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + } + } + string = reinterpret_cast<const ushort *>(casedString.constData()); + } + QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading); + + bool kerningEnabled; bool letterSpacingIsAbsolute; QFixed letterSpacing, wordSpacing; #ifndef QT_NO_RAWFONT if (useRawFont) { QTextCharFormat f = format(&si); + kerningEnabled = f.fontKerning(); wordSpacing = QFixed::fromReal(f.fontWordSpacing()); letterSpacing = QFixed::fromReal(f.fontLetterSpacing()); letterSpacingIsAbsolute = true; @@ -912,6 +926,7 @@ void QTextEngine::shapeText(int item) const #endif { QFont font = this->font(si); + kerningEnabled = font.d->kerning; letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute; letterSpacing = font.d->letterSpacing; wordSpacing = font.d->wordSpacing; @@ -920,6 +935,13 @@ void QTextEngine::shapeText(int item) const letterSpacing *= font.d->dpi / qt_defaultDpiY(); } + si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, kerningEnabled); + if (!si.num_glyphs) + return; // ### report shaping errors somehow + layoutData->used += si.num_glyphs; + + QGlyphLayout glyphs = shapedGlyphs(&si); + if (letterSpacing != 0) { for (int i = 1; i < si.num_glyphs; ++i) { if (glyphs.attributes[i].clusterStart) { @@ -940,12 +962,12 @@ void QTextEngine::shapeText(int item) const } if (wordSpacing != 0) { for (int i = 0; i < si.num_glyphs; ++i) { - if (glyphs.attributes[i].justification == HB_Space - || glyphs.attributes[i].justification == HB_Arabic_Space) { + if (glyphs.attributes[i].justification == QGlyphAttributes::Space + || glyphs.attributes[i].justification == QGlyphAttributes::Arabic_Space) { // word spacing only gets added once to a consecutive run of spaces (see CSS spec) if (i + 1 == si.num_glyphs - ||(glyphs.attributes[i+1].justification != HB_Space - && glyphs.attributes[i+1].justification != HB_Arabic_Space)) + ||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space + && glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space)) glyphs.advances_x[i] += wordSpacing; } } @@ -955,14 +977,6 @@ void QTextEngine::shapeText(int item) const si.width += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint; } -static inline bool hasCaseChange(const QScriptItem &si) -{ - return si.analysis.flags == QScriptAnalysis::SmallCaps || - si.analysis.flags == QScriptAnalysis::Uppercase || - si.analysis.flags == QScriptAnalysis::Lowercase; -} - - static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) { if (num > 0 && destination.glyphs != source.glyphs) { @@ -973,84 +987,60 @@ static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLa } } +QT_BEGIN_INCLUDE_NAMESPACE + +#include <private/qharfbuzz_p.h> + +QT_END_INCLUDE_NAMESPACE + 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 +// 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) { - QScriptItem &si = layoutData->items[item]; - - si.glyph_data_offset = layoutData->used; + int nGlyphs = item->num_glyphs; - QFontEngine *font = fontEngine(si, &si.ascent, &si.descent, &si.leading); + QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); + if (item->item.bidiLevel % 2) + shaperFlags |= QFontEngine::RightToLeft; - bool kerningEnabled; -#ifndef QT_NO_RAWFONT - if (useRawFont) { - QTextCharFormat f = format(&si); - kerningEnabled = f.fontKerning(); - } else -#endif - kerningEnabled = this->font(si).d->kerning; + bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags); + item->num_glyphs = nGlyphs; + glyphs->numGlyphs = nGlyphs; + return result; +} +int QTextEngine::shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const +{ HB_ShaperItem entire_shaper_item; 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.string = reinterpret_cast<const HB_UChar16 *>(string); + entire_shaper_item.stringLength = itemLength; 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.pos = 0; + entire_shaper_item.item.length = itemLength; entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel; - QVarLengthArray<HB_UChar16, 256> casedString; - if (hasCaseChange(si)) { - if (casedString.size() < static_cast<int>(entire_shaper_item.item.length)) - casedString.resize(entire_shaper_item.item.length); - HB_UChar16 *uc = casedString.data(); - for (uint i = 0; i < entire_shaper_item.item.length; ++i) { - uint ucs4 = entire_shaper_item.string[si.position + i]; - if (QChar::isHighSurrogate(ucs4)) { - uc[i] = ucs4; // high part never changes in simple casing - if (i + 1 < entire_shaper_item.item.length) { - ushort low = entire_shaper_item.string[si.position + i + 1]; - if (QChar::isLowSurrogate(low)) { - ucs4 = QChar::surrogateToUcs4(ucs4, low); - ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) - : QChar::toUpper(ucs4); - uc[++i] = QChar::lowSurrogate(ucs4); - } - } - } else { - uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) - : QChar::toUpper(ucs4); - } - } - entire_shaper_item.item.pos = 0; - entire_shaper_item.string = uc; - entire_shaper_item.stringLength = entire_shaper_item.item.length; - } - entire_shaper_item.shaperFlags = 0; if (!kerningEnabled) entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning; if (option.useDesignMetrics()) entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics; - entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length)); - if (!ensureSpace(entire_shaper_item.num_glyphs)) - return; + entire_shaper_item.num_glyphs = itemLength; + QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); - if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { + if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) { if (!ensureSpace(entire_shaper_item.num_glyphs)) - return; + return 0; initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); - if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { + if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, fontEngine)) { // ############ if this happens there's a bug in the fontengine - return; + return 0; } } @@ -1060,7 +1050,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const itemBoundaries[0] = entire_shaper_item.item.pos; itemBoundaries[1] = 0; - if (font->type() == QFontEngine::Multi) { + if (fontEngine->type() == QFontEngine::Multi) { uint lastEngine = 0; int charIdx = entire_shaper_item.item.pos; const int stringEnd = charIdx + entire_shaper_item.item.length; @@ -1099,18 +1089,17 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const if (shaper_item.num_glyphs < shaper_item.item.length) shaper_item.num_glyphs = shaper_item.item.length; - QFontEngine *actualFontEngine = font; + QFontEngine *actualFontEngine = fontEngine; uint engineIdx = 0; - if (font->type() == QFontEngine::Multi) { + if (fontEngine->type() == QFontEngine::Multi) { engineIdx = uint(availableGlyphs(&si).glyphs[glyph_pos] >> 24); - actualFontEngine = static_cast<QFontEngineMulti *>(font)->engine(engineIdx); + actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); + si.ascent = qMax(actualFontEngine->ascent(), si.ascent); + si.descent = qMax(actualFontEngine->descent(), si.descent); + si.leading = qMax(actualFontEngine->leading(), si.leading); } - si.ascent = qMax(actualFontEngine->ascent(), si.ascent); - si.descent = qMax(actualFontEngine->descent(), si.descent); - si.leading = qMax(actualFontEngine->leading(), si.leading); - shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont(); shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace(); @@ -1120,7 +1109,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const do { if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) - return; + return 0; const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); if (shaper_item.num_glyphs > shaper_item.item.length) @@ -1137,8 +1126,6 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const } shaper_item.log_clusters = logClusters(&si) + shaper_item.item.pos - entire_shaper_item.item.pos; - -// qDebug(" .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); } while (!qShapeItem(&shaper_item)); // this does the actual shaping via harfbuzz. QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs); @@ -1158,10 +1145,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const glyph_pos += shaper_item.num_glyphs; } -// qDebug(" -> item: script=%d num_glyphs=%d", shaper_item.script, shaper_item.num_glyphs); - si.num_glyphs = glyph_pos; - - layoutData->used += si.num_glyphs; + return glyph_pos; } void QTextEngine::init(QTextEngine *e) @@ -1821,7 +1805,7 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, point->type = type; point->glyph = glyph; - if (type >= HB_Arabic_Normal) { + if (type >= QGlyphAttributes::Arabic_Normal) { QChar ch(0x640); // Kashida character QGlyphLayoutArray<8> glyphs; int nglyphs = 7; @@ -1829,7 +1813,7 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, if (glyphs.glyphs[0] && glyphs.advances_x[0] != 0) { point->kashidaWidth = glyphs.advances_x[0]; } else { - point->type = HB_NoJustification; + point->type = QGlyphAttributes::NoJustification; point->kashidaWidth = 0; } } @@ -1897,7 +1881,7 @@ void QTextEngine::justify(const QScriptLine &line) for (int i = 0; i < nItems; ++i) { QScriptItem &si = layoutData->items[firstItem + i]; - int kashida_type = HB_Arabic_Normal; + int kashida_type = QGlyphAttributes::Arabic_Normal; int kashida_pos = -1; int start = qMax(line.from - si.position, 0); @@ -1921,11 +1905,11 @@ void QTextEngine::justify(const QScriptLine &line) int justification = g.attributes[i].justification; switch(justification) { - case HB_NoJustification: + case QGlyphAttributes::NoJustification: break; - case HB_Space : + case QGlyphAttributes::Space : // fall through - case HB_Arabic_Space : + case QGlyphAttributes::Arabic_Space : if (kashida_pos >= 0) { // qDebug("kashida position at %d in word", kashida_pos); set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si)); @@ -1936,19 +1920,19 @@ void QTextEngine::justify(const QScriptLine &line) } } kashida_pos = -1; - kashida_type = HB_Arabic_Normal; + kashida_type = QGlyphAttributes::Arabic_Normal; // fall through - case HB_Character : + case QGlyphAttributes::Character : set(&justificationPoints[nPoints++], justification, g.mid(i), fontEngine(si)); maxJustify = qMax(maxJustify, justification); break; - case HB_Arabic_Normal : - case HB_Arabic_Waw : - case HB_Arabic_BaRa : - case HB_Arabic_Alef : - case HB_Arabic_HaaDal : - case HB_Arabic_Seen : - case HB_Arabic_Kashida : + case QGlyphAttributes::Arabic_Normal : + case QGlyphAttributes::Arabic_Waw : + case QGlyphAttributes::Arabic_BaRa : + case QGlyphAttributes::Arabic_Alef : + case QGlyphAttributes::Arabic_HaaDal : + case QGlyphAttributes::Arabic_Seen : + case QGlyphAttributes::Arabic_Kashida : if (justification >= kashida_type) { kashida_pos = i; kashida_type = justification; @@ -1977,9 +1961,9 @@ void QTextEngine::justify(const QScriptLine &line) // qDebug(" minKashida=%f, need=%f", minKashida.toReal(), need.toReal()); // distribute in priority order - if (maxJustify >= HB_Arabic_Normal) { + if (maxJustify >= QGlyphAttributes::Arabic_Normal) { while (need >= minKashida) { - for (int type = maxJustify; need >= minKashida && type >= HB_Arabic_Normal; --type) { + for (int type = maxJustify; need >= minKashida && type >= QGlyphAttributes::Arabic_Normal; --type) { for (int i = 0; need >= minKashida && i < nPoints; ++i) { if (justificationPoints[i].type == type && justificationPoints[i].kashidaWidth <= need) { justificationPoints[i].glyph.justifications->nKashidas++; @@ -1996,7 +1980,7 @@ void QTextEngine::justify(const QScriptLine &line) if (!need) goto end; - maxJustify = qMin(maxJustify, (int)HB_Space); + maxJustify = qMin(maxJustify, int(QGlyphAttributes::Space)); for (int type = maxJustify; need != 0 && type > 0; --type) { int n = 0; for (int i = 0; i < nPoints; ++i) { @@ -2438,12 +2422,13 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int const int end = si.position + length(&si); for (int i = si.position; i < end - 1; ++i) { - if (layoutData->string.at(i) == QLatin1Char('&')) { + if (layoutData->string.at(i) == QLatin1Char('&') + && !attributes[i + 1].whiteSpace && attributes[i + 1].graphemeBoundary) { const int gp = logClusters[i - si.position]; glyphs.attributes[gp].dontPrint = true; - attributes[i + 1].graphemeBoundary = false; - attributes[i + 1].lineBreak = false; - attributes[i + 1].whiteSpace = false; + // emulate grapheme cluster + attributes[i] = attributes[i + 1]; + memset(attributes + i + 1, 0, sizeof(QCharAttributes)); if (layoutData->string.at(i + 1) == QLatin1Char('&')) ++i; } @@ -2596,7 +2581,6 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int namespace { struct QScriptItemComparator { - bool operator()(const QScriptItem &a, const QScriptItem &b) { return a.position < b.position; } bool operator()(int p, const QScriptItem &b) { return p < b.position; } #if defined(Q_CC_MSVC) && _MSC_VER < 1600 //The STL implementation of MSVC 2008 requires the definition @@ -2786,10 +2770,10 @@ void QTextEngine::resolveAdditionalFormats() const addFormatSortedByStart.append(i); } QVarLengthArray<int, 64> addFormatSortedByEnd = addFormatSortedByStart; - qSort(addFormatSortedByStart.begin(), addFormatSortedByStart.end(), - FormatRangeComparatorByStart(specialData->addFormats)); - qSort(addFormatSortedByEnd.begin(), addFormatSortedByEnd.end(), - FormatRangeComparatorByEnd(specialData->addFormats)); + std::sort(addFormatSortedByStart.begin(), addFormatSortedByStart.end(), + FormatRangeComparatorByStart(specialData->addFormats)); + std::sort(addFormatSortedByEnd.begin(), addFormatSortedByEnd.end(), + FormatRangeComparatorByEnd(specialData->addFormats)); QVarLengthArray<int, 16> currentFormats; const int *startIt = addFormatSortedByStart.constBegin(); diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index ec7f7407b2..b3ab9a42d8 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -96,6 +96,20 @@ typedef quint8 q_hb_bitfield; #endif typedef struct { + typedef enum { + NoJustification= 0, /* Justification can't be applied after this glyph */ + Arabic_Space = 1, /* This glyph represents a space inside arabic text */ + Character = 2, /* Inter-character justification point follows this glyph */ + Space = 4, /* This glyph represents a blank outside an Arabic run */ + Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */ + Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */ + Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */ + Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */ + Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */ + Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */ + Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */ + } JustificationClass; + q_hb_bitfield justification :4; /* Justification class */ q_hb_bitfield clusterStart :1; /* First glyph of representation of cluster */ q_hb_bitfield mark :1; /* needs to be positioned around base char */ @@ -174,15 +188,6 @@ struct QGlyphJustification }; Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE); -struct QGlyphLayoutInstance -{ - QFixedPoint offset; - QFixedPoint advance; - glyph_t glyph; - QGlyphJustification justification; - QGlyphAttributes attributes; -}; - struct QGlyphLayout { // init to 0 not needed, done when shaping @@ -237,28 +242,6 @@ struct QGlyphLayout inline QFixed effectiveAdvance(int item) const { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } - inline QGlyphLayoutInstance instance(int position) const { - QGlyphLayoutInstance g; - g.offset.x = offsets[position].x; - g.offset.y = offsets[position].y; - g.glyph = glyphs[position]; - g.advance.x = advances_x[position]; - g.advance.y = advances_y[position]; - g.justification = justifications[position]; - g.attributes = attributes[position]; - return g; - } - - inline void setInstance(int position, const QGlyphLayoutInstance &g) { - offsets[position].x = g.offset.x; - offsets[position].y = g.offset.y; - glyphs[position] = g.glyph; - advances_x[position] = g.advance.x; - advances_y[position] = g.advance.y; - justifications[position] = g.justification; - attributes[position] = g.attributes; - } - inline void clear(int first = 0, int last = -1) { if (last == -1) last = numGlyphs; @@ -685,7 +668,7 @@ private: void setBoundary(int strPos) const; void addRequiredBoundaries() const; void shapeText(int item) const; - void shapeTextWithHarfbuzz(int item) const; + int shapeTextWithHarfbuzz(QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, bool kerningEnabled) const; void splitItem(int item, int pos) const; int endOfLine(int lineNum); |