diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/configure.cmake | 2 | ||||
-rw-r--r-- | src/gui/doc/src/external-resources.qdoc | 2 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 6 | ||||
-rw-r--r-- | src/gui/itemmodels/qfilesystemmodel_p.h | 5 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 5 | ||||
-rw-r--r-- | src/gui/kernel/qpalette.cpp | 21 | ||||
-rw-r--r-- | src/gui/kernel/qpointingdevice.cpp | 42 | ||||
-rw-r--r-- | src/gui/kernel/qtestsupport_gui.cpp | 24 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 9 | ||||
-rw-r--r-- | src/gui/painting/qpdf.cpp | 13 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 4 | ||||
-rw-r--r-- | src/gui/text/coretext/qcoretextfontdatabase.mm | 144 | ||||
-rw-r--r-- | src/gui/text/coretext/qcoretextfontdatabase_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext.mm | 3 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 20 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase.cpp | 22 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite.cpp | 94 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite_p.h | 3 |
19 files changed, 346 insertions, 77 deletions
diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake index cfb9f8412f..611928d13a 100644 --- a/src/gui/configure.cmake +++ b/src/gui/configure.cmake @@ -644,7 +644,7 @@ qt_feature("system-freetype" PRIVATE qt_feature("fontconfig" PUBLIC PRIVATE LABEL "Fontconfig" AUTODETECT NOT APPLE - CONDITION NOT WIN32 AND QT_FEATURE_system_freetype AND FONTCONFIG_FOUND + CONDITION NOT WIN32 AND QT_FEATURE_system_freetype AND Fontconfig_FOUND ) qt_feature_definition("fontconfig" "QT_NO_FONTCONFIG" NEGATE VALUE "1") qt_feature("gbm" diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc index d58230ed2b..6d7e2f95c0 100644 --- a/src/gui/doc/src/external-resources.qdoc +++ b/src/gui/doc/src/external-resources.qdoc @@ -32,7 +32,7 @@ */ /*! - \externalpage http://www.linux-foundation.org/en/Accessibility/IAccessible2 + \externalpage https://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/index.html \title IAccessible2 Specification */ diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index c8ce42f4b9..662be6abc9 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4661,6 +4661,8 @@ QImage QImage::smoothScaled(int w, int h) const static QImage rotated90(const QImage &image) { QImage out(image.height(), image.width(), image.format()); + if (out.isNull()) + return out; copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); @@ -4689,6 +4691,8 @@ static QImage rotated180(const QImage &image) return image.mirrored(true, true); QImage out(image.width(), image.height(), image.format()); + if (out.isNull()) + return out; copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); @@ -4701,6 +4705,8 @@ static QImage rotated180(const QImage &image) static QImage rotated270(const QImage &image) { QImage out(image.height(), image.width(), image.format()); + if (out.isNull()) + return out; copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); diff --git a/src/gui/itemmodels/qfilesystemmodel_p.h b/src/gui/itemmodels/qfilesystemmodel_p.h index fe27457b4e..35d1c85e0a 100644 --- a/src/gui/itemmodels/qfilesystemmodel_p.h +++ b/src/gui/itemmodels/qfilesystemmodel_p.h @@ -86,7 +86,10 @@ public: Q_DECLARE_TYPEINFO(QFileSystemModelNodePathKey, Q_RELOCATABLE_TYPE); -inline size_t qHash(const QFileSystemModelNodePathKey &key) { return qHash(key.toCaseFolded()); } +inline size_t qHash(const QFileSystemModelNodePathKey &key, size_t seed = 0) +{ + return qHash(key.toCaseFolded(), seed); +} #else // Q_OS_WIN typedef QString QFileSystemModelNodePathKey; #endif diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index af903f92f1..55c3fab2c2 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2650,8 +2650,9 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl { if (e->window.isNull()) return; - if (e->window.data()->d_func()->blockedByModalWindow) { - // a modal window is blocking this window, don't allow close events through + if (e->window.data()->d_func()->blockedByModalWindow && !e->window.data()->d_func()->inClose) { + // a modal window is blocking this window, don't allow close events through, unless they + // originate from a call to QWindow::close. return; } diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index f088a01c63..4ccadadee7 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -71,14 +71,25 @@ class QPalettePrivate public: class Data : public QSharedData { public: - Data() : ser_no(qt_palette_count++) { } + // Every instance of Data has to have a unique serial number, even + // if it gets created by copying another - we wouldn't create a copy + // in the first place if the serial number should be the same! + Data(const Data &other) + : QSharedData(other) + { + for (int grp = 0; grp < int(QPalette::NColorGroups); grp++) { + for (int role = 0; role < int(QPalette::NColorRoles); role++) + br[grp][role] = other.br[grp][role]; + } + } + Data() = default; QBrush br[QPalette::NColorGroups][QPalette::NColorRoles]; - const int ser_no; + const int ser_no = qt_palette_count++; }; QPalettePrivate(const QExplicitlySharedDataPointer<Data> &data) - : ref(1), detach_no(0), data(data) + : ref(1), data(data) { } QPalettePrivate() : QPalettePrivate(QExplicitlySharedDataPointer<Data>(new Data)) @@ -86,7 +97,8 @@ public: QAtomicInt ref; QPalette::ResolveMask resolveMask = {0}; - int detach_no; + static inline int qt_palette_private_count = 0; + const int detach_no = ++qt_palette_private_count; QExplicitlySharedDataPointer<Data> data; }; @@ -889,7 +901,6 @@ void QPalette::detach() delete d; d = x; } - ++d->detach_no; } /*! diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp index d02f81a8af..4ca0351287 100644 --- a/src/gui/kernel/qpointingdevice.cpp +++ b/src/gui/kernel/qpointingdevice.cpp @@ -143,6 +143,48 @@ Q_LOGGING_CATEGORY(lcPointerGrab, "qt.pointer.grab"); Any of the above (used as a default filter value). */ +/*! \enum QPointingDevice::GrabTransition + + This enum represents a transition of exclusive or passive grab + from one object (possibly \c nullptr) to another (possibly \c nullptr). + It is emitted as an argument of the QPointingDevice::grabChanged() signal. + + Valid values are: + + \value GrabExclusive + Emitted after QPointerEvent::setExclusiveGrabber(). + \value UngrabExclusive + Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is + set to \c nullptr, to notify that the grab has terminated normally. + \value CancelGrabExclusive + Emitted after QPointerEvent::setExclusiveGrabber() when the grabber is set + to a different object, to notify that the old grabber's grab is "stolen". + \value GrabPassive + Emitted after QPointerEvent::addPassiveGrabber(). + \value UngrabPassive + Emitted when a passive grab is terminated normally, + for example after QPointerEvent::removePassiveGrabber(). + \value CancelGrabPassive + Emitted when a passive grab is terminated abnormally (a gesture is canceled). + \value OverrideGrabPassive + This value is not currently used. +*/ + +/*! \fn void QPointingDevice::grabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point) const + + This signal is emitted when the \a grabber object gains or loses an + exclusive or passive grab of \a point during delivery of \a event. + The \a transition tells what happened, from the perspective of the + \c grabber object. + + \note A grab transition from one object to another results in two signals, + to notify that one object has lost its grab, and to notify that there is + another grabber. In other cases, when transitioning to or from a non-grabbing + state, only one signal is emitted: the \a grabber argument is never \c nullptr. + + \sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber() +*/ + /*! Creates a new invalid pointing device instance as a child of \a parent. */ diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp index ab48111fb5..19f4ea27df 100644 --- a/src/gui/kernel/qtestsupport_gui.cpp +++ b/src/gui/kernel/qtestsupport_gui.cpp @@ -53,9 +53,16 @@ QT_BEGIN_NAMESPACE /*! \since 5.0 - Waits for \a timeout milliseconds or until the \a window is active. + Returns \c true, if \a window is active within \a timeout milliseconds. Otherwise returns \c false. - Returns \c true if \c window is active within \a timeout milliseconds, otherwise returns \c false. + The method is useful in tests that call QWindow::show() and rely on the window actually being + active (i.e. being visible and having focus) before proceeding. + + \note The method will time out and return \c false if another window prevents \a window from + becoming active. + + \note Since focus is an exclusive property, \a window may loose its focus to another window at + any time - even after the method has returned \c true. \sa qWaitForWindowExposed(), QWindow::isActive() */ @@ -75,15 +82,14 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout) /*! \since 5.0 - Waits for \a timeout milliseconds or until the \a window is exposed. - Returns \c true if \c window is exposed within \a timeout milliseconds, otherwise returns \c false. + Returns \c true, if \a window is exposed within \a timeout milliseconds. Otherwise returns \c false. - This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some - time after being asked to show itself on the screen. + The method is useful in tests that call QWindow::show() and rely on the window actually being + being visible before proceeding. - Note that a window that is mapped to screen may still not be considered exposed if the window client - area is completely covered by other windows, or if the window is otherwise not visible. This function - will then time out when waiting for such a window. + \note A window mapped to screen may still not be considered exposed, if the window client area is + not visible, e.g. because it is completely covered by other windows. + In such cases, the method will time out and return \c false. \sa qWaitForWindowActive(), QWindow::isExposed() */ diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 7858a37d4f..be7f13f81e 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -313,15 +313,6 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() : */ /*! - \typedef QSpan - \relates QRasterPaintEngine - - A struct equivalent to QT_FT_Span, containing a position (x, - y), the span's length in pixels and its color/coverage (a value - ranging from 0 to 255). -*/ - -/*! \since 4.5 Creates a raster based paint engine for operating on the given diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 2d25b5811e..fa03388cce 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2312,16 +2312,15 @@ int QPdfEnginePrivate::writeCompressed(const char *src, int len) { #ifndef QT_NO_COMPRESS if (do_compress) { - uLongf destLen = len + len/100 + 13; // zlib requirement - Bytef* dest = new Bytef[destLen]; - if (Z_OK == ::compress(dest, &destLen, (const Bytef*) src, (uLongf)len)) { - stream->writeRawData((const char*)dest, destLen); + const QByteArray data = qCompress(reinterpret_cast<const uchar *>(src), len); + constexpr qsizetype HeaderSize = 4; + if (!data.isNull()) { + stream->writeRawData(data.data() + HeaderSize, data.size() - HeaderSize); + len = data.size() - HeaderSize; } else { qWarning("QPdfStream::writeCompressed: Error in compress()"); - destLen = 0; + len = 0; } - delete [] dest; - len = destLen; } else #endif { diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 6bb7536748..f5d002dc3c 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2902,8 +2902,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) f->glDepthMask(GL_TRUE); f->glClearDepthf(cmd.args.clear.d); } - if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT) + if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT) { + f->glStencilMask(0xFF); f->glClearStencil(GLint(cmd.args.clear.s)); + } f->glClear(cmd.args.clear.mask); cbD->graphicsPassState.reset(); // altered depth/color write, invalidate in order to avoid confusing the state tracking break; diff --git a/src/gui/text/coretext/qcoretextfontdatabase.mm b/src/gui/text/coretext/qcoretextfontdatabase.mm index bdf0e502f3..9c454fa8c3 100644 --- a/src/gui/text/coretext/qcoretextfontdatabase.mm +++ b/src/gui/text/coretext/qcoretextfontdatabase.mm @@ -114,6 +114,12 @@ QCoreTextFontDatabase::~QCoreTextFontDatabase() qDeleteAll(m_themeFonts); } +CTFontDescriptorRef descriptorForFamily(const QString &familyName) +{ + return CTFontDescriptorCreateWithAttributes(CFDictionaryRef(@{ + (id)kCTFontFamilyNameAttribute: familyName.toNSString() + })); +} void QCoreTextFontDatabase::populateFontDatabase() { qCDebug(lcQpaFonts) << "Populating font database..."; @@ -125,6 +131,110 @@ void QCoreTextFontDatabase::populateFontDatabase() for (NSString *familyName in familyNames.as<const NSArray *>()) QPlatformFontDatabase::registerFontFamily(QString::fromNSString(familyName)); + // Some fonts has special handling since macOS Catalina: It is available + // on the platform, so that it may be used by applications directly, but does not + // get enumerated. Since there are no alternatives, we hardcode it. + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSCatalina + && !qEnvironmentVariableIsSet("QT_NO_HARDCODED_FALLBACK_FONTS")) { + m_hardcodedFallbackFonts[QChar::Script_Adlam] = QStringLiteral("Noto Sans Adlam"); + m_hardcodedFallbackFonts[QChar::Script_Ahom] = QStringLiteral("Noto Serif Ahom"); + m_hardcodedFallbackFonts[QChar::Script_Avestan] = QStringLiteral("Noto Sans Avestan"); + m_hardcodedFallbackFonts[QChar::Script_Balinese] = QStringLiteral("Noto Serif Balinese"); + m_hardcodedFallbackFonts[QChar::Script_Bamum] = QStringLiteral("Noto Sans Bamum"); + m_hardcodedFallbackFonts[QChar::Script_BassaVah] = QStringLiteral("Noto Sans Bassa Vah"); + m_hardcodedFallbackFonts[QChar::Script_Batak] = QStringLiteral("Noto Sans Batak"); + m_hardcodedFallbackFonts[QChar::Script_Bhaiksuki] = QStringLiteral("Noto Sans Bhaiksuki"); + m_hardcodedFallbackFonts[QChar::Script_Brahmi] = QStringLiteral("Noto Sans Brahmi"); + m_hardcodedFallbackFonts[QChar::Script_Buginese] = QStringLiteral("Noto Sans Buginese"); + m_hardcodedFallbackFonts[QChar::Script_Buhid] = QStringLiteral("Noto Sans Buhid"); + m_hardcodedFallbackFonts[QChar::Script_Carian] = QStringLiteral("Noto Sans Carian"); + m_hardcodedFallbackFonts[QChar::Script_CaucasianAlbanian] = QStringLiteral("Noto Sans Caucasian Albanian"); + m_hardcodedFallbackFonts[QChar::Script_Chakma] = QStringLiteral("Noto Sans Chakma"); + m_hardcodedFallbackFonts[QChar::Script_Cham] = QStringLiteral("Noto Sans Cham"); + m_hardcodedFallbackFonts[QChar::Script_Coptic] = QStringLiteral("Noto Sans Coptic"); + m_hardcodedFallbackFonts[QChar::Script_Cuneiform] = QStringLiteral("Noto Sans Cuneiform"); + m_hardcodedFallbackFonts[QChar::Script_Cypriot] = QStringLiteral("Noto Sans Cypriot"); + m_hardcodedFallbackFonts[QChar::Script_Duployan] = QStringLiteral("Noto Sans Duployan"); + m_hardcodedFallbackFonts[QChar::Script_EgyptianHieroglyphs] = QStringLiteral("Noto Sans Egyptian Hieroglyphs"); + m_hardcodedFallbackFonts[QChar::Script_Elbasan] = QStringLiteral("Noto Sans Elbasan"); + m_hardcodedFallbackFonts[QChar::Script_Glagolitic] = QStringLiteral("Noto Sans Glagolitic"); + m_hardcodedFallbackFonts[QChar::Script_Gothic] = QStringLiteral("Noto Sans Gothic"); + m_hardcodedFallbackFonts[QChar::Script_HanifiRohingya] = QStringLiteral("Noto Sans Hanifi Rohingya"); + m_hardcodedFallbackFonts[QChar::Script_Hanunoo] = QStringLiteral("Noto Sans Hanunoo"); + m_hardcodedFallbackFonts[QChar::Script_Hatran] = QStringLiteral("Noto Sans Hatran"); + m_hardcodedFallbackFonts[QChar::Script_ImperialAramaic] = QStringLiteral("Noto Sans Imperial Aramaic"); + m_hardcodedFallbackFonts[QChar::Script_InscriptionalPahlavi] = QStringLiteral("Noto Sans Inscriptional Pahlavi"); + m_hardcodedFallbackFonts[QChar::Script_InscriptionalParthian] = QStringLiteral("Noto Sans Inscriptional Parthian"); + m_hardcodedFallbackFonts[QChar::Script_Javanese] = QStringLiteral("Noto Sans Javanese"); + m_hardcodedFallbackFonts[QChar::Script_Kaithi] = QStringLiteral("Noto Sans Kaithi"); + m_hardcodedFallbackFonts[QChar::Script_KayahLi] = QStringLiteral("Noto Sans Kayah Li"); + m_hardcodedFallbackFonts[QChar::Script_Kharoshthi] = QStringLiteral("Noto Sans Kharoshthi"); + m_hardcodedFallbackFonts[QChar::Script_Khojki] = QStringLiteral("Noto Sans Khojki"); + m_hardcodedFallbackFonts[QChar::Script_Khudawadi] = QStringLiteral("Noto Sans Khudawadi"); + m_hardcodedFallbackFonts[QChar::Script_Lepcha] = QStringLiteral("Noto Sans Lepcha"); + m_hardcodedFallbackFonts[QChar::Script_Limbu] = QStringLiteral("Noto Sans Limbu"); + m_hardcodedFallbackFonts[QChar::Script_LinearA] = QStringLiteral("Noto Sans Linear A"); + m_hardcodedFallbackFonts[QChar::Script_LinearB] = QStringLiteral("Noto Sans Linear B"); + m_hardcodedFallbackFonts[QChar::Script_Lisu] = QStringLiteral("Noto Sans Lisu"); + m_hardcodedFallbackFonts[QChar::Script_Lycian] = QStringLiteral("Noto Sans Lycian"); + m_hardcodedFallbackFonts[QChar::Script_Lydian] = QStringLiteral("Noto Sans Lydian"); + m_hardcodedFallbackFonts[QChar::Script_Mahajani] = QStringLiteral("Noto Sans Mahajani"); + m_hardcodedFallbackFonts[QChar::Script_Mandaic] = QStringLiteral("Noto Sans Mandaic"); + m_hardcodedFallbackFonts[QChar::Script_Manichaean] = QStringLiteral("Noto Sans Manichaean"); + m_hardcodedFallbackFonts[QChar::Script_Marchen] = QStringLiteral("Noto Sans Marchen"); + m_hardcodedFallbackFonts[QChar::Script_MendeKikakui] = QStringLiteral("Noto Sans Mende Kikakui"); + m_hardcodedFallbackFonts[QChar::Script_MeroiticCursive] = QStringLiteral("Noto Sans Meroitic"); + m_hardcodedFallbackFonts[QChar::Script_MeroiticHieroglyphs] = QStringLiteral("Noto Sans Meroitic"); + m_hardcodedFallbackFonts[QChar::Script_Miao] = QStringLiteral("Noto Sans Miao"); + m_hardcodedFallbackFonts[QChar::Script_Modi] = QStringLiteral("Noto Sans Modi"); + m_hardcodedFallbackFonts[QChar::Script_Mongolian] = QStringLiteral("Noto Sans Mongolian"); + m_hardcodedFallbackFonts[QChar::Script_Mro] = QStringLiteral("Noto Sans Mro"); + m_hardcodedFallbackFonts[QChar::Script_MeeteiMayek] = QStringLiteral("Noto Sans Meetei Mayek"); + m_hardcodedFallbackFonts[QChar::Script_Multani] = QStringLiteral("Noto Sans Multani"); + m_hardcodedFallbackFonts[QChar::Script_Nabataean] = QStringLiteral("Noto Sans Nabataean"); + m_hardcodedFallbackFonts[QChar::Script_Newa] = QStringLiteral("Noto Sans Newa"); + m_hardcodedFallbackFonts[QChar::Script_NewTaiLue] = QStringLiteral("Noto Sans New Tai Lue"); + m_hardcodedFallbackFonts[QChar::Script_Nko] = QStringLiteral("Noto Sans Nko"); + m_hardcodedFallbackFonts[QChar::Script_OlChiki] = QStringLiteral("Noto Sans Ol Chiki"); + m_hardcodedFallbackFonts[QChar::Script_OldHungarian] = QStringLiteral("Noto Sans Old Hungarian"); + m_hardcodedFallbackFonts[QChar::Script_OldItalic] = QStringLiteral("Noto Sans Old Italic"); + m_hardcodedFallbackFonts[QChar::Script_OldNorthArabian] = QStringLiteral("Noto Sans Old North Arabian"); + m_hardcodedFallbackFonts[QChar::Script_OldPermic] = QStringLiteral("Noto Sans Old Permic"); + m_hardcodedFallbackFonts[QChar::Script_OldPersian] = QStringLiteral("Noto Sans Old Persian"); + m_hardcodedFallbackFonts[QChar::Script_OldSouthArabian] = QStringLiteral("Noto Sans Old South Arabian"); + m_hardcodedFallbackFonts[QChar::Script_OldTurkic] = QStringLiteral("Noto Sans Old Turkic"); + m_hardcodedFallbackFonts[QChar::Script_Osage] = QStringLiteral("Noto Sans Osage"); + m_hardcodedFallbackFonts[QChar::Script_Osmanya] = QStringLiteral("Noto Sans Osmanya"); + m_hardcodedFallbackFonts[QChar::Script_PahawhHmong] = QStringLiteral("Noto Sans Pahawh Hmong"); + m_hardcodedFallbackFonts[QChar::Script_Palmyrene] = QStringLiteral("Noto Sans Palmyrene"); + m_hardcodedFallbackFonts[QChar::Script_PauCinHau] = QStringLiteral("Noto Sans Pau Cin Hau"); + m_hardcodedFallbackFonts[QChar::Script_PhagsPa] = QStringLiteral("Noto Sans PhagsPa"); + m_hardcodedFallbackFonts[QChar::Script_Phoenician] = QStringLiteral("Noto Sans Phoenician"); + m_hardcodedFallbackFonts[QChar::Script_PsalterPahlavi] = QStringLiteral("Noto Sans Psalter Pahlavi"); + m_hardcodedFallbackFonts[QChar::Script_Rejang] = QStringLiteral("Noto Sans Rejang"); + m_hardcodedFallbackFonts[QChar::Script_Samaritan] = QStringLiteral("Noto Sans Samaritan"); + m_hardcodedFallbackFonts[QChar::Script_Saurashtra] = QStringLiteral("Noto Sans Saurashtra"); + m_hardcodedFallbackFonts[QChar::Script_Sharada] = QStringLiteral("Noto Sans Sharada"); + m_hardcodedFallbackFonts[QChar::Script_Siddham] = QStringLiteral("Noto Sans Siddham"); + m_hardcodedFallbackFonts[QChar::Script_SoraSompeng] = QStringLiteral("Noto Sans Sora Sompeng"); + m_hardcodedFallbackFonts[QChar::Script_Sundanese] = QStringLiteral("Noto Sans Sundanese"); + m_hardcodedFallbackFonts[QChar::Script_SylotiNagri] = QStringLiteral("Noto Sans Syloti Nagri"); + m_hardcodedFallbackFonts[QChar::Script_Tagalog] = QStringLiteral("Noto Sans Tagalog"); + m_hardcodedFallbackFonts[QChar::Script_Tagbanwa] = QStringLiteral("Noto Sans Tagbanwa"); + m_hardcodedFallbackFonts[QChar::Script_Takri] = QStringLiteral("Noto Sans Takri"); + m_hardcodedFallbackFonts[QChar::Script_TaiLe] = QStringLiteral("Noto Sans Tai Le"); + m_hardcodedFallbackFonts[QChar::Script_TaiTham] = QStringLiteral("Noto Sans Tai Tham"); + m_hardcodedFallbackFonts[QChar::Script_TaiViet] = QStringLiteral("Noto Sans Tai Viet"); + m_hardcodedFallbackFonts[QChar::Script_Thaana] = QStringLiteral("Noto Sans Thaana"); + m_hardcodedFallbackFonts[QChar::Script_Tifinagh] = QStringLiteral("Noto Sans Tifinagh"); + m_hardcodedFallbackFonts[QChar::Script_Tirhuta] = QStringLiteral("Noto Sans Tirhuta"); + m_hardcodedFallbackFonts[QChar::Script_Ugaritic] = QStringLiteral("Noto Sans Ugaritic"); + m_hardcodedFallbackFonts[QChar::Script_Vai] = QStringLiteral("Noto Sans Vai"); + m_hardcodedFallbackFonts[QChar::Script_WarangCiti] = QStringLiteral("Noto Sans Warang Citi"); + m_hardcodedFallbackFonts[QChar::Script_Wancho] = QStringLiteral("Noto Sans Wancho"); + m_hardcodedFallbackFonts[QChar::Script_Yi] = QStringLiteral("Noto Sans Yi"); + } + qCDebug(lcQpaFonts) << "Populating available families took" << elapsed.restart() << "ms"; populateThemeFonts(); @@ -198,13 +308,6 @@ bool QCoreTextFontDatabase::populateFamilyAliases(const QString &missingFamily) #endif } -CTFontDescriptorRef descriptorForFamily(const QString &familyName) -{ - return CTFontDescriptorCreateWithAttributes(CFDictionaryRef(@{ - (id)kCTFontFamilyNameAttribute: familyName.toNSString() - })); -} - CTFontDescriptorRef descriptorForFamily(const char *familyName) { return descriptorForFamily(QString::fromLatin1(familyName)); @@ -594,6 +697,31 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo // add Apple Symbols to cover those too. if (!fallbackList.contains(QStringLiteral("Apple Symbols"))) fallbackList.append(QStringLiteral("Apple Symbols")); + // Some Noto* fonts are not automatically enumerated by system, despite being the main + // fonts for their writing system. + QString hardcodedFont = m_hardcodedFallbackFonts.value(script); + if (!hardcodedFont.isEmpty() && !fallbackList.contains(hardcodedFont)) { + if (!isFamilyPopulated(hardcodedFont)) { + if (!m_privateFamilies.contains(hardcodedFont)) { + QCFType<CTFontDescriptorRef> familyDescriptor = descriptorForFamily(hardcodedFont); + QCFType<CFArrayRef> matchingFonts = CTFontDescriptorCreateMatchingFontDescriptors(familyDescriptor, nullptr); + if (matchingFonts) { + const int numFonts = CFArrayGetCount(matchingFonts); + for (int i = 0; i < numFonts; ++i) + const_cast<QCoreTextFontDatabase *>(this)->populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)), + hardcodedFont); + + fallbackList.append(hardcodedFont); + } + + // Register as private family even if the font is not found, in order to avoid + // redoing the check later. In later calls, the font will then just be ignored. + m_privateFamilies.insert(hardcodedFont); + } + } else { + fallbackList.append(hardcodedFont); + } + } #endif extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); @@ -644,7 +772,7 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const { - if (family.startsWith(QLatin1Char('.')) || family == QLatin1String("LastResort")) + if (family.startsWith(QLatin1Char('.')) || family == QLatin1String("LastResort") || m_privateFamilies.contains(family)) return true; return QPlatformFontDatabase::isPrivateFontFamily(family); diff --git a/src/gui/text/coretext/qcoretextfontdatabase_p.h b/src/gui/text/coretext/qcoretextfontdatabase_p.h index c07ed57d31..91508afb22 100644 --- a/src/gui/text/coretext/qcoretextfontdatabase_p.h +++ b/src/gui/text/coretext/qcoretextfontdatabase_p.h @@ -93,6 +93,8 @@ private: QHash<QPlatformTheme::Font, QFont *> m_themeFonts; QHash<QString, QList<QCFType<CTFontDescriptorRef>>> m_systemFontDescriptors; + QHash<QChar::Script, QString> m_hardcodedFallbackFonts; + mutable QSet<QString> m_privateFamilies; bool m_hasPopulatedAliases; }; diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm index 57738ef9fc..e38af34d5b 100644 --- a/src/gui/text/coretext/qfontengine_coretext.mm +++ b/src/gui/text/coretext/qfontengine_coretext.mm @@ -422,7 +422,8 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight); - CGAffineTransformConcat(cgMatrix, oldTextMatrix); + // FIXME: Should we include the old matrix here? If so we need to assign it. + Q_UNUSED(CGAffineTransformConcat(cgMatrix, oldTextMatrix)); if (synthesisFlags & QFontEngine::SynthesizedItalic) cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index b263c9c00a..b8d21c9a8e 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1282,7 +1282,6 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition QFixed base = sl.base(); QFixed descent = sl.descent; - QFixed cursorDescent = descent; bool rightToLeft = d->isRightToLeft(); const int realCursorPosition = cursorPosition; @@ -1311,15 +1310,16 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition si = &d->layoutData->items[itm]; } } - if (si->ascent >= 0) - base = si->ascent; - if (si->descent == 0) - descent = si->descent; - else if (si->descent > 0 && si->descent < descent) - cursorDescent = si->descent; + // objects need some special treatment as they can have special alignment or be floating + if (si->analysis.flags != QScriptAnalysis::Object) { + if (si->ascent > 0) + base = si->ascent; + if (si->descent > 0) + descent = si->descent; + } rightToLeft = si->analysis.bidiLevel % 2; } - qreal y = position.y() + (sl.y + sl.base() + sl.descent - base - descent).toReal(); + qreal y = position.y() + (sl.y + sl.base() - base).toReal(); bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing) && (p->transform().type() > QTransform::TxTranslate); if (toggleAntialiasing) @@ -1330,7 +1330,7 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition const QTransform &deviceTransform = p->deviceTransform(); const qreal xScale = deviceTransform.m11(); if (deviceTransform.type() != QTransform::TxScale || std::trunc(xScale) == xScale) { - p->fillRect(QRectF(x, y, qreal(width), (base + cursorDescent).toReal()), p->pen().brush()); + p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush()); } else { // Ensure consistently rendered cursor width under fractional scaling const QPen origPen = p->pen(); @@ -1338,7 +1338,7 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition pen.setCosmetic(true); const qreal center = x + qreal(width) / 2; p->setPen(pen); - p->drawLine(QPointF(center, y), QPointF(center, y + (base + cursorDescent).toReal())); + p->drawLine(QPointF(center, y), QPointF(center, y + (base + descent).toReal())); p->setPen(origPen); } p->setCompositionMode(origCompositionMode); diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index 47ef300cfa..0c190bc02e 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -604,16 +604,9 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory } #endif // directwrite && direct2d -static int s_defaultVerticalDPI = 96; // Native Pixels - int QWindowsFontDatabaseBase::defaultVerticalDPI() { - return s_defaultVerticalDPI; -} - -void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d) -{ - s_defaultVerticalDPI = d; + return 96; } LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName) @@ -728,9 +721,9 @@ HFONT QWindowsFontDatabaseBase::systemFont() QFont QWindowsFontDatabaseBase::systemDefaultFont() { // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610) - NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + NONCLIENTMETRICS ncm = {}; + ncm.cbSize = sizeof(ncm); + SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI()); const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; return systemFont; @@ -789,6 +782,13 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra } #endif // directwrite && direct2d +QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QFontDef &fontDef, void *handle) +{ + // This function was apparently not used before, and probably isn't now either, + // call the base implementation which just prints that it's not supported. + return QPlatformFontDatabase::fontEngine(fontDef, handle); +} + QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { QFontEngine *fontEngine = nullptr; diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h index 158991a796..b161721bb7 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h @@ -89,10 +89,10 @@ public: QWindowsFontDatabaseBase(); ~QWindowsFontDatabaseBase() override; + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; static int defaultVerticalDPI(); - static void setDefaultVerticalDPI(int d); static QSharedPointer<QWindowsFontEngineData> data(); #if QT_CONFIG(directwrite) diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index 55aab15132..210036f080 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -101,7 +101,7 @@ namespace { }; void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, - UINT bezierCount) + UINT bezierCount) noexcept { for (uint i=0; i<bezierCount; ++i) { QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1); @@ -112,48 +112,48 @@ namespace { } } - void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) + void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) noexcept { for (uint i=0; i<pointsCount; ++i) m_path->lineTo(fromD2D1_POINT_2F(points[i])); } void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint, - D2D1_FIGURE_BEGIN /*figureBegin*/) + D2D1_FIGURE_BEGIN /*figureBegin*/) noexcept { m_startPoint = fromD2D1_POINT_2F(startPoint); m_path->moveTo(m_startPoint); } - IFACEMETHODIMP GeometrySink::Close() + IFACEMETHODIMP GeometrySink::Close() noexcept { return E_NOTIMPL; } - void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) + void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) noexcept { if (figureEnd == D2D1_FIGURE_END_CLOSED) m_path->closeSubpath(); } - void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) + void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) noexcept { m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE ? Qt::OddEvenFill : Qt::WindingFill); } - void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) + void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) noexcept { /* Not implemented */ } - IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() + IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() noexcept { return InterlockedIncrement(&m_refCount); } - IFACEMETHODIMP_(unsigned long) GeometrySink::Release() + IFACEMETHODIMP_(unsigned long) GeometrySink::Release() noexcept { unsigned long newCount = InterlockedDecrement(&m_refCount); if (newCount == 0) @@ -165,7 +165,7 @@ namespace { return newCount; } - IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) + IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) noexcept { if (__uuidof(IDWriteGeometrySink) == riid) { *ppvObject = this; @@ -530,6 +530,53 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn } } +void QWindowsFontEngineDirectWrite::getUnscaledGlyph(glyph_t glyph, + QPainterPath *path, + glyph_metrics_t *metric) +{ + float advance = 0.0f; + UINT16 g = glyph; + DWRITE_GLYPH_OFFSET offset; + offset.advanceOffset = 0; + offset.ascenderOffset = 0; + GeometrySink geometrySink(path); + HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(m_unitsPerEm, + &g, + &advance, + &offset, + 1, + false, + false, + &geometrySink); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__); + return; + } + + DWRITE_GLYPH_METRICS glyphMetrics; + hr = m_directWriteFontFace->GetDesignGlyphMetrics(&g, 1, &glyphMetrics); + if (FAILED(hr)) { + qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); + return; + } + + QFixed advanceWidth = QFixed(int(glyphMetrics.advanceWidth)); + QFixed leftSideBearing = QFixed(glyphMetrics.leftSideBearing); + QFixed rightSideBearing = QFixed(glyphMetrics.rightSideBearing); + QFixed advanceHeight = QFixed(int(glyphMetrics.advanceHeight)); + QFixed verticalOriginY = QFixed(glyphMetrics.verticalOriginY); + QFixed topSideBearing = QFixed(glyphMetrics.topSideBearing); + QFixed bottomSideBearing = QFixed(glyphMetrics.bottomSideBearing); + QFixed width = advanceWidth - leftSideBearing - rightSideBearing; + QFixed height = advanceHeight - topSideBearing - bottomSideBearing; + *metric = glyph_metrics_t(leftSideBearing, + -verticalOriginY + topSideBearing, + width, + height, + advanceWidth, + 0); +} + void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) { @@ -651,6 +698,33 @@ bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const return true; } +QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const +{ + IDWriteFontFace2 *directWriteFontFace2; + if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), + reinterpret_cast<void **>(&directWriteFontFace2)))) { + DWRITE_FONT_METRICS1 metrics; + directWriteFontFace2->GetMetrics(&metrics); + + Properties p = QFontEngine::properties(); + p.emSquare = metrics.designUnitsPerEm; + p.boundingBox = QRectF(metrics.glyphBoxLeft, + -metrics.glyphBoxTop, + metrics.glyphBoxRight - metrics.glyphBoxLeft, + metrics.glyphBoxTop - metrics.glyphBoxBottom); + p.ascent = metrics.ascent; + p.descent = metrics.descent; + p.leading = metrics.lineGap; + p.capHeight = metrics.capHeight; + p.lineWidth = metrics.underlineThickness; + + directWriteFontFace2->Release(); + return p; + } else { + return QFontEngine::properties(); + } +} + QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, int margin, diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index 06eb5ae475..dd2b16048b 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -134,6 +134,9 @@ public: void initializeHeightMetrics() const override; + Properties properties() const override; + void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; + private: QImage imageForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, |