diff options
Diffstat (limited to 'src/gui/text')
31 files changed, 664 insertions, 960 deletions
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp index 8528f59844..48b7f85413 100644 --- a/src/gui/text/qabstracttextdocumentlayout.cpp +++ b/src/gui/text/qabstracttextdocumentlayout.cpp @@ -53,7 +53,6 @@ QAbstractTextDocumentLayoutPrivate::~QAbstractTextDocumentLayoutPrivate() QTextObjectInterface::~QTextObjectInterface() { - // must be empty until ### Qt 6 } /*! @@ -568,7 +567,7 @@ void QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed(QObject *obj) */ int QAbstractTextDocumentLayout::formatIndex(int pos) { - QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle(); + QTextDocumentPrivate *pieceTable = QTextDocumentPrivate::get(qobject_cast<QTextDocument *>(parent())); return pieceTable->find(pos).value()->format; } @@ -579,7 +578,7 @@ int QAbstractTextDocumentLayout::formatIndex(int pos) */ QTextCharFormat QAbstractTextDocumentLayout::format(int pos) { - QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle(); + QTextDocumentPrivate *pieceTable = QTextDocumentPrivate::get(qobject_cast<QTextDocument *>(parent())); int idx = pieceTable->find(pos).value()->format; return pieceTable->formatCollection()->charFormat(idx); } @@ -645,7 +644,7 @@ QTextFormat QAbstractTextDocumentLayout::formatAt(const QPointF &pos) const block = block.next(); } - QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle(); + const QTextDocumentPrivate *pieceTable = QTextDocumentPrivate::get(qobject_cast<const QTextDocument *>(parent())); QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); return pieceTable->formatCollection()->format(it->format); } diff --git a/src/gui/text/qabstracttextdocumentlayout_p.h b/src/gui/text/qabstracttextdocumentlayout_p.h index d631ce3197..88035eb66d 100644 --- a/src/gui/text/qabstracttextdocumentlayout_p.h +++ b/src/gui/text/qabstracttextdocumentlayout_p.h @@ -53,6 +53,7 @@ #include <QtGui/private/qtguiglobal_p.h> #include "private/qobject_p.h" +#include "qtextdocument_p.h" #include "QtCore/qhash.h" QT_BEGIN_NAMESPACE @@ -78,7 +79,7 @@ public: document = doc; docPrivate = nullptr; if (doc) - docPrivate = doc->docHandle(); + docPrivate = QTextDocumentPrivate::get(doc); } inline int _q_dynamicPageCountSlot() const diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index f2fd585835..523895bc0e 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qfontdatabase.h" +#include "qfontdatabase_p.h" #include "qloggingcategory.h" #include "qalgorithms.h" #include "qguiapplication.h" @@ -173,71 +174,6 @@ static int getFontWeight(const QString &weightString) } -struct QtFontSize -{ - - void *handle; - - unsigned short pixelSize : 16; -}; - - - -struct QtFontStyle -{ - struct Key { - Key(const QString &styleString); - Key() : style(QFont::StyleNormal), - weight(QFont::Normal), stretch(0) { } - Key(const Key &o) : style(o.style), weight(o.weight), stretch(o.stretch) { } - uint style : 2; - signed int weight : 8; - signed int stretch : 12; - - bool operator==(const Key & other) { - return (style == other.style && weight == other.weight && - (stretch == 0 || other.stretch == 0 || stretch == other.stretch)); - } - bool operator!=(const Key &other) { - return !operator==(other); - } - bool operator <(const Key &o) { - int x = (style << 12) + (weight << 14) + stretch; - int y = (o.style << 12) + (o.weight << 14) + o.stretch; - return (x < y); - } - }; - - QtFontStyle(const Key &k) - : key(k), bitmapScalable(false), smoothScalable(false), - count(0), pixelSizes(nullptr) - { - } - - ~QtFontStyle() { - while (count) { - // bitfield count-- in while condition does not work correctly in mwccsym2 - count--; - QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); - if (integration) { - integration->fontDatabase()->releaseHandle(pixelSizes[count].handle); - } - } - free(pixelSizes); - } - - Key key; - bool bitmapScalable : 1; - bool smoothScalable : 1; - signed int count : 30; - QtFontSize *pixelSizes; - QString styleName; - - bool antialiased; - - QtFontSize *pixelSize(unsigned short size, bool = false); -}; - QtFontStyle::Key::Key(const QString &styleString) : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0) { @@ -284,22 +220,6 @@ QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add) return pixelSizes + (count++); } -struct QtFontFoundry -{ - QtFontFoundry(const QString &n) : name(n), count(0), styles(nullptr) {} - ~QtFontFoundry() { - while (count--) - delete styles[count]; - free(styles); - } - - QString name; - - int count; - QtFontStyle **styles; - QtFontStyle *style(const QtFontStyle::Key &, const QString & = QString(), bool = false); -}; - QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, const QString &styleName, bool create) { int pos = 0; @@ -331,46 +251,6 @@ QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, const QString &st return styles[pos]; } - -struct QtFontFamily -{ - enum WritingSystemStatus { - Unknown = 0, - Supported = 1, - UnsupportedFT = 2, - Unsupported = UnsupportedFT - }; - - QtFontFamily(const QString &n) - : - populated(false), - fixedPitch(false), - name(n), count(0), foundries(nullptr) - { - memset(writingSystems, 0, sizeof(writingSystems)); - } - ~QtFontFamily() { - while (count--) - delete foundries[count]; - free(foundries); - } - - bool populated : 1; - bool fixedPitch : 1; - - QString name; - QStringList aliases; - int count; - QtFontFoundry **foundries; - - unsigned char writingSystems[QFontDatabase::WritingSystemsCount]; - - bool matchesFamilyName(const QString &familyName) const; - QtFontFoundry *foundry(const QString &f, bool = false); - - void ensurePopulated(); -}; - QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) { if (f.isNull() && count == 1) @@ -414,85 +294,6 @@ void QtFontFamily::ensurePopulated() Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name)); } - -struct FallbacksCacheKey { - QString family; - QFont::Style style; - QFont::StyleHint styleHint; - QChar::Script script; -}; - -inline bool operator==(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) noexcept -{ - return lhs.script == rhs.script && - lhs.styleHint == rhs.styleHint && - lhs.style == rhs.style && - lhs.family == rhs.family; -} - -inline bool operator!=(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) noexcept -{ - return !operator==(lhs, rhs); -} - -inline uint qHash(const FallbacksCacheKey &key, uint seed = 0) noexcept -{ - QtPrivate::QHashCombine hash; - seed = hash(seed, key.family); - seed = hash(seed, int(key.style)); - seed = hash(seed, int(key.styleHint)); - seed = hash(seed, int(key.script)); - return seed; -} - - -class QFontDatabasePrivate -{ -public: - QFontDatabasePrivate() - : count(0), families(nullptr), - fallbacksCache(64) - { } - - ~QFontDatabasePrivate() { - free(); - } - - enum FamilyRequestFlags { - RequestFamily = 0, - EnsureCreated, - EnsurePopulated - }; - - QtFontFamily *family(const QString &f, FamilyRequestFlags flags = EnsurePopulated); - void free() { - while (count--) - delete families[count]; - ::free(families); - families = nullptr; - count = 0; - // don't clear the memory fonts! - } - - int count; - QtFontFamily **families; - - QCache<FallbacksCacheKey, QStringList> fallbacksCache; - - - struct ApplicationFont { - QString fileName; - QByteArray data; - QStringList families; - }; - QVector<ApplicationFont> applicationFonts; - int addAppFont(const QByteArray &fontData, const QString &fileName); - bool isApplicationFont(const QString &fileName); - - void invalidate(); -}; -Q_DECLARE_TYPEINFO(QFontDatabasePrivate::ApplicationFont, Q_MOVABLE_TYPE); - void QFontDatabasePrivate::invalidate() { QFontCache::instance()->clear(); @@ -597,7 +398,32 @@ Q_GUI_EXPORT int qt_script_for_writing_system(QFontDatabase::WritingSystem writi } +/*! + \internal + + Tests if the given family \a family supports writing system \a writingSystem, + including the special case for Han script mapping to several subsequent writing systems +*/ +static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem) +{ + Q_ASSERT(family != nullptr); + Q_ASSERT(writingSystem != QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount); + + size_t ws = writingSystem; + do { + if ((family->writingSystems[ws] & QtFontFamily::Supported) != 0) + return true; + } while (writingSystem >= QFontDatabase::SimplifiedChinese && writingSystem <= QFontDatabase::Japanese && ++ws <= QFontDatabase::Japanese); + + return false; +} +Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script) +{ + return QFontDatabase::WritingSystem(std::find(scriptForWritingSystem, + scriptForWritingSystem + QFontDatabase::WritingSystemsCount, + script) - scriptForWritingSystem); +} /*! \internal @@ -723,6 +549,10 @@ QRecursiveMutex *qt_fontdatabase_mutex() return fontDatabaseMutex(); } +QFontDatabasePrivate *QFontDatabasePrivate::instance() +{ + return privateDb(); +} void qt_registerFont(const QString &familyName, const QString &stylename, const QString &foundryname, int weight, @@ -814,9 +644,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo QStringList preferredFallbacks; QStringList otherFallbacks; - size_t writingSystem = std::find(scriptForWritingSystem, - scriptForWritingSystem + QFontDatabase::WritingSystemsCount, - script) - scriptForWritingSystem; + auto writingSystem = qt_writing_system_for_script(script); if (writingSystem >= QFontDatabase::WritingSystemsCount) writingSystem = QFontDatabase::Any; @@ -826,7 +654,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo f->ensurePopulated(); - if (writingSystem > QFontDatabase::Any && f->writingSystems[writingSystem] != QtFontFamily::Supported) + if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(f, writingSystem)) continue; for (int j = 0; j < f->count; ++j) { @@ -855,7 +683,7 @@ static QStringList fallbacksForFamily(const QString &family, QFont::Style style, if (!db->count) initializeDb(); - const FallbacksCacheKey cacheKey = { family, style, styleHint, script }; + const QtFontFallbacksCacheKey cacheKey = { family, style, styleHint, script }; if (const QStringList *fallbacks = db->fallbacksCache.object(cacheKey)) return *fallbacks; @@ -899,7 +727,7 @@ static void initializeDb() if (!db->count) { QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase(); for (int i = 0; i < db->applicationFonts.count(); i++) { - if (!db->applicationFonts.at(i).families.isEmpty()) + if (!db->applicationFonts.at(i).properties.isEmpty()) registerFont(&db->applicationFonts[i]); } } @@ -1027,9 +855,22 @@ QFontEngine *loadEngine(int script, const QFontDef &request, return engine; } +QtFontStyle::~QtFontStyle() +{ + while (count) { + // bitfield count-- in while condition does not work correctly in mwccsym2 + count--; + QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); + if (integration) + integration->fontDatabase()->releaseHandle(pixelSizes[count].handle); + } + + free(pixelSizes); +} + static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) { - fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName); + QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data, fnt->fileName, fnt); } static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey, @@ -1253,8 +1094,7 @@ static int match(int script, const QFontDef &request, load(family_name, script); - size_t writingSystem = std::find(scriptForWritingSystem, scriptForWritingSystem + - QFontDatabase::WritingSystemsCount, script) - scriptForWritingSystem; + auto writingSystem = qt_writing_system_for_script(script); if (writingSystem >= QFontDatabase::WritingSystemsCount) writingSystem = QFontDatabase::Any; @@ -1271,7 +1111,7 @@ static int match(int script, const QFontDef &request, test.family->ensurePopulated(); // Check if family is supported in the script we want - if (writingSystem != QFontDatabase::Any && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported)) + if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(test.family, writingSystem)) continue; // as we know the script is supported, we can be sure @@ -2433,7 +2273,7 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString & int i; for (i = 0; i < applicationFonts.count(); ++i) - if (applicationFonts.at(i).families.isEmpty()) + if (applicationFonts.at(i).properties.isEmpty()) break; if (i >= applicationFonts.count()) { applicationFonts.append(ApplicationFont()); @@ -2445,7 +2285,7 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString & bool wasEmpty = privateDb()->count == 0; registerFont(&font); - if (font.families.isEmpty()) + if (font.properties.isEmpty()) return -1; applicationFonts[i] = font; @@ -2534,7 +2374,14 @@ int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData) QStringList QFontDatabase::applicationFontFamilies(int id) { QMutexLocker locker(fontDatabaseMutex()); - return privateDb()->applicationFonts.value(id).families; + + QStringList ret; + ret.reserve(privateDb()->applicationFonts.value(id).properties.size()); + + for (const auto &properties : privateDb()->applicationFonts.value(id).properties) + ret.append(properties.familyName); + + return ret; } /*! @@ -2857,9 +2704,7 @@ QString QFontDatabase::resolveFontFamilyAlias(const QString &family) Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families) { - size_t writingSystem = std::find(scriptForWritingSystem, - scriptForWritingSystem + QFontDatabase::WritingSystemsCount, - script) - scriptForWritingSystem; + size_t writingSystem = qt_writing_system_for_script(script); if (writingSystem == QFontDatabase::Any || writingSystem >= QFontDatabase::WritingSystemsCount) { return families; @@ -2881,7 +2726,7 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script uint order = i; if (testFamily == nullptr - || (testFamily->writingSystems[writingSystem] & QtFontFamily::Supported) == 0) { + || !familySupportsWritingSystem(testFamily, writingSystem)) { order |= 1u << 31; } diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 80b092f177..63e6b48e4f 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE class QStringList; -template <class T> class QList; struct QFontDef; class QFontEngine; diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h new file mode 100644 index 0000000000..f13dd66aa8 --- /dev/null +++ b/src/gui/text/qfontdatabase_p.h @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTDATABASE_P_H +#define QFONTDATABASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qcache.h> + +#include <QtGui/qfontdatabase.h> + +QT_BEGIN_NAMESPACE + +struct QtFontFallbacksCacheKey +{ + QString family; + QFont::Style style; + QFont::StyleHint styleHint; + QChar::Script script; +}; + +inline bool operator==(const QtFontFallbacksCacheKey &lhs, const QtFontFallbacksCacheKey &rhs) noexcept +{ + return lhs.script == rhs.script && + lhs.styleHint == rhs.styleHint && + lhs.style == rhs.style && + lhs.family == rhs.family; +} + +inline bool operator!=(const QtFontFallbacksCacheKey &lhs, const QtFontFallbacksCacheKey &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +inline uint qHash(const QtFontFallbacksCacheKey &key, uint seed = 0) noexcept +{ + QtPrivate::QHashCombine hash; + seed = hash(seed, key.family); + seed = hash(seed, int(key.style)); + seed = hash(seed, int(key.styleHint)); + seed = hash(seed, int(key.script)); + return seed; +} + +struct Q_GUI_EXPORT QtFontSize +{ + void *handle; + unsigned short pixelSize : 16; +}; + +struct Q_GUI_EXPORT QtFontStyle +{ + struct Key + { + Key(const QString &styleString); + + Key() + : style(QFont::StyleNormal) + , weight(QFont::Normal) + , stretch(0) + {} + + Key(const Key &o) + : style(o.style) + , weight(o.weight) + , stretch(o.stretch) + {} + + uint style : 2; + signed int weight : 8; + signed int stretch : 12; + + bool operator==(const Key &other) + { + return (style == other.style && weight == other.weight && + (stretch == 0 || other.stretch == 0 || stretch == other.stretch)); + } + + bool operator!=(const Key &other) + { + return !operator==(other); + } + + bool operator<(const Key &o) + { + int x = (style << 12) + (weight << 14) + stretch; + int y = (o.style << 12) + (o.weight << 14) + o.stretch; + return (x < y); + } + }; + + QtFontStyle(const Key &k) + : key(k) + , bitmapScalable(false) + , smoothScalable(false) + , count(0) + , pixelSizes(nullptr) + { + } + + ~QtFontStyle(); + + QtFontSize *pixelSize(unsigned short size, bool = false); + + Key key; + bool bitmapScalable : 1; + bool smoothScalable : 1; + signed int count : 30; + QtFontSize *pixelSizes; + QString styleName; + bool antialiased; +}; + +struct Q_GUI_EXPORT QtFontFoundry +{ + QtFontFoundry(const QString &n) + : name(n) + , count(0) + , styles(nullptr) + {} + + ~QtFontFoundry() + { + while (count--) + delete styles[count]; + free(styles); + } + + QString name; + int count; + QtFontStyle **styles; + QtFontStyle *style(const QtFontStyle::Key &, const QString & = QString(), bool = false); +}; + +struct Q_GUI_EXPORT QtFontFamily +{ + enum WritingSystemStatus { + Unknown = 0, + Supported = 1, + UnsupportedFT = 2, + Unsupported = UnsupportedFT + }; + + QtFontFamily(const QString &n) + : + populated(false), + fixedPitch(false), + name(n), count(0), foundries(nullptr) + { + memset(writingSystems, 0, sizeof(writingSystems)); + } + ~QtFontFamily() { + while (count--) + delete foundries[count]; + free(foundries); + } + + bool populated : 1; + bool fixedPitch : 1; + + QString name; + QStringList aliases; + int count; + QtFontFoundry **foundries; + + unsigned char writingSystems[QFontDatabase::WritingSystemsCount]; + + bool matchesFamilyName(const QString &familyName) const; + QtFontFoundry *foundry(const QString &f, bool = false); + + void ensurePopulated(); +}; + +class Q_GUI_EXPORT QFontDatabasePrivate +{ +public: + QFontDatabasePrivate() + : count(0) + , families(nullptr) + , fallbacksCache(64) + { } + + ~QFontDatabasePrivate() { + free(); + } + + enum FamilyRequestFlags { + RequestFamily = 0, + EnsureCreated, + EnsurePopulated + }; + + QtFontFamily *family(const QString &f, FamilyRequestFlags flags = EnsurePopulated); + void free() { + while (count--) + delete families[count]; + ::free(families); + families = nullptr; + count = 0; + // don't clear the memory fonts! + } + + int count; + QtFontFamily **families; + + QCache<QtFontFallbacksCacheKey, QStringList> fallbacksCache; + struct ApplicationFont { + QString fileName; + QByteArray data; + + struct Properties { + QString familyName; + QString styleName; + int weight = 0; + QFont::Style style = QFont::StyleNormal; + int stretch = QFont::Unstretched; + }; + + QVector<Properties> properties; + }; + QVector<ApplicationFont> applicationFonts; + int addAppFont(const QByteArray &fontData, const QString &fileName); + bool isApplicationFont(const QString &fileName); + + static QFontDatabasePrivate *instance(); + + void invalidate(); +}; +Q_DECLARE_TYPEINFO(QFontDatabasePrivate::ApplicationFont, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +#endif // QFONTDATABASE_P_H diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index b6046b0fc5..32fbd8cfed 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -57,7 +57,6 @@ # include "qharfbuzzng_p.h" # include <harfbuzz/hb-ot.h> #endif -#include <private/qharfbuzz_p.h> #include <algorithm> #include <limits.h> @@ -102,75 +101,6 @@ bool qt_useHarfbuzzNG() } #endif -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; - - const QChar *str = reinterpret_cast<const QChar *>(string); - - QGlyphLayout qglyphs; - qglyphs.numGlyphs = *numGlyphs; - qglyphs.glyphs = glyphs; - int nGlyphs = *numGlyphs; - bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly); - *numGlyphs = nGlyphs; - - if (rightToLeft && result && !fe->symbol) { - QStringIterator it(str, str + length); - while (it.hasNext()) { - const uint ucs4 = it.next(); - const uint mirrored = QChar::mirroredChar(ucs4); - if (Q_UNLIKELY(mirrored != ucs4)) - *glyphs = fe->glyphIndex(mirrored); - ++glyphs; - } - } - - 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; - - QGlyphLayout qglyphs; - qglyphs.numGlyphs = numGlyphs; - qglyphs.glyphs = const_cast<glyph_t *>(glyphs); - qglyphs.advances = reinterpret_cast<QFixed *>(advances); - - fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{}); -} - -static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length) -{ - QFontEngine *fe = (QFontEngine *)font->userData; - return fe->canRender(reinterpret_cast<const QChar *>(string), length); -} - -static void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics) -{ - QFontEngine *fe = (QFontEngine *)font->userData; - glyph_metrics_t m = fe->boundingBox(glyph); - metrics->x = m.x.value(); - metrics->y = m.y.value(); - metrics->width = m.width.value(); - metrics->height = m.height.value(); - metrics->xOffset = m.xoff.value(); - metrics->yOffset = m.yoff.value(); -} - -static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric) -{ - if (metric == HB_FontAscent) { - QFontEngine *fe = (QFontEngine *)font->userData; - return fe->ascent().value(); - } - return 0; -} - int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) { Q_UNUSED(glyph) @@ -182,36 +112,6 @@ int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFix 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) -{ - QFontEngine *fe = (QFontEngine *)font->userData; - return (HB_Error)fe->getPointInOutline(glyph, flags, point, (QFixed *)xpos, (QFixed *)ypos, (quint32 *)nPoints); -} - -static const HB_FontClass hb_fontClass = { - hb_stringToGlyphs, hb_getAdvances, hb_canRender, hb_getPointInOutline, - hb_getGlyphMetrics, hb_getFontMetric -}; - -static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length) -{ - QFontEngine::FaceData *data = (QFontEngine::FaceData *)font; - Q_ASSERT(data); - - qt_get_font_table_func_t get_font_table = data->get_font_table; - Q_ASSERT(get_font_table); - - if (!get_font_table(data->user_data, tableTag, buffer, length)) - return HB_Err_Invalid_Argument; - return HB_Err_Ok; -} - -static void hb_freeFace(void *face) -{ - qHBFreeFace((HB_Face)face); -} - - static bool qt_get_font_table_default(void *user_data, uint tag, uchar *buffer, uint *length) { QFontEngine *fe = (QFontEngine *)user_data; @@ -301,32 +201,7 @@ void *QFontEngine::harfbuzzFont() const if (qt_useHarfbuzzNG()) 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) { - void *data = hbFace->font_for_init; - q_check_ptr(qHBLoadFace(hbFace)); - free(data); - } - - 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) - emSquare = 1000; // a fallback value suitable for Type1 fonts - hbFont->y_ppem = fontDef.pixelSize; - hbFont->x_ppem = fontDef.pixelSize * fontDef.stretch / 100; - // 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_ = Holder(hbFont, free); - } - return font_.get(); + return nullptr; } void *QFontEngine::harfbuzzFace() const @@ -336,19 +211,7 @@ void *QFontEngine::harfbuzzFace() const if (qt_useHarfbuzzNG()) return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this)); #endif - if (!face_) { - QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData)); - Q_CHECK_PTR(data); - data->user_data = faceData.user_data; - data->get_font_table = faceData.get_font_table; - - HB_Face hbFace = qHBNewFace(data, hb_getSFntTable); - Q_CHECK_PTR(hbFace); - hbFace->isSymbolFont = symbol; - - face_ = Holder(hbFace, hb_freeFace); - } - return face_.get(); + return nullptr; } bool QFontEngine::supportsScript(QChar::Script script) const @@ -364,36 +227,25 @@ bool QFontEngine::supportsScript(QChar::Script script) const #if QT_CONFIG(harfbuzz) if (qt_useHarfbuzzNG()) { -#if defined(Q_OS_DARWIN) // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table uint len; if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len)) return true; -#endif - bool ret = false; if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) { - hb_tag_t script_tag_1, script_tag_2; - hb_ot_tags_from_script(hb_qt_script_to_script(script), &script_tag_1, &script_tag_2); - - unsigned int script_index; - ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_1, &script_index); - if (!ret) { - ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_2, &script_index); - if (!ret && script_tag_2 != HB_OT_TAG_DEFAULT_SCRIPT) - ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, HB_OT_TAG_DEFAULT_SCRIPT, &script_index); - } + unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT; + hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT]; + + hb_ot_tags_from_script_and_language(hb_qt_script_to_script(script), HB_LANGUAGE_INVALID, + &script_count, script_tags, + nullptr, nullptr); + + if (hb_ot_layout_table_select_script(face, HB_OT_TAG_GSUB, script_count, script_tags, nullptr, nullptr)) + return true; } - return ret; } #endif - HB_Face hbFace = (HB_Face)harfbuzzFace(); - if (hbFace->font_for_init) { - void *data = hbFace->font_for_init; - q_check_ptr(qHBLoadFace(hbFace)); - free(data); - } - return hbFace->supported_scripts[script_to_hbscript(script)]; + return false; } bool QFontEngine::canRender(const QChar *str, int len) const @@ -807,14 +659,14 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp const int w = alphaMask.width(); const int h = alphaMask.height(); - const int srcBpl = alphaMask.bytesPerLine(); + const qsizetype srcBpl = alphaMask.bytesPerLine(); QImage bitmap; if (alphaMask.depth() == 1) { bitmap = alphaMask; } else { bitmap = QImage(w, h, QImage::Format_Mono); const uchar *imageData = alphaMask.bits(); - const int destBpl = bitmap.bytesPerLine(); + const qsizetype destBpl = bitmap.bytesPerLine(); uchar *bitmapData = bitmap.bits(); for (int yi = 0; yi < h; ++yi) { diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index e00f9d058c..d636bca510 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -168,7 +168,7 @@ const QFontEngineQPF2::Glyph *QFontEngineQPF2::findGlyph(glyph_t g) const bool QFontEngineQPF2::verifyHeader(const uchar *data, int size) { - VERIFY(quintptr(data) % Q_ALIGNOF(Header) == 0); + VERIFY(quintptr(data) % alignof(Header) == 0); VERIFY(size >= int(sizeof(Header))); const Header *header = reinterpret_cast<const Header *>(data); if (header->magic[0] != 'Q' diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index 4613aff9e8..0ee44192b1 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2013 Konstantin Ritt ** Contact: https://www.qt.io/licensing/ ** @@ -82,7 +82,7 @@ static const hb_script_t _qtscript_to_hbscript[] = { HB_SCRIPT_HANGUL, HB_SCRIPT_ETHIOPIC, HB_SCRIPT_CHEROKEE, - HB_SCRIPT_CANADIAN_ABORIGINAL, + HB_SCRIPT_CANADIAN_SYLLABICS, HB_SCRIPT_OGHAM, HB_SCRIPT_RUNIC, HB_SCRIPT_KHMER, @@ -218,20 +218,22 @@ static const hb_script_t _qtscript_to_hbscript[] = { HB_SCRIPT_SOYOMBO, HB_SCRIPT_ZANABAZAR_SQUARE, - // Unicode 12.1 additions (not present in harfbuzz-ng 1.7.4) - hb_script_t(HB_TAG('D', 'o', 'g', 'r')), // Script_Dogra - hb_script_t(HB_TAG('G', 'o', 'n', 'g')), // Script_GunjalaGondi - hb_script_t(HB_TAG('R', 'o', 'h', 'g')), // Script_HanifiRohingya - hb_script_t(HB_TAG('M', 'a', 'k', 'a')), // Script_Makasar - hb_script_t(HB_TAG('M', 'e', 'd', 'f')), // Script_Medefaidrin - hb_script_t(HB_TAG('S', 'o', 'g', 'o')), // Script_OldSogdian - hb_script_t(HB_TAG('S', 'o', 'g', 'd')), // Script_Sogdian - hb_script_t(HB_TAG('E', 'l', 'y', 'm')), // Script_Elymaic - hb_script_t(HB_TAG('N', 'a', 'n', 'd')), // Script_Nandinagari - hb_script_t(HB_TAG('H', 'm', 'n', 'p')), // Script_NyiakengPuachueHmong - hb_script_t(HB_TAG('W', 'c', 'h', 'o')), // Script_Wancho - - // Unicode 13.0 additions (as above) + // Unicode 11.0 additions + HB_SCRIPT_DOGRA, + HB_SCRIPT_GUNJALA_GONDI, + HB_SCRIPT_HANIFI_ROHINGYA, + HB_SCRIPT_MAKASAR, + HB_SCRIPT_MEDEFAIDRIN, + HB_SCRIPT_OLD_SOGDIAN, + HB_SCRIPT_SOGDIAN, + + // Unicode 12.0 additions + HB_SCRIPT_ELYMAIC, + HB_SCRIPT_NANDINAGARI, + HB_SCRIPT_NYIAKENG_PUACHUE_HMONG, + HB_SCRIPT_WANCHO, + + // Unicode 13.0 additions (not present in harfbuzz-ng 2.6.4) hb_script_t(HB_TAG('C', 'h', 'o', 'r')), // Script_Chorasmian hb_script_t(HB_TAG('D', 'i', 'v', 'e')), // Script_DivesAkuru hb_script_t(HB_TAG('K', 'h', 'i', 't')), // Script_KhitanSmallScript @@ -261,15 +263,6 @@ _hb_qt_unicode_combining_class(hb_unicode_funcs_t * /*ufuncs*/, return hb_unicode_combining_class_t(QChar::combiningClass(unicode)); } -static unsigned int -_hb_qt_unicode_eastasian_width(hb_unicode_funcs_t * /*ufuncs*/, - hb_codepoint_t /*unicode*/, - void * /*user_data*/) -{ - qCritical("hb_qt_unicode_eastasian_width: not implemented!"); - return 1; -} - static const hb_unicode_general_category_t _qtcategory_to_hbcategory[] = { HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // Mn HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, // Mc @@ -405,37 +398,17 @@ _hb_qt_unicode_decompose(hb_unicode_funcs_t * /*ufuncs*/, return true; } -static unsigned int -_hb_qt_unicode_decompose_compatibility(hb_unicode_funcs_t * /*ufuncs*/, - hb_codepoint_t u, - hb_codepoint_t *decomposed, - void * /*user_data*/) -{ - const QString normalized = QChar::decomposition(u); - - uint outlen = 0; - QStringIterator it(normalized); - while (it.hasNext()) { - Q_ASSERT(outlen < HB_UNICODE_MAX_DECOMPOSITION_LEN); - decomposed[outlen++] = it.next(); - } - - return outlen; -} - struct _hb_unicode_funcs_t { _hb_unicode_funcs_t() { funcs = hb_unicode_funcs_create(NULL); hb_unicode_funcs_set_combining_class_func(funcs, _hb_qt_unicode_combining_class, NULL, NULL); - hb_unicode_funcs_set_eastasian_width_func(funcs, _hb_qt_unicode_eastasian_width, NULL, NULL); hb_unicode_funcs_set_general_category_func(funcs, _hb_qt_unicode_general_category, NULL, NULL); hb_unicode_funcs_set_mirroring_func(funcs, _hb_qt_unicode_mirroring, NULL, NULL); hb_unicode_funcs_set_script_func(funcs, _hb_qt_unicode_script, NULL, NULL); hb_unicode_funcs_set_compose_func(funcs, _hb_qt_unicode_compose, NULL, NULL); hb_unicode_funcs_set_decompose_func(funcs, _hb_qt_unicode_decompose, NULL, NULL); - hb_unicode_funcs_set_decompose_compatibility_func(funcs, _hb_qt_unicode_decompose_compatibility, NULL, NULL); } ~_hb_unicode_funcs_t() { @@ -619,11 +592,6 @@ struct _hb_qt_font_funcs_t { Q_GLOBAL_STATIC(_hb_qt_font_funcs_t, qt_ffuncs) -hb_font_funcs_t *hb_qt_get_font_funcs() -{ - return qt_ffuncs()->funcs; -} - static hb_blob_t * _hb_qt_reference_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data) @@ -639,13 +607,14 @@ _hb_qt_reference_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data) return hb_blob_get_empty(); char *buffer = static_cast<char *>(malloc(length)); - Q_CHECK_PTR(buffer); + if (q_check_ptr(buffer) == nullptr) + return nullptr; if (Q_UNLIKELY(!get_font_table(data->user_data, tag, reinterpret_cast<uchar *>(buffer), &length))) - length = 0; + return nullptr; return hb_blob_create(const_cast<const char *>(buffer), length, - HB_MEMORY_MODE_READONLY, + HB_MEMORY_MODE_WRITABLE, buffer, free); } @@ -658,10 +627,6 @@ _hb_qt_face_create(QFontEngine *fe) data->get_font_table = fe->faceData.get_font_table; hb_face_t *face = hb_face_create_for_tables(_hb_qt_reference_table, (void *)data, free); - if (Q_UNLIKELY(hb_face_is_immutable(face))) { - hb_face_destroy(face); - return NULL; - } hb_face_set_index(face, fe->faceId().index); hb_face_set_upem(face, fe->emSquareSize().truncate()); @@ -672,8 +637,7 @@ _hb_qt_face_create(QFontEngine *fe) static void _hb_qt_face_release(void *user_data) { - if (Q_LIKELY(user_data)) - hb_face_destroy(static_cast<hb_face_t *>(user_data)); + hb_face_destroy(static_cast<hb_face_t *>(user_data)); } hb_face_t *hb_qt_face_get_for_engine(QFontEngine *fe) @@ -691,20 +655,13 @@ static inline hb_font_t * _hb_qt_font_create(QFontEngine *fe) { hb_face_t *face = hb_qt_face_get_for_engine(fe); - if (Q_UNLIKELY(!face)) - return NULL; hb_font_t *font = hb_font_create(face); - if (Q_UNLIKELY(hb_font_is_immutable(font))) { - hb_font_destroy(font); - return NULL; - } - const qreal y_ppem = fe->fontDef.pixelSize; const qreal x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100.0; - hb_font_set_funcs(font, hb_qt_get_font_funcs(), (void *)fe, NULL); + hb_font_set_funcs(font, qt_ffuncs()->funcs, fe, nullptr); hb_font_set_scale(font, QFixed::fromReal(x_ppem).value(), -QFixed::fromReal(y_ppem).value()); hb_font_set_ppem(font, int(x_ppem), int(y_ppem)); @@ -716,8 +673,7 @@ _hb_qt_font_create(QFontEngine *fe) static void _hb_qt_font_release(void *user_data) { - if (Q_LIKELY(user_data)) - hb_font_destroy(static_cast<hb_font_t *>(user_data)); + hb_font_destroy(static_cast<hb_font_t *>(user_data)); } hb_font_t *hb_qt_font_get_for_engine(QFontEngine *fe) diff --git a/src/gui/text/qharfbuzzng_p.h b/src/gui/text/qharfbuzzng_p.h index fabf222bae..4fb7e0aef7 100644 --- a/src/gui/text/qharfbuzzng_p.h +++ b/src/gui/text/qharfbuzzng_p.h @@ -58,24 +58,33 @@ QT_REQUIRE_CONFIG(harfbuzz); #include <QtCore/qchar.h> -#include <harfbuzz/hb.h> +#if defined(QT_BUILD_GUI_LIB) +# include <harfbuzz/hb.h> +#else +// a minimal set of HB types required for Qt libs other than Gui + +typedef struct hb_face_t hb_face_t; +typedef struct hb_font_t hb_font_t; + +#endif // QT_BUILD_GUI_LIB QT_BEGIN_NAMESPACE class QFontEngine; +#if defined(QT_BUILD_GUI_LIB) + // Unicode -Q_GUI_EXPORT hb_script_t hb_qt_script_to_script(QChar::Script script); -Q_GUI_EXPORT QChar::Script hb_qt_script_from_script(hb_script_t script); +hb_script_t hb_qt_script_to_script(QChar::Script script); +QChar::Script hb_qt_script_from_script(hb_script_t script); -Q_GUI_EXPORT hb_unicode_funcs_t *hb_qt_get_unicode_funcs(); +hb_unicode_funcs_t *hb_qt_get_unicode_funcs(); +#endif // QT_BUILD_GUI_LIB // Font -Q_GUI_EXPORT hb_font_funcs_t *hb_qt_get_font_funcs(); - Q_GUI_EXPORT hb_face_t *hb_qt_face_get_for_engine(QFontEngine *fe); Q_GUI_EXPORT hb_font_t *hb_qt_font_get_for_engine(QFontEngine *fe); diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 48ba8987f3..0e19f6866f 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -40,6 +40,7 @@ #include "qplatformfontdatabase.h" #include <QtGui/private/qfontengine_p.h> #include <QtGui/private/qfontengine_qpf2_p.h> +#include <QtGui/private/qfontdatabase_p.h> #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <qpa/qplatformscreen.h> @@ -376,16 +377,27 @@ QFontEngine *QPlatformFontDatabase::fontEngine(const QByteArray &fontData, qreal or using the font contained in the file referenced by \a fileName. Returns a list of family names, or an empty list if the font could not be added. + If \a applicationFont is non-null, its \c properties vector should be filled + with information from the loaded fonts. This is exposed through FontLoader in + Qt Quick where it is needed for disambiguating fonts in the same family. When + the function exits, the \a applicationFont should contain an entry of properties + per font in the file, or it should be empty if no font was loaded. + \note The default implementation of this function does not add an application font. Subclasses should reimplement this function to perform the necessary loading and registration of fonts. */ -QStringList QPlatformFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +QStringList QPlatformFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) { Q_UNUSED(fontData); Q_UNUSED(fileName); + Q_UNUSED(applicationFont); + + if (applicationFont != nullptr) + applicationFont->properties.clear(); qWarning("This plugin does not support application fonts"); + return QStringList(); } @@ -534,6 +546,32 @@ enum CsbBits { }; /*! + Helper function that determines the writing system support based on the contents of the OS/2 table + in the font. + + \since 6.0 +*/ +QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromOS2Table(const char *os2Table, size_t length) +{ + if (length >= 86) { + quint32 unicodeRange[4] = { + qFromBigEndian<quint32>(os2Table + 42), + qFromBigEndian<quint32>(os2Table + 46), + qFromBigEndian<quint32>(os2Table + 50), + qFromBigEndian<quint32>(os2Table + 54) + }; + quint32 codePageRange[2] = { + qFromBigEndian<quint32>(os2Table + 78), + qFromBigEndian<quint32>(os2Table + 82) + }; + + return writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + } + + return QSupportedWritingSystems(); +} + +/*! Helper function that determines the writing systems support by a given \a unicodeRange and \a codePageRange. diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index f79c5db625..2d25d9a036 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -59,6 +59,7 @@ #include <QtGui/QFontDatabase> #include <QtGui/private/qfontengine_p.h> #include <QtGui/private/qfont_p.h> +#include <QtGui/private/qfontdatabase_p.h> QT_BEGIN_NAMESPACE @@ -111,7 +112,7 @@ public: virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); 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 QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *font = nullptr); virtual void releaseHandle(void *handle); virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); @@ -127,6 +128,7 @@ public: // helper static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]); + static QSupportedWritingSystems writingSystemsFromOS2Table(const char *os2Table, size_t length); static QFont::Weight weightFromInteger(int weight); //callback diff --git a/src/gui/text/qsyntaxhighlighter.cpp b/src/gui/text/qsyntaxhighlighter.cpp index b50957d63d..8abcac5dec 100644 --- a/src/gui/text/qsyntaxhighlighter.cpp +++ b/src/gui/text/qsyntaxhighlighter.cpp @@ -173,7 +173,7 @@ void QSyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int c if (lastBlock.isValid()) endPosition = lastBlock.position() + lastBlock.length(); else - endPosition = doc->docHandle()->length(); + endPosition = QTextDocumentPrivate::get(doc)->length(); bool forceHighlightOfNextBlock = false; diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index fa323ef4bd..c579eca1ff 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -1052,7 +1052,7 @@ QTextCursor::QTextCursor() Constructs a cursor pointing to the beginning of the \a document. */ QTextCursor::QTextCursor(QTextDocument *document) - : d(new QTextCursorPrivate(document->docHandle())) + : d(new QTextCursorPrivate(QTextDocumentPrivate::get(document))) { } @@ -1060,7 +1060,7 @@ QTextCursor::QTextCursor(QTextDocument *document) Constructs a cursor pointing to the beginning of the \a frame. */ QTextCursor::QTextCursor(QTextFrame *frame) - : d(new QTextCursorPrivate(frame->document()->docHandle())) + : d(new QTextCursorPrivate(QTextDocumentPrivate::get(frame->document()))) { d->adjusted_anchor = d->anchor = d->position = frame->firstPosition(); } @@ -1070,7 +1070,7 @@ QTextCursor::QTextCursor(QTextFrame *frame) Constructs a cursor pointing to the beginning of the \a block. */ QTextCursor::QTextCursor(const QTextBlock &block) - : d(new QTextCursorPrivate(block.docHandle())) + : d(new QTextCursorPrivate(const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block)))) { d->adjusted_anchor = d->anchor = d->position = block.position(); } @@ -2264,7 +2264,7 @@ void QTextCursor::insertFragment(const QTextDocumentFragment &fragment) d->setX(); if (fragment.d && fragment.d->doc) - d->priv->mergeCachedResources(fragment.d->doc->docHandle()); + d->priv->mergeCachedResources(QTextDocumentPrivate::get(fragment.d->doc)); } /*! diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 64ba01d4e5..2b712c54b0 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -40,13 +40,13 @@ #include "qtextdocument.h" #include <qtextformat.h> #include "qtextcursor_p.h" +#include "qtextdocument_p.h" #include "qtextdocumentlayout_p.h" #include "qtextdocumentfragment.h" #include "qtextdocumentfragment_p.h" #include "qtexttable.h" #include "qtextlist.h" #include <qdebug.h> -#include <qregexp.h> #if QT_CONFIG(regularexpression) #include <qregularexpression.h> #endif @@ -1328,7 +1328,8 @@ static bool findInBlock(const QTextBlock &block, const QString &expression, int } } //we have a hit, return the cursor for that. - *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx); + *cursor = QTextCursorPrivate::fromPosition(const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block)), + block.position() + idx); cursor->setPosition(cursor->position() + expression.length(), QTextCursor::KeepAnchor); return true; } @@ -1420,139 +1421,10 @@ QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cur return find(subString, pos, options); } - -#ifndef QT_NO_REGEXP -static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int offset, - QTextDocument::FindFlags options, QTextCursor *cursor) -{ - QRegExp expr(expression); - QString text = block.text(); - text.replace(QChar::Nbsp, QLatin1Char(' ')); - - int idx = -1; - while (offset >=0 && offset <= text.length()) { - idx = (options & QTextDocument::FindBackward) ? - expr.lastIndexIn(text, offset) : expr.indexIn(text, offset); - if (idx == -1) - return false; - - if (options & QTextDocument::FindWholeWords) { - const int start = idx; - const int end = start + expr.matchedLength(); - if ((start != 0 && text.at(start - 1).isLetterOrNumber()) - || (end != text.length() && text.at(end).isLetterOrNumber())) { - //if this is not a whole word, continue the search in the string - offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1; - idx = -1; - continue; - } - } - //we have a hit, return the cursor for that. - *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx); - cursor->setPosition(cursor->position() + expr.matchedLength(), QTextCursor::KeepAnchor); - return true; - } - return false; -} - -/*! - \overload - - Finds the next occurrence that matches the given regular expression, - \a expr, within the same paragraph in the document. - - The search starts at the given \a from position, and proceeds forwards - through the document unless specified otherwise in the search options. - The \a options control the type of search performed. The FindCaseSensitively - option is ignored for this overload, use QRegExp::caseSensitivity instead. - - Returns a cursor with the match selected if a match was found; otherwise - returns a null cursor. - - If the \a from position is 0 (the default) the search begins from the beginning - of the document; otherwise it begins at the specified position. -*/ -QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags options) const -{ - Q_D(const QTextDocument); - - if (expr.isEmpty()) - return QTextCursor(); - - int pos = from; - //the cursor is positioned between characters, so for a backward search - //do not include the character given in the position. - if (options & FindBackward) { - --pos ; - if(pos < 0) - return QTextCursor(); - } - - QTextCursor cursor; - QTextBlock block = d->blocksFind(pos); - int blockOffset = pos - block.position(); - if (!(options & FindBackward)) { - while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, &cursor)) - return cursor; - block = block.next(); - blockOffset = 0; - } - } else { - while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, &cursor)) - return cursor; - block = block.previous(); - blockOffset = block.length() - 1; - } - } - - return QTextCursor(); -} - -/*! - \overload - - Finds the next occurrence that matches the given regular expression, - \a expr, within the same paragraph in the document. - - The search starts at the position of the given from \a cursor, and proceeds - forwards through the document unless specified otherwise in the search - options. The \a options control the type of search performed. The FindCaseSensitively - option is ignored for this overload, use QRegExp::caseSensitivity instead. - - Returns a cursor with the match selected if a match was found; otherwise - returns a null cursor. - - If the given \a cursor has a selection, the search begins after the - selection; otherwise it begins at the cursor's position. - - By default the search is case insensitive, and can match text anywhere in the - document. -*/ -QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const -{ - int pos = 0; - if (!cursor.isNull()) { - if (options & QTextDocument::FindBackward) - pos = cursor.selectionStart(); - else - pos = cursor.selectionEnd(); - } - return find(expr, pos, options); -} -#endif // QT_REGEXP - #if QT_CONFIG(regularexpression) -static bool findInBlock(const QTextBlock &block, const QRegularExpression &expression, int offset, +static bool findInBlock(const QTextBlock &block, const QRegularExpression &expr, int offset, QTextDocument::FindFlags options, QTextCursor *cursor) { - QRegularExpression expr(expression); - if (!(options & QTextDocument::FindCaseSensitively)) - expr.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption); - else - expr.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption); - QString text = block.text(); text.replace(QChar::Nbsp, QLatin1Char(' ')); QRegularExpressionMatch match; @@ -1576,7 +1448,8 @@ static bool findInBlock(const QTextBlock &block, const QRegularExpression &expre } } //we have a hit, return the cursor for that. - *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx); + *cursor = QTextCursorPrivate::fromPosition(const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block)), + block.position() + idx); cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor); return true; } @@ -1619,16 +1492,22 @@ QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFl QTextBlock block = d->blocksFind(pos); int blockOffset = pos - block.position(); + QRegularExpression expression(expr); + if (!(options & QTextDocument::FindCaseSensitively)) + expression.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption); + else + expression.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption); + if (!(options & FindBackward)) { while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, &cursor)) + if (findInBlock(block, expression, blockOffset, options, &cursor)) return cursor; block = block.next(); blockOffset = 0; } } else { while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, &cursor)) + if (findInBlock(block, expression, blockOffset, options, &cursor)) return cursor; block = block.previous(); blockOffset = block.length() - 1; @@ -1737,7 +1616,7 @@ QTextObject *QTextDocument::objectForFormat(const QTextFormat &f) const QTextBlock QTextDocument::findBlock(int pos) const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().findNode(pos)); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(pos)); } /*! @@ -1749,7 +1628,7 @@ QTextBlock QTextDocument::findBlock(int pos) const QTextBlock QTextDocument::findBlockByNumber(int blockNumber) const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().findNode(blockNumber, 1)); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(blockNumber, 1)); } /*! @@ -1761,7 +1640,7 @@ QTextBlock QTextDocument::findBlockByNumber(int blockNumber) const QTextBlock QTextDocument::findBlockByLineNumber(int lineNumber) const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().findNode(lineNumber, 2)); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(lineNumber, 2)); } /*! @@ -1772,7 +1651,7 @@ QTextBlock QTextDocument::findBlockByLineNumber(int lineNumber) const QTextBlock QTextDocument::begin() const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().begin().n); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n); } /*! @@ -1789,7 +1668,8 @@ QTextBlock QTextDocument::begin() const */ QTextBlock QTextDocument::end() const { - return QTextBlock(docHandle(), 0); + Q_D(const QTextDocument); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), 0); } /*! @@ -1799,7 +1679,7 @@ QTextBlock QTextDocument::end() const QTextBlock QTextDocument::firstBlock() const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().begin().n); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n); } /*! @@ -1809,7 +1689,7 @@ QTextBlock QTextDocument::firstBlock() const QTextBlock QTextDocument::lastBlock() const { Q_D(const QTextDocument); - return QTextBlock(docHandle(), d->blockMap().last().n); + return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().last().n); } /*! @@ -1893,12 +1773,14 @@ QFont QTextDocument::defaultFont() const bool QTextDocument::isModified() const { - return docHandle()->isModified(); + Q_D(const QTextDocument); + return d->isModified(); } void QTextDocument::setModified(bool m) { - docHandle()->setModified(m); + Q_D(QTextDocument); + d->setModified(m); } #ifndef QT_NO_PRINTER @@ -2276,7 +2158,11 @@ static QString colorValue(QColor color) if (color.alpha() == 255) { result = color.name(); } else if (color.alpha()) { - QString alphaValue = QString::number(color.alphaF(), 'f', 6).remove(QRegExp(QLatin1String("\\.?0*$"))); + QString alphaValue = QString::number(color.alphaF(), 'f', 6); + while (alphaValue.length() > 1 && alphaValue.at(alphaValue.size() - 1) == QLatin1Char('0')) + alphaValue.chop(1); + if (alphaValue.at(alphaValue.size() - 1) == QLatin1Char('.')) + alphaValue.chop(1); result = QString::fromLatin1("rgba(%1,%2,%3,%4)").arg(color.red()) .arg(color.green()) .arg(color.blue()) @@ -2319,7 +2205,7 @@ QString QTextHtmlExporter::toHtml(const QByteArray &encoding, ExportMode mode) html = QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" />"); - html.reserve(doc->docHandle()->length()); + html.reserve(QTextDocumentPrivate::get(doc)->length()); fragmentMarkers = (mode == ExportFragment); @@ -2779,10 +2665,10 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment) txt = txt.toHtmlEscaped(); // split for [\n{LineSeparator}] - QString forcedLineBreakRegExp = QString::fromLatin1("[\\na]"); - forcedLineBreakRegExp[3] = QChar::LineSeparator; // space in BR on purpose for compatibility with old-fashioned browsers - html += txt.replace(QRegExp(forcedLineBreakRegExp), QLatin1String("<br />")); + txt.replace(QLatin1Char('\n'), QLatin1String("<br />")); + txt.replace(QChar::LineSeparator, QLatin1String("<br />")); + html += txt; } if (attributesEmitted) @@ -2889,8 +2775,9 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block) int p = block.position(); if (p > 0) --p; - QTextDocumentPrivate::FragmentIterator frag = doc->docHandle()->find(p); - QChar ch = doc->docHandle()->buffer().at(frag->stringPosition); + + QTextDocumentPrivate::FragmentIterator frag = QTextDocumentPrivate::get(doc)->find(p); + QChar ch = QTextDocumentPrivate::get(doc)->buffer().at(frag->stringPosition); if (ch == QTextBeginningOfFrame || ch == QTextEndOfFrame) return; @@ -3008,7 +2895,7 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block) for (; !it.atEnd(); ++it) emitFragment(it.fragment()); - if (fragmentMarkers && block.position() + block.length() == doc->docHandle()->length()) + if (fragmentMarkers && block.position() + block.length() == QTextDocumentPrivate::get(doc)->length()) html += QLatin1String("<!--EndFragment-->"); if (pre) @@ -3046,27 +2933,27 @@ QString QTextHtmlExporter::findUrlForImage(const QTextDocument *doc, qint64 cach if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent())) return findUrlForImage(parent, cacheKey, isPixmap); - if (doc && doc->docHandle()) { - QTextDocumentPrivate *priv = doc->docHandle(); - QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin(); - for (; it != priv->cachedResources.constEnd(); ++it) { + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(doc); + Q_ASSERT(priv != nullptr); - const QVariant &v = it.value(); - if (v.userType() == QMetaType::QImage && !isPixmap) { - if (qvariant_cast<QImage>(v).cacheKey() == cacheKey) - break; - } + QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin(); + for (; it != priv->cachedResources.constEnd(); ++it) { - if (v.userType() == QMetaType::QPixmap && isPixmap) { - if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey) - break; - } + const QVariant &v = it.value(); + if (v.userType() == QMetaType::QImage && !isPixmap) { + if (qvariant_cast<QImage>(v).cacheKey() == cacheKey) + break; } - if (it != priv->cachedResources.constEnd()) - url = it.key().toString(); + if (v.userType() == QMetaType::QPixmap && isPixmap) { + if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey) + break; + } } + if (it != priv->cachedResources.constEnd()) + url = it.key().toString(); + return url; } @@ -3435,18 +3322,6 @@ QVector<QTextFormat> QTextDocument::allFormats() const return d->formatCollection()->formats; } - -/*! - \internal - - So that not all classes have to be friends of each other... -*/ -QTextDocumentPrivate *QTextDocument::docHandle() const -{ - Q_D(const QTextDocument); - return const_cast<QTextDocumentPrivate *>(d); -} - /*! \since 4.4 \fn QTextDocument::undoCommandAdded() diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 2459c78768..5a165331bf 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -186,11 +186,6 @@ public: QTextCursor find(const QString &subString, int from = 0, FindFlags options = FindFlags()) const; QTextCursor find(const QString &subString, const QTextCursor &cursor, FindFlags options = FindFlags()) const; -#ifndef QT_NO_REGEXP - QTextCursor find(const QRegExp &expr, int from = 0, FindFlags options = FindFlags()) const; - QTextCursor find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options = FindFlags()) const; -#endif - #if QT_CONFIG(regularexpression) QTextCursor find(const QRegularExpression &expr, int from = 0, FindFlags options = FindFlags()) const; QTextCursor find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options = FindFlags()) const; @@ -316,8 +311,6 @@ protected: Q_INVOKABLE virtual QVariant loadResource(int type, const QUrl &name); QTextDocument(QTextDocumentPrivate &dd, QObject *parent); -public: - QTextDocumentPrivate *docHandle() const; private: Q_DISABLE_COPY(QTextDocument) Q_DECLARE_PRIVATE(QTextDocument) diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index ce8e905eb0..17fe452a3f 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -65,6 +65,7 @@ #include "QtGui/qtextcursor.h" #include "QtCore/qmap.h" #include "QtCore/qvariant.h" +#include "QtCore/qset.h" #include "QtCore/qurl.h" #include "private/qcssparser_p.h" @@ -295,6 +296,36 @@ public: bool ensureMaximumBlockCount(); + static inline const QTextDocumentPrivate *get(const QTextDocument *document) + { + return document->d_func(); + } + + static inline QTextDocumentPrivate *get(QTextDocument *document) + { + return document->d_func(); + } + + static inline QTextDocumentPrivate *get(QTextBlock &block) + { + return block.p; + } + + static inline const QTextDocumentPrivate *get(const QTextBlock &block) + { + return block.p; + } + + static inline QTextDocumentPrivate *get(QTextObject *object) + { + return get(object->document()); + } + + static inline const QTextDocumentPrivate *get(const QTextObject *object) + { + return get(object->document()); + } + private: QTextDocumentPrivate(const QTextDocumentPrivate& m); QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m); diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index d7bc707491..96d690fda4 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -224,13 +224,14 @@ QTextDocumentFragmentPrivate::QTextDocumentFragmentPrivate(const QTextCursor &_c if (!_cursor.hasSelection()) return; - doc->docHandle()->beginEditBlock(); + QTextDocumentPrivate *p = QTextDocumentPrivate::get(doc); + p->beginEditBlock(); QTextCursor destCursor(doc); QTextCopyHelper(_cursor, destCursor).copy(); - doc->docHandle()->endEditBlock(); + p->endEditBlock(); if (_cursor.d) - doc->docHandle()->mergeCachedResources(_cursor.d->priv); + p->mergeCachedResources(_cursor.d->priv); } void QTextDocumentFragmentPrivate::insert(QTextCursor &_cursor) const @@ -353,7 +354,7 @@ QTextDocumentFragment::~QTextDocumentFragment() */ bool QTextDocumentFragment::isEmpty() const { - return !d || !d->doc || d->doc->docHandle()->length() <= 1; + return d == nullptr || d->doc == nullptr || QTextDocumentPrivate::get(d->doc)->length() <= 1; } /*! diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 9d70873590..91e5595fbf 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -3400,7 +3400,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout } else { currentLazyLayoutPosition = checkPoints.constLast().positionInFrame; // ####### - //checkPoints.last().positionInFrame = q->document()->docHandle()->length(); + //checkPoints.last().positionInFrame = QTextDocumentPrivate::get(q->document())->length(); } } @@ -4146,7 +4146,7 @@ int QTextDocumentLayout::layoutStatus() const int pos = d->currentLazyLayoutPosition; if (pos == -1) return 100; - return pos * 100 / d->document->docHandle()->length(); + return pos * 100 / QTextDocumentPrivate::get(d->document)->length(); } void QTextDocumentLayout::timerEvent(QTimerEvent *e) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 26e8141184..990dfa2537 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1510,7 +1510,12 @@ void QTextEngine::shapeText(int item) const itemBoundaries.append(0); } - if (Q_UNLIKELY(!shapingEnabled)) { +#if QT_CONFIG(harfbuzz) + if (Q_LIKELY(shapingEnabled && qt_useHarfbuzzNG())) { + si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0); + } else +#endif + { ushort *log_clusters = logClusters(&si); int glyph_pos = 0; @@ -1540,12 +1545,6 @@ void QTextEngine::shapeText(int item) const } si.num_glyphs = glyph_pos; -#if QT_CONFIG(harfbuzz) - } else if (Q_LIKELY(qt_useHarfbuzzNG())) { - si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0); -#endif - } else { - si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled); } if (Q_UNLIKELY(si.num_glyphs == 0)) { Q_UNREACHABLE(); // ### report shaping errors somehow @@ -1627,7 +1626,8 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, props.direction = si.analysis.bidiLevel % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; QChar::Script script = QChar::Script(si.analysis.script); props.script = hb_qt_script_to_script(script); - // ### props.language = hb_language_get_default_for_script(props.script); + // ### TODO get_default_for_script? + props.language = hb_language_get_default(); // use default language from locale for (int k = 0; k < itemBoundaries.size(); k += 3) { const uint item_pos = itemBoundaries[k]; @@ -1642,22 +1642,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, hb_buffer_clear_contents(buffer); hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16_t *>(string) + item_pos, item_length, 0, item_length); -#if defined(Q_OS_DARWIN) - // ### temporary workaround for QTBUG-38113 - // CoreText throws away the PDF token, while the OpenType backend will replace it with - // a zero-advance glyph. This becomes a real issue when PDF is the last character, - // since it gets treated like if it were a grapheme extender, so we - // temporarily replace it with some visible grapheme starter. - bool endsWithPDF = actualFontEngine->type() == QFontEngine::Mac && string[item_pos + item_length - 1] == 0x202c; - if (Q_UNLIKELY(endsWithPDF)) { - uint num_glyphs; - hb_glyph_info_t *infos = hb_buffer_get_glyph_infos(buffer, &num_glyphs); - infos[num_glyphs - 1].codepoint = '.'; - } -#endif - hb_buffer_set_segment_properties(buffer, &props); - hb_buffer_guess_segment_properties(buffer); uint buffer_flags = HB_BUFFER_FLAG_DEFAULT; // Symbol encoding used to encode various crap in the 32..255 character code range, @@ -1680,28 +1665,21 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType; const hb_feature_t features[5] = { - { HB_TAG('k','e','r','n'), !!kerningEnabled, 0, uint(-1) }, - { HB_TAG('l','i','g','a'), !dontLigate, 0, uint(-1) }, - { HB_TAG('c','l','i','g'), !dontLigate, 0, uint(-1) }, - { HB_TAG('d','l','i','g'), !dontLigate, 0, uint(-1) }, - { HB_TAG('h','l','i','g'), !dontLigate, 0, uint(-1) } }; + { HB_TAG('k','e','r','n'), !!kerningEnabled, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }, + { HB_TAG('l','i','g','a'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }, + { HB_TAG('c','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }, + { HB_TAG('d','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }, + { HB_TAG('h','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END } + }; const int num_features = dontLigate ? 5 : 1; - const char *const *shaper_list = nullptr; -#if defined(Q_OS_DARWIN) - // What's behind QFontEngine::FaceData::user_data isn't compatible between different font engines - // - specifically functions in hb-coretext.cc would run into undefined behavior with data - // from non-CoreText engine. The other shapers works with that engine just fine. - if (actualFontEngine->type() != QFontEngine::Mac) { - static const char *s_shaper_list_without_coretext[] = { - "graphite2", - "ot", - "fallback", - nullptr - }; - shaper_list = s_shaper_list_without_coretext; - } -#endif + // whitelist cross-platforms shapers only + static const char *shaper_list[] = { + "graphite2", + "ot", + "fallback", + nullptr + }; bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list); if (Q_UNLIKELY(!shapedOk)) { @@ -1753,35 +1731,11 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, while (str_pos < item_length) log_clusters[str_pos++] = last_glyph_pos; -#if defined(Q_OS_DARWIN) - if (Q_UNLIKELY(endsWithPDF)) { - int last_glyph_idx = num_glyphs - 1; - g.glyphs[last_glyph_idx] = 0xffff; - g.advances[last_glyph_idx] = QFixed(); - g.offsets[last_glyph_idx].x = QFixed(); - g.offsets[last_glyph_idx].y = QFixed(); - g.attributes[last_glyph_idx].clusterStart = true; - g.attributes[last_glyph_idx].dontPrint = true; - - log_clusters[item_length - 1] = glyphs_shaped + last_glyph_idx; - } -#endif - if (Q_UNLIKELY(engineIdx != 0)) { for (quint32 i = 0; i < num_glyphs; ++i) g.glyphs[i] |= (engineIdx << 24); } -#ifdef Q_OS_DARWIN - if (actualFontEngine->type() == QFontEngine::Mac) { - if (actualFontEngine->fontDef.stretch != 100 && actualFontEngine->fontDef.stretch != QFont::AnyStretch) { - QFixed stretch = QFixed(int(actualFontEngine->fontDef.stretch)) / QFixed(100); - for (uint i = 0; i < num_glyphs; ++i) - g.advances[i] *= stretch; - } - } -#endif - QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED if (!actualFontEngine->supportsSubPixelPositions() || (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics)) { @@ -1800,138 +1754,6 @@ QT_WARNING_POP #endif // harfbuzz - -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_Fixed) == sizeof(QFixed)); -Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint)); - -static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) -{ - if (num > 0 && destination.glyphs != source.glyphs) - memmove(destination.glyphs, source.glyphs, num * sizeof(glyph_t)); -} - -int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const -{ - HB_ShaperItem entire_shaper_item; - memset(&entire_shaper_item, 0, sizeof(entire_shaper_item)); - 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 = 0; - entire_shaper_item.item.length = itemLength; - entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel; - - entire_shaper_item.shaperFlags = 0; - if (!kerningEnabled) - entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning; - if (option.useDesignMetrics()) - entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics; - - // ensure we are not asserting in HB_HeuristicSetGlyphAttributes() - entire_shaper_item.num_glyphs = 0; - for (int i = 0; i < itemLength; ++i, ++entire_shaper_item.num_glyphs) { - if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1])) - ++i; - } - - - int remaining_glyphs = entire_shaper_item.num_glyphs; - int glyph_pos = 0; - // for each item shape using harfbuzz and store the results in our layoutData's glyphs array. - for (int k = 0; k < itemBoundaries.size(); k += 3) { - HB_ShaperItem shaper_item = entire_shaper_item; - shaper_item.item.pos = itemBoundaries[k]; - if (k + 4 < itemBoundaries.size()) { - shaper_item.item.length = itemBoundaries[k + 3] - shaper_item.item.pos; - shaper_item.num_glyphs = itemBoundaries[k + 4] - itemBoundaries[k + 1]; - } else { // last combo in the list, avoid out of bounds access. - shaper_item.item.length -= shaper_item.item.pos - entire_shaper_item.item.pos; - shaper_item.num_glyphs -= itemBoundaries[k + 1]; - } - shaper_item.initialGlyphCount = shaper_item.num_glyphs; - if (shaper_item.num_glyphs < shaper_item.item.length) - shaper_item.num_glyphs = shaper_item.item.length; - - uint engineIdx = itemBoundaries[k + 2]; - QFontEngine *actualFontEngine = fontEngine; - if (fontEngine->type() == QFontEngine::Multi) { - actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); - - if ((si.analysis.bidiLevel % 2) == 0) - shaper_item.glyphIndicesPresent = true; - } - - shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont(); - shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace(); - - remaining_glyphs -= shaper_item.initialGlyphCount; - - QVarLengthArray<HB_GlyphAttributes, 128> hbGlyphAttributes; - do { - if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) - return 0; - if (hbGlyphAttributes.size() < int(shaper_item.num_glyphs)) { - hbGlyphAttributes.resize(shaper_item.num_glyphs); - memset(hbGlyphAttributes.data(), 0, hbGlyphAttributes.size() * sizeof(HB_GlyphAttributes)); - } - - const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); - if (fontEngine->type() == QFontEngine::Multi && shaper_item.num_glyphs > shaper_item.item.length) - moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); - - shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs); - shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances); - shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets); - shaper_item.attributes = hbGlyphAttributes.data(); - - if (engineIdx != 0 && shaper_item.glyphIndicesPresent) { - for (quint32 i = 0; i < shaper_item.initialGlyphCount; ++i) - shaper_item.glyphs[i] &= 0x00ffffff; - } - - shaper_item.log_clusters = logClusters(&si) + shaper_item.item.pos - entire_shaper_item.item.pos; - } while (!qShapeItem(&shaper_item)); // this does the actual shaping via harfbuzz. - - QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs); - if (fontEngine->type() == QFontEngine::Multi) - moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); - - for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) { - HB_GlyphAttributes hbAttrs = hbGlyphAttributes.at(i); - QGlyphAttributes &attrs = g.attributes[i]; - attrs.clusterStart = hbAttrs.clusterStart; - attrs.dontPrint = hbAttrs.dontPrint; - attrs.justification = hbAttrs.justification; - } - - for (quint32 i = 0; i < shaper_item.item.length; ++i) { - // Workaround wrong log_clusters for surrogates (i.e. QTBUG-39875) - if (shaper_item.log_clusters[i] >= shaper_item.num_glyphs) - shaper_item.log_clusters[i] = shaper_item.num_glyphs - 1; - shaper_item.log_clusters[i] += glyph_pos; - } - - if (kerningEnabled && !shaper_item.kerning_applied) - actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{}); - - if (engineIdx != 0) { - for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) - g.glyphs[i] |= (engineIdx << 24); - } - - glyph_pos += shaper_item.num_glyphs; - } - - return glyph_pos; -} - void QTextEngine::init(QTextEngine *e) { e->ignoreBidi = false; @@ -1985,7 +1807,7 @@ const QCharAttributes *QTextEngine::attributes() const for (int i = 0; i < layoutData->items.size(); ++i) { const QScriptItem &si = layoutData->items.at(i); scriptItems[i].position = si.position; - scriptItems[i].script = si.analysis.script; + scriptItems[i].script = QChar::Script(si.analysis.script); } QUnicodeTools::initCharAttributes(reinterpret_cast<const ushort *>(layoutData->string.constData()), @@ -2005,7 +1827,7 @@ void QTextEngine::shape(int item) const auto &li = layoutData->items[item]; if (li.analysis.flags == QScriptAnalysis::Object) { ensureSpace(1); - if (block.docHandle()) { + if (QTextDocumentPrivate::get(block) != nullptr) { docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)), li.position + block.position(), format(&li)); @@ -2061,7 +1883,7 @@ void QTextEngine::validate() const if (layoutData) return; layoutData = new LayoutData(); - if (block.docHandle()) { + if (QTextDocumentPrivate::get(block) != nullptr) { layoutData->string = block.text(); const bool nextBlockValid = block.next().isValid(); if (!nextBlockValid && option.flags() & QTextOption::ShowDocumentTerminator) { @@ -2098,10 +1920,14 @@ void QTextEngine::itemize() const layoutData->hasBidi = bidi.process(); { - QVarLengthArray<uchar> scripts(length); - QUnicodeTools::initScripts(string, length, scripts.data()); - for (int i = 0; i < length; ++i) - analysis[i].script = scripts.at(i); + QUnicodeTools::ScriptItemArray scriptItems; + QUnicodeTools::initScripts(string, length, &scriptItems); + for (int i = 0; i < scriptItems.length(); ++i) { + const auto &item = scriptItems.at(i); + int end = i < scriptItems.length() - 1 ? scriptItems.at(i + 1).position : length; + for (int j = item.position; j < end; ++j) + analysis[j].script = item.script; + } } const ushort *uc = string; @@ -2137,26 +1963,16 @@ void QTextEngine::itemize() const analysis->flags = QScriptAnalysis::None; break; } -#if !QT_CONFIG(harfbuzz) - analysis->script = hbscript_to_script(script_to_hbscript(analysis->script)); -#endif ++uc; ++analysis; } if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) { (analysis-1)->flags = QScriptAnalysis::LineOrParagraphSeparator; // to exclude it from width } -#if QT_CONFIG(harfbuzz) - analysis = scriptAnalysis.data(); - if (!qt_useHarfbuzzNG()) { - for (int i = 0; i < length; ++i) - analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script)); - } -#endif Itemizer itemizer(layoutData->string, scriptAnalysis.data(), layoutData->items); - const QTextDocumentPrivate *p = block.docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(block); if (p) { SpecialData *s = specialData; @@ -2434,9 +2250,10 @@ QFont QTextEngine::font(const QScriptItem &si) const QTextCharFormat f = format(&si); font = f.font(); - if (block.docHandle() && block.docHandle()->layout()) { + const QTextDocumentPrivate *document_d = QTextDocumentPrivate::get(block); + if (document_d != nullptr && document_d->layout() != nullptr) { // Make sure we get the right dpi on printers - QPaintDevice *pdev = block.docHandle()->layout()->paintDevice(); + QPaintDevice *pdev = document_d->layout()->paintDevice(); if (pdev) font = QFont(font, pdev); } else { @@ -2511,9 +2328,9 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix QTextCharFormat f = format(&si); font = f.font(); - if (block.docHandle() && block.docHandle()->layout()) { + if (QTextDocumentPrivate::get(block) != nullptr && QTextDocumentPrivate::get(block)->layout() != nullptr) { // Make sure we get the right dpi on printers - QPaintDevice *pdev = block.docHandle()->layout()->paintDevice(); + QPaintDevice *pdev = QTextDocumentPrivate::get(block)->layout()->paintDevice(); if (pdev) font = QFont(font, pdev); } else { @@ -2810,10 +2627,10 @@ void QScriptLine::setDefaultHeight(QTextEngine *eng) QFont f; QFontEngine *e; - if (eng->block.docHandle() && eng->block.docHandle()->layout()) { + if (QTextDocumentPrivate::get(eng->block) != nullptr && QTextDocumentPrivate::get(eng->block)->layout() != nullptr) { f = eng->block.charFormat().font(); // Make sure we get the right dpi on printers - QPaintDevice *pdev = eng->block.docHandle()->layout()->paintDevice(); + QPaintDevice *pdev = QTextDocumentPrivate::get(eng->block)->layout()->paintDevice(); if (pdev) f = QFont(f, pdev); e = f.d->engineForScript(QChar::Script_Common); @@ -2975,7 +2792,7 @@ int QTextEngine::formatIndex(const QScriptItem *si) const return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items.at(0))); } - QTextDocumentPrivate *p = block.docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(block); if (!p) return -1; int pos = si->position; @@ -3100,7 +2917,7 @@ void QTextEngine::indexFormats() { QTextFormatCollection *collection = formatCollection(); if (!collection) { - Q_ASSERT(!block.docHandle()); + Q_ASSERT(QTextDocumentPrivate::get(block) == nullptr); specialData->formatCollection.reset(new QTextFormatCollection); collection = specialData->formatCollection.data(); } @@ -3362,8 +3179,8 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const const QScriptItem &si = layoutData->items[item]; QFixed dpiScale = 1; - if (block.docHandle() && block.docHandle()->layout()) { - QPaintDevice *pdev = block.docHandle()->layout()->paintDevice(); + if (QTextDocumentPrivate::get(block) != nullptr && QTextDocumentPrivate::get(block)->layout() != nullptr) { + QPaintDevice *pdev = QTextDocumentPrivate::get(block)->layout()->paintDevice(); if (pdev) dpiScale = QFixed::fromReal(pdev->logicalDpiY() / qreal(qt_defaultDpiY())); } else { @@ -3525,8 +3342,8 @@ void QTextEngine::resolveFormats() const } QTextCharFormat &format = resolvedFormats[i]; - if (block.docHandle()) { - // when we have a docHandle, formatIndex might still return a valid index based + if (QTextDocumentPrivate::get(block) != nullptr) { + // when we have a QTextDocumentPrivate, 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)); } diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index f069951ce5..ab4dc59594 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -525,14 +525,14 @@ public: int findItem(int strPos, int firstItem = 0) const; inline QTextFormatCollection *formatCollection() const { - if (block.docHandle()) - return block.docHandle()->formatCollection(); + if (QTextDocumentPrivate::get(block) != nullptr) + return const_cast<QTextFormatCollection *>(QTextDocumentPrivate::get(block)->formatCollection()); return specialData ? specialData->formatCollection.data() : nullptr; } QTextCharFormat format(const QScriptItem *si) const; inline QAbstractTextDocumentLayout *docLayout() const { - Q_ASSERT(block.docHandle()); - return block.docHandle()->document()->documentLayout(); + Q_ASSERT(QTextDocumentPrivate::get(block) != nullptr); + return QTextDocumentPrivate::get(block)->document()->documentLayout(); } int formatIndex(const QScriptItem *si) const; @@ -589,14 +589,14 @@ public: ItemDecorationList overlineList; inline bool visualCursorMovement() const - { return visualMovement || (block.docHandle() && block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle); } + { return visualMovement || (QTextDocumentPrivate::get(block) != nullptr && QTextDocumentPrivate::get(block)->defaultCursorMoveStyle == Qt::VisualMoveStyle); } inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; } inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); } void setPreeditArea(int position, const QString &text); inline bool hasFormats() const - { return block.docHandle() || (specialData && !specialData->formats.isEmpty()); } + { return QTextDocumentPrivate::get(block) != nullptr || (specialData && !specialData->formats.isEmpty()); } inline QVector<QTextLayout::FormatRange> formats() const { return specialData ? specialData->formats : QVector<QTextLayout::FormatRange>(); } void setFormats(const QVector<QTextLayout::FormatRange> &formats); @@ -609,7 +609,7 @@ private: QString preeditText; QVector<QTextLayout::FormatRange> formats; QVector<QTextCharFormat> resolvedFormats; - // only used when no docHandle is available + // only used when no QTextDocumentPrivate is available QScopedPointer<QTextFormatCollection> formatCollection; }; SpecialData *specialData; @@ -662,7 +662,6 @@ private: bool kerningEnabled, bool hasLetterSpacing) const; #endif - int shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const; int endOfLine(int lineNum); int beginningOfLine(int lineNum); diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 10b8ade117..e94fad8890 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -201,10 +201,9 @@ public: inline void insertProperty(qint32 key, const QVariant &value) { hashDirty = true; - if ((key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty) - || key == QTextFormat::FontLetterSpacingType) { + if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty) fontDirty = true; - } + for (int i = 0; i < props.count(); ++i) if (props.at(i).key == key) { props[i].value = value; @@ -218,10 +217,8 @@ public: for (int i = 0; i < props.count(); ++i) if (props.at(i).key == key) { hashDirty = true; - if ((key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty) - || key == QTextFormat::FontLetterSpacingType) { + if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty) fontDirty = true; - } props.remove(i); return; } @@ -444,7 +441,22 @@ void QTextFormatPrivate::recalcFont() const #ifndef QT_NO_DATASTREAM Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt) { - stream << fmt.format_type << fmt.properties(); + QMap<int, QVariant> properties = fmt.properties(); + if (stream.version() < QDataStream::Qt_6_0) { + auto it = properties.find(QTextFormat::FontLetterSpacingType); + if (it != properties.end()) { + properties[QTextFormat::OldFontLetterSpacingType] = it.value(); + properties.erase(it); + } + + it = properties.find(QTextFormat::FontStretch); + if (it != properties.end()) { + properties[QTextFormat::OldFontStretch] = it.value(); + properties.erase(it); + } + } + + stream << fmt.format_type << properties; return stream; } @@ -459,8 +471,14 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) fmt.d = new QTextFormatPrivate(); for (QMap<qint32, QVariant>::ConstIterator it = properties.constBegin(); - it != properties.constEnd(); ++it) - fmt.d->insertProperty(it.key(), it.value()); + it != properties.constEnd(); ++it) { + qint32 key = it.key(); + if (key == QTextFormat::OldFontLetterSpacingType) + key = QTextFormat::FontLetterSpacingType; + else if (key == QTextFormat::OldFontStretch) + key = QTextFormat::FontStretch; + fmt.d->insertProperty(key, it.value()); + } return stream; } @@ -620,6 +638,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) \value IsAnchor \value AnchorHref \value AnchorName + \omitvalue OldFontLetterSpacingType + \omitvalue OldFontStretch \value ObjectType List properties diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index 28da0fe344..b4db18289e 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -184,16 +184,16 @@ public: // character properties FirstFontProperty = 0x1FE0, FontCapitalization = FirstFontProperty, - FontLetterSpacingType = 0x2033, FontLetterSpacing = 0x1FE1, FontWordSpacing = 0x1FE2, - FontStretch = 0x2034, FontStyleHint = 0x1FE3, FontStyleStrategy = 0x1FE4, FontKerning = 0x1FE5, FontHintingPreference = 0x1FE6, FontFamilies = 0x1FE7, FontStyleName = 0x1FE8, + FontLetterSpacingType = 0x1FE9, + FontStretch = 0x1FEA, FontFamily = 0x2000, FontPointSize = 0x2001, FontSizeAdjustment = 0x2002, @@ -207,7 +207,7 @@ public: FontPixelSize = 0x2009, LastFontProperty = FontPixelSize, - TextUnderlineColor = 0x2010, + TextUnderlineColor = 0x2020, TextVerticalAlignment = 0x2021, TextOutline = 0x2022, TextUnderlineStyle = 0x2023, @@ -216,6 +216,12 @@ public: IsAnchor = 0x2030, AnchorHref = 0x2031, AnchorName = 0x2032, + + // Included for backwards compatibility with old QDataStreams. + // Should not be referenced in user code. + OldFontLetterSpacingType = 0x2033, + OldFontStretch = 0x2034, + ObjectType = 0x2f00, // list properties diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index f003544391..76ff99aae0 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1373,7 +1373,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration> case QCss::QtForegroundTextureCacheKey: { - if (resourceProvider != nullptr && resourceProvider->docHandle() != nullptr) { + if (resourceProvider != nullptr && QTextDocumentPrivate::get(resourceProvider) != nullptr) { bool ok; qint64 searchKey = decl.d->values.first().variant.toLongLong(&ok); if (ok) @@ -1415,7 +1415,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration> void QTextHtmlParserNode::applyForegroundImage(qint64 searchKey, const QTextDocument *resourceProvider) { - QTextDocumentPrivate *priv = resourceProvider->docHandle(); + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(resourceProvider); for (int i = 0; i < priv->formats.numFormats(); ++i) { QTextCharFormat format = priv->formats.charFormat(i); if (format.isValid()) { @@ -2110,7 +2110,7 @@ QVector<QCss::Declaration> QTextHtmlParser::declarationsForNode(int node) const + externalStyleSheets.count() + inlineStyleSheets.count()); if (resourceProvider) - selector.styleSheets[idx++] = resourceProvider->docHandle()->parsedDefaultStyleSheet; + selector.styleSheets[idx++] = QTextDocumentPrivate::get(resourceProvider)->parsedDefaultStyleSheet; for (int i = 0; i < externalStyleSheets.count(); ++i, ++idx) selector.styleSheets[idx] = externalStyleSheets.at(i).sheet; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 50faee4853..4d0a9e3a7c 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -491,8 +491,8 @@ void QTextLayout::setPreeditArea(int position, const QString &text) return; d->setPreeditArea(position, text); - if (d->block.docHandle()) - d->block.docHandle()->documentChange(d->block.position(), d->block.length()); + if (QTextDocumentPrivate::get(d->block) != nullptr) + QTextDocumentPrivate::get(d->block)->documentChange(d->block.position(), d->block.length()); } /*! @@ -538,8 +538,8 @@ void QTextLayout::setFormats(const QVector<FormatRange> &formats) { d->setFormats(formats); - if (d->block.docHandle()) - d->block.docHandle()->documentChange(d->block.position(), d->block.length()); + if (QTextDocumentPrivate::get(d->block) != nullptr) + QTextDocumentPrivate::get(d->block)->documentChange(d->block.position(), d->block.length()); } #if QT_DEPRECATED_SINCE(5, 6) @@ -1919,7 +1919,7 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.whiteSpaceOrObject = true; lbh.tmpData.length++; - if (eng->block.docHandle()) { + if (QTextDocumentPrivate::get(eng->block) != nullptr) { QTextInlineObject inlineObject(item, eng); QTextFormat f = inlineObject.format(); eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, f); @@ -2065,7 +2065,7 @@ found: line += lbh.tmpData; } - if (hasInlineObject && eng->block.docHandle()) { + if (hasInlineObject && QTextDocumentPrivate::get(eng->block) != nullptr) { // position top/bottom aligned inline objects if (maxInlineObjectHeight > line.ascent + line.descent) { // extend line height if required @@ -2571,7 +2571,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR if (eng->hasFormats()) { p->save(); - if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) { + if (si.analysis.flags == QScriptAnalysis::Object && QTextDocumentPrivate::get(eng->block)) { QFixed itemY = y - si.ascent; if (format.verticalAlignment() == QTextCharFormat::AlignTop) { itemY = y - lineBase; diff --git a/src/gui/text/qtextlist.cpp b/src/gui/text/qtextlist.cpp index 5857afa048..25f2d7adf8 100644 --- a/src/gui/text/qtextlist.cpp +++ b/src/gui/text/qtextlist.cpp @@ -304,7 +304,7 @@ void QTextList::remove(const QTextBlock &block) QTextBlockFormat fmt = block.blockFormat(); fmt.setIndent(fmt.indent() + format().indent()); fmt.setObjectIndex(-1); - block.docHandle()->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat); + const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block))->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat); } /*! @@ -316,7 +316,7 @@ void QTextList::add(const QTextBlock &block) { QTextBlockFormat fmt = block.blockFormat(); fmt.setObjectIndex(objectIndex()); - block.docHandle()->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat); + const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block))->setBlockFormat(block, block, fmt, QTextDocumentPrivate::SetFormat); } QT_END_NAMESPACE diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 77dcae0dc8..1476a8a58f 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -171,14 +171,6 @@ QTextDocument *QTextObject::document() const } /*! - \internal -*/ -QTextDocumentPrivate *QTextObject::docHandle() const -{ - return static_cast<const QTextDocument *>(parent())->docHandle(); -} - -/*! \class QTextBlockGroup \reentrant @@ -270,7 +262,7 @@ void QTextBlockGroup::blockRemoved(const QTextBlock &block) d->blocks.removeAll(block); d->markBlocksDirty(); if (d->blocks.isEmpty()) { - document()->docHandle()->deleteObject(this); + QTextDocumentPrivate::get(document())->deleteObject(this); return; } } @@ -576,7 +568,7 @@ void QTextFramePrivate::remove_me() Q_Q(QTextFrame); if (fragment_start == 0 && fragment_end == 0 && !parentFrame) { - q->document()->docHandle()->deleteObject(q); + QTextDocumentPrivate::get(q->document())->deleteObject(q); return; } @@ -630,7 +622,7 @@ void QTextFramePrivate::remove_me() */ QTextFrame::iterator QTextFrame::begin() const { - const QTextDocumentPrivate *priv = docHandle(); + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(this); int b = priv->blockMap().findNode(firstPosition()); int e = priv->blockMap().findNode(lastPosition()+1); return iterator(const_cast<QTextFrame *>(this), b, b, e); @@ -643,7 +635,7 @@ QTextFrame::iterator QTextFrame::begin() const */ QTextFrame::iterator QTextFrame::end() const { - const QTextDocumentPrivate *priv = docHandle(); + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(this); int b = priv->blockMap().findNode(firstPosition()); int e = priv->blockMap().findNode(lastPosition()+1); return iterator(const_cast<QTextFrame *>(this), e, b, e); @@ -724,7 +716,7 @@ QTextBlock QTextFrame::iterator::currentBlock() const { if (!f) return QTextBlock(); - return QTextBlock(f->docHandle(), cb); + return QTextBlock(QTextDocumentPrivate::get(f), cb); } /*! @@ -734,7 +726,7 @@ QTextBlock QTextFrame::iterator::currentBlock() const */ QTextFrame::iterator &QTextFrame::iterator::operator++() { - const QTextDocumentPrivate *priv = f->docHandle(); + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(f); const QTextDocumentPrivate::BlockMap &map = priv->blockMap(); if (cf) { int end = cf->lastPosition() + 1; @@ -772,7 +764,7 @@ QTextFrame::iterator &QTextFrame::iterator::operator++() */ QTextFrame::iterator &QTextFrame::iterator::operator--() { - const QTextDocumentPrivate *priv = f->docHandle(); + const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(f); const QTextDocumentPrivate::BlockMap &map = priv->blockMap(); if (cf) { int start = cf->firstPosition() - 1; @@ -1014,12 +1006,6 @@ bool QTextBlock::isValid() const */ /*! - \fn QTextDocumentPrivate *QTextBlock::docHandle() const - - \internal -*/ - -/*! \fn int QTextBlock::fragmentIndex() const \internal diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index 215a76fb4d..22e5e4e593 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -75,8 +75,6 @@ public: int objectIndex() const; - QTextDocumentPrivate *docHandle() const; - protected: QTextObject(QTextObjectPrivate &p, QTextDocument *doc); @@ -287,7 +285,6 @@ public: QTextBlock next() const; QTextBlock previous() const; - inline QTextDocumentPrivate *docHandle() const { return p; } inline int fragmentIndex() const { return n; } private: diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index 155ec43c50..be13615aa6 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -1036,16 +1036,16 @@ bool QTextOdfWriter::writeAll() writer.writeAttribute(officeNS, QString::fromLatin1("version"), QString::fromLatin1("1.2")); // add fragments. (for character formats) - QTextDocumentPrivate::FragmentIterator fragIt = m_document->docHandle()->begin(); + QTextDocumentPrivate::FragmentIterator fragIt = QTextDocumentPrivate::get(m_document)->begin(); QSet<int> formats; - while (fragIt != m_document->docHandle()->end()) { + while (fragIt != QTextDocumentPrivate::get(m_document)->end()) { const QTextFragmentData * const frag = fragIt.value(); formats << frag->format; ++fragIt; } // add blocks (for blockFormats) - QTextDocumentPrivate::BlockMap &blocks = m_document->docHandle()->blockMap(); + QTextDocumentPrivate::BlockMap &blocks = const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(m_document))->blockMap(); QTextDocumentPrivate::BlockMap::Iterator blockIt = blocks.begin(); while (blockIt != blocks.end()) { const QTextBlockData * const block = blockIt.value(); diff --git a/src/gui/text/qtextoption.h b/src/gui/text/qtextoption.h index 8b57278633..808076603a 100644 --- a/src/gui/text/qtextoption.h +++ b/src/gui/text/qtextoption.h @@ -48,8 +48,6 @@ QT_BEGIN_NAMESPACE - -template <typename T> class QList; struct QTextOptionPrivate; class Q_GUI_EXPORT QTextOption @@ -135,11 +133,11 @@ public: bool useDesignMetrics() const { return design; } private: - uint align : 8; + uint align : 9; uint wordWrap : 4; uint design : 1; uint direction : 2; - uint unused : 17; + uint unused : 16; uint unused2; // ### Qt 6: remove unnecessary, extra 32 bits uint f; qreal tab; diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index 39f26d5d42..ceef4d785a 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -121,7 +121,7 @@ void QTextTableCell::setFormat(const QTextCharFormat &format) QTextCharFormat fmt = format; fmt.clearProperty(QTextFormat::ObjectIndex); fmt.setObjectType(QTextFormat::TableCellObject); - QTextDocumentPrivate *p = table->docHandle(); + QTextDocumentPrivate *p = const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(table)); QTextDocumentPrivate::FragmentIterator frag(&p->fragmentMap(), fragment); QTextFormatCollection *c = p->formatCollection(); @@ -137,8 +137,8 @@ void QTextTableCell::setFormat(const QTextCharFormat &format) */ QTextCharFormat QTextTableCell::format() const { - QTextDocumentPrivate *p = table->docHandle(); - QTextFormatCollection *c = p->formatCollection(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); + const QTextFormatCollection *c = p->formatCollection(); QTextCharFormat fmt = c->charFormat(tableCellFormatIndex()); fmt.setObjectType(QTextFormat::TableCellObject); @@ -154,7 +154,7 @@ QTextCharFormat QTextTableCell::format() const */ int QTextTableCell::tableCellFormatIndex() const { - QTextDocumentPrivate *p = table->docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); return QTextDocumentPrivate::FragmentIterator(&p->fragmentMap(), fragment)->format; } @@ -248,7 +248,7 @@ QTextCursor QTextTableCell::lastCursorPosition() const */ int QTextTableCell::firstPosition() const { - QTextDocumentPrivate *p = table->docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); return p->fragmentMap().position(fragment) + 1; } @@ -259,7 +259,7 @@ int QTextTableCell::firstPosition() const */ int QTextTableCell::lastPosition() const { - QTextDocumentPrivate *p = table->docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); const QTextTablePrivate *td = table->d_func(); int index = table->d_func()->findCellIndex(fragment); int f; @@ -278,7 +278,7 @@ int QTextTableCell::lastPosition() const */ QTextFrame::iterator QTextTableCell::begin() const { - QTextDocumentPrivate *p = table->docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); int b = p->blockMap().findNode(firstPosition()); int e = p->blockMap().findNode(lastPosition()+1); return QTextFrame::iterator(const_cast<QTextTable *>(table), b, b, e); @@ -291,7 +291,7 @@ QTextFrame::iterator QTextTableCell::begin() const */ QTextFrame::iterator QTextTableCell::end() const { - QTextDocumentPrivate *p = table->docHandle(); + const QTextDocumentPrivate *p = QTextDocumentPrivate::get(table); int b = p->blockMap().findNode(firstPosition()); int e = p->blockMap().findNode(lastPosition()+1); return QTextFrame::iterator(const_cast<QTextTable *>(table), e, b, e); diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 464ff3953b..ab93975344 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -3,6 +3,7 @@ HEADERS += \ text/qfont.h \ text/qfontdatabase.h \ + text/qfontdatabase_p.h \ text/qfontengine_p.h \ text/qfontengineglyphcache_p.h \ text/qfontinfo.h \ |