diff options
Diffstat (limited to 'src/gui')
22 files changed, 193 insertions, 74 deletions
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp index 7ae9a57f01f..4e6f9f028f8 100644 --- a/src/gui/image/qmovie.cpp +++ b/src/gui/image/qmovie.cpp @@ -320,7 +320,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) // For an animated image format, QImageIOHandler::nextImageDelay() should // provide the time to wait until showing the next frame; but multi-frame // formats are not expected to provide this value, so use 1000 ms by default. - const int nextFrameDelay = supportsAnimation ? reader->nextImageDelay() : 1000; + const auto nextFrameDelay = [&]() { return supportsAnimation ? reader->nextImageDelay() : 1000; }; if (cacheMode == QMovie::CacheNone) { if (frameNumber != currentFrameNumber+1) { @@ -364,7 +364,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) } if (frameNumber > greatestFrameNumber) greatestFrameNumber = frameNumber; - return QFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay); + return QFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); } else if (frameNumber != 0) { // We've read all frames now. Return an end marker haveReadAll = true; @@ -392,7 +392,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) return QFrameInfo(); // Invalid } greatestFrameNumber = i; - QFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay); + QFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); // Cache it! frameMap.insert(i, info); if (i == frameNumber) { diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index c9b12c15f8c..615a36fa36a 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -554,10 +554,10 @@ bool QPngHandlerPrivate::readPngHeader() #endif png_uint_32 profLen; png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen); - colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen)); - if (!colorSpace.isValid()) { - qCDebug(lcImageIo) << "QPngHandler: Failed to parse ICC profile"; - } else { + Q_UNUSED(name); + Q_UNUSED(compressionType); + if (profLen > 0) { + colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen)); QColorSpacePrivate *csD = QColorSpacePrivate::get(colorSpace); if (csD->description.isEmpty()) csD->description = QString::fromLatin1((const char *)name); @@ -926,15 +926,15 @@ bool QPNGImageWriter::writeImage(const QImage& image, int compression_in, const color_type, 0, 0, 0); // sets #channels #ifdef PNG_iCCP_SUPPORTED - if (image.colorSpace().isValid()) { - QColorSpace cs = image.colorSpace(); - // Support the old gamma making it override transferfunction. - if (gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma)) - cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma); + QColorSpace cs = image.colorSpace(); + // Support the old gamma making it override transferfunction (if possible) + if (cs.isValid() && gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma)) + cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma); + QByteArray iccProfile = cs.iccProfile(); + if (!iccProfile.isEmpty()) { QByteArray iccProfileName = cs.description().toLatin1(); if (iccProfileName.isEmpty()) iccProfileName = QByteArrayLiteral("Custom"); - QByteArray iccProfile = cs.iccProfile(); png_set_iCCP(png_ptr, info_ptr, #if PNG_LIBPNG_VER < 10500 iccProfileName.data(), PNG_COMPRESSION_TYPE_BASE, iccProfile.data(), diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d2bf905edab..6e0867530d0 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4460,8 +4460,6 @@ Q_IMPL_EVENT_COMMON(QWindowStateChangeEvent) */ /*! - \deprecated [6.2] Use another constructor. - Constructs a QTouchEvent with the given \a eventType, \a device, \a touchPoints, and current keyboard \a modifiers at the time of the event. */ diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index ef633d093a1..a3b3d26e4ba 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -140,7 +140,6 @@ public: bool hasCursor = false; #endif - bool compositing = false; QElapsedTimer lastComposeTime; #if QT_CONFIG(vulkan) diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp index e1a21c2d860..13a8bdb1574 100644 --- a/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -17,6 +17,7 @@ QBackingStoreDefaultCompositor::~QBackingStoreDefaultCompositor() void QBackingStoreDefaultCompositor::reset() { + m_rhi = nullptr; delete m_psNoBlend; m_psNoBlend = nullptr; delete m_psBlend; diff --git a/src/gui/painting/qbackingstorerhisupport.cpp b/src/gui/painting/qbackingstorerhisupport.cpp index 530de60e88b..9e0e1b00441 100644 --- a/src/gui/painting/qbackingstorerhisupport.cpp +++ b/src/gui/painting/qbackingstorerhisupport.cpp @@ -181,13 +181,14 @@ QRhiSwapChain *QBackingStoreRhiSupport::swapChainForWindow(QWindow *window) bool QBackingStoreRhiSupportWindowWatcher::eventFilter(QObject *obj, QEvent *event) { - if (event->type() == QEvent::PlatformSurface - && static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + if (event->type() == QEvent::WindowAboutToChangeInternal + || (event->type() == QEvent::PlatformSurface + && static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)) { QWindow *window = qobject_cast<QWindow *>(obj); auto it = m_rhiSupport->m_swapchains.find(window); if (it != m_rhiSupport->m_swapchains.end()) { - qCDebug(lcQpaBackingStore) << "SurfaceAboutToBeDestroyed received for tracked window" << window << "cleaning up swapchain"; + qCDebug(lcQpaBackingStore) << event << "received for" << window << "- cleaning up swapchain"; auto data = *it; m_rhiSupport->m_swapchains.erase(it); data.reset(); // deletes 'this' diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp index 77aae9ec49a..d21bf6b4d93 100644 --- a/src/gui/painting/qicc.cpp +++ b/src/gui/painting/qicc.cpp @@ -63,7 +63,7 @@ enum class ColorSpaceType : quint32 { }; enum class ProfileClass : quint32 { - Input = IccTag('s', 'c', 'r', 'n'), + Input = IccTag('s', 'c', 'n', 'r'), Display = IccTag('m', 'n', 't', 'r'), // Not supported: Output = IccTag('p', 'r', 't', 'r'), diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index a50f5aec60e..b9568ae64e0 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3390,16 +3390,18 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp // Boundaries int w = image.width(); int h = image.height(); - int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height()); - int ymin = qMax(qRound(pos.y()), 0); - int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width()); - int xmin = qMax(qRound(pos.x()), 0); + int px = qRound(pos.x()); + int py = qRound(pos.y()); + int ymax = qMin(py + h, d->rasterBuffer->height()); + int ymin = qMax(py, 0); + int xmax = qMin(px + w, d->rasterBuffer->width()); + int xmin = qMax(px, 0); - int x_offset = xmin - qRound(pos.x()); + int x_offset = xmin - px; QImage::Format format = image.format(); for (int y = ymin; y < ymax; ++y) { - const uchar *src = image.scanLine(y - qRound(pos.y())); + const uchar *src = image.scanLine(y - py); if (format == QImage::Format_MonoLSB) { for (int x = 0; x < xmax - xmin; ++x) { int src_x = x + x_offset; @@ -3799,7 +3801,7 @@ void QClipData::initialize() return; if (!m_clipLines) - m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight); + m_clipLines = (ClipLine *)calloc(clipSpanHeight, sizeof(ClipLine)); Q_CHECK_PTR(m_clipLines); QT_TRY { diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 69473ef0f45..c76527d8dff 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -517,10 +517,8 @@ QPainterPath::QPainterPath(const QPainterPath &other) = default; */ QPainterPath::QPainterPath(const QPointF &startPoint) - : d_ptr(new QPainterPathPrivate) + : d_ptr(new QPainterPathPrivate(startPoint)) { - Element e = { startPoint.x(), startPoint.y(), MoveToElement }; - d_func()->elements << e; } void QPainterPath::detach() diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h index 55164bc3477..a07b6cca37d 100644 --- a/src/gui/painting/qpainterpath_p.h +++ b/src/gui/painting/qpainterpath_p.h @@ -119,6 +119,21 @@ public: { } + QPainterPathPrivate(QPointF startPoint) + : QSharedData(), + elements{ { startPoint.x(), startPoint.y(), QPainterPath::MoveToElement } }, + cStart(0), + fillRule(Qt::OddEvenFill), + bounds(startPoint, QSizeF(0, 0)), + controlBounds(startPoint, QSizeF(0, 0)), + require_moveTo(false), + dirtyBounds(false), + dirtyControlBounds(false), + convex(false), + pathConverter(nullptr) + { + } + QPainterPathPrivate(const QPainterPathPrivate &other) noexcept : QSharedData(other), elements(other.elements), diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 82e7778b86a..f7c4df40c84 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -379,6 +379,7 @@ void QPlatformBackingStore::graphicsDeviceReportedLost() return; qWarning("Rhi backingstore: graphics device lost, attempting to reinitialize"); + d_ptr->compositor.reset(); d_ptr->rhiSupport.reset(); d_ptr->rhiSupport.create(); if (!d_ptr->rhiSupport.rhi()) diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 40453574aaf..02cb9022f4e 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -36,7 +36,6 @@ class QPlatformGraphicsBuffer; class QRhi; class QRhiTexture; class QRhiResourceUpdateBatch; -class QRhiSwapChain; struct Q_GUI_EXPORT QPlatformBackingStoreRhiConfig { @@ -172,7 +171,6 @@ public: void setRhiConfig(const QPlatformBackingStoreRhiConfig &config); QRhi *rhi() const; - QRhiSwapChain *rhiSwapChain() const; void surfaceAboutToBeDestroyed(); void graphicsDeviceReportedLost(); diff --git a/src/gui/platform/unix/qxkbcommon_p.h b/src/gui/platform/unix/qxkbcommon_p.h index 96a209cb262..2f1c37758d3 100644 --- a/src/gui/platform/unix/qxkbcommon_p.h +++ b/src/gui/platform/unix/qxkbcommon_p.h @@ -63,7 +63,46 @@ public: return sym >= 0x20 && sym <= 0xff; } static bool isKeypad(xkb_keysym_t sym) { - return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9; + switch (sym) { + case XKB_KEY_KP_Space: + case XKB_KEY_KP_Tab: + case XKB_KEY_KP_Enter: + case XKB_KEY_KP_F1: + case XKB_KEY_KP_F2: + case XKB_KEY_KP_F3: + case XKB_KEY_KP_F4: + case XKB_KEY_KP_Home: + case XKB_KEY_KP_Left: + case XKB_KEY_KP_Up: + case XKB_KEY_KP_Right: + case XKB_KEY_KP_Down: + case XKB_KEY_KP_Prior: + case XKB_KEY_KP_Next: + case XKB_KEY_KP_End: + case XKB_KEY_KP_Begin: + case XKB_KEY_KP_Insert: + case XKB_KEY_KP_Delete: + case XKB_KEY_KP_Equal: + case XKB_KEY_KP_Multiply: + case XKB_KEY_KP_Add: + case XKB_KEY_KP_Separator: + case XKB_KEY_KP_Subtract: + case XKB_KEY_KP_Decimal: + case XKB_KEY_KP_Divide: + case XKB_KEY_KP_0: + case XKB_KEY_KP_1: + case XKB_KEY_KP_2: + case XKB_KEY_KP_3: + case XKB_KEY_KP_4: + case XKB_KEY_KP_5: + case XKB_KEY_KP_6: + case XKB_KEY_KP_7: + case XKB_KEY_KP_8: + case XKB_KEY_KP_9: + return true; + default: + return false; + } } static void setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context); diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index bf65b90aef5..0c468560813 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -4736,8 +4736,12 @@ void QD3D11SwapChain::destroy() } QRHI_RES_RHI(QRhiD3D11); - if (rhiD) + if (rhiD) { rhiD->unregisterResource(this); + // See Deferred Destruction Issues with Flip Presentation Swap Chains in + // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-flush + rhiD->context->Flush(); + } } QRhiCommandBuffer *QD3D11SwapChain::currentFrameCommandBuffer() @@ -5078,8 +5082,11 @@ bool QD3D11SwapChain::createOrResize() } } if (FAILED(hr)) { - qWarning("Failed to create D3D11 swapchain: %s", - qPrintable(QSystemError::windowsComString(hr))); + qWarning("Failed to create D3D11 swapchain: %s" + " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)", + qPrintable(QSystemError::windowsComString(hr)), + desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count, + desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo)); return false; } rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES); diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index f597f06935a..f79f3a8e781 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -4388,6 +4388,7 @@ QByteArray QRhiVulkan::pipelineCacheData() header.deviceId = physDevProperties.deviceID; header.dataSize = quint32(dataSize); header.uuidSize = VK_UUID_SIZE; + header.reserved = 0; memcpy(data.data(), &header, headerSize); memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index bff8af80b1c..8e515a79810 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2502,6 +2502,35 @@ QDataStream &operator>>(QDataStream &s, QFont &font) info object is \e not updated. \endlist + \section1 Checking for the existence of a font + + Sometimes it can be useful to check if a font exists before attempting + to use it. The most thorough way of doing so is by using \l {exactMatch()}: + + \code + const QFont segoeFont(QLatin1String("Segoe UI")); + if (QFontInfo(segoeFont).exactMatch()) { + // Use the font... + } + \endcode + + However, this deep search of families can be expensive on some platforms. + \c QFontDatabase::families().contains() is a faster, but less thorough + alternative: + + \code + const QLatin1String segoeUiFamilyName("Segoe UI"); + if (QFontDatabase::families().contains(segoeUiFamilyName)) { + const QFont segoeFont(segoeUiFamilyName); + // Use the font... + } + \endcode + + It's less thorough because it's not a complete search: some font family + aliases may be missing from the list. However, this approach results in + faster application startup times, and so should always be preferred if + possible. + \sa QFont, QFontMetrics, QFontDatabase */ @@ -2518,6 +2547,8 @@ QDataStream &operator>>(QDataStream &s, QFont &font) Use QPainter::fontInfo() to get the font info when painting. This will give correct results also when painting on paint device that is not screen-compatible. + + \sa {Checking for the existence of a font} */ QFontInfo::QFontInfo(const QFont &font) : d(font.d) @@ -2559,7 +2590,7 @@ QFontInfo &QFontInfo::operator=(const QFontInfo &fi) /*! Returns the family name of the matched window system font. - \sa QFont::family() + \sa QFont::family(), {Checking for the existence of a font} */ QString QFontInfo::family() const { diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index ebaa78adab6..dc05aa322fd 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1862,8 +1862,7 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, && ucs4 != QChar::LineSeparator && ucs4 != QChar::LineFeed && ucs4 != QChar::CarriageReturn - && ucs4 != QChar::ParagraphSeparator - && QChar::category(ucs4) != QChar::Other_PrivateUse) { + && ucs4 != QChar::ParagraphSeparator) { if (!m_fallbackFamiliesQueried) const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried(); for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) { diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 254960522db..7474fc996bc 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -2205,17 +2205,15 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p } case QTextListFormat::ListSquare: if (!marker) - painter->fillRect(r, brush); + painter->fillRect(r, painter->pen().brush()); break; case QTextListFormat::ListCircle: - if (!marker) { - painter->setPen(QPen(brush, 0)); + if (!marker) painter->drawEllipse(r.translated(0.5, 0.5)); // pixel align for sharper rendering - } break; case QTextListFormat::ListDisc: if (!marker) { - painter->setBrush(brush); + painter->setBrush(painter->pen().brush()); painter->setPen(Qt::NoPen); painter->drawEllipse(r); } diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index a09d37392ac..415de3363c5 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1672,23 +1672,18 @@ namespace { struct LineBreakHelper { - LineBreakHelper() - : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(nullptr), logClusters(nullptr), - manualWrap(false), whiteSpaceOrObject(true) - { - } - + LineBreakHelper() = default; QScriptLine tmpData; QScriptLine spaceData; QGlyphLayout glyphs; - int glyphCount; - int maxGlyphs; - int currentPosition; - glyph_t previousGlyph; - QFontEngine *previousGlyphFontEngine; + int glyphCount = 0; + int maxGlyphs = 0; + int currentPosition = 0; + glyph_t previousGlyph = 0; + QExplicitlySharedDataPointer<QFontEngine> previousGlyphFontEngine; QFixed minw; QFixed currentSoftHyphenWidth; @@ -1696,11 +1691,11 @@ namespace { QFixed rightBearing; QFixed minimumRightBearing; - QFontEngine *fontEngine; - const unsigned short *logClusters; + QExplicitlySharedDataPointer<QFontEngine> fontEngine; + const unsigned short *logClusters = nullptr; - bool manualWrap; - bool whiteSpaceOrObject; + bool manualWrap = false; + bool whiteSpaceOrObject = true; bool checkFullOtherwiseExtend(QScriptLine &line); @@ -1744,13 +1739,13 @@ namespace { { if (currentPosition <= 0) return; - calculateRightBearing(fontEngine, currentGlyph()); + calculateRightBearing(fontEngine.data(), currentGlyph()); } inline void calculateRightBearingForPreviousGlyph() { if (previousGlyph > 0) - calculateRightBearing(previousGlyphFontEngine, previousGlyph); + calculateRightBearing(previousGlyphFontEngine.data(), previousGlyph); } static const QFixed RightBearingNotCalculated; diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index f9b36b48527..75e2f9d3381 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -761,6 +761,9 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr return nullptr; IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); + if (directWriteFontFace == nullptr) + return nullptr; + fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, pixelSize, fontEngineData); diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index 5126398a3db..353afde6ea1 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -158,8 +158,11 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende } } -static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) +DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const { + if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB) + return DWRITE_RENDERING_MODE_ALIASED; + QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference); if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) { // Microsoft documentation recommends using asymmetric rendering for small fonts @@ -466,7 +469,7 @@ QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const return m_faceId; } -void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const +void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags shaperFlags) const { QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); @@ -478,11 +481,14 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn HRESULT hr; DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); - if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) { + bool needsDesignMetrics = shaperFlags & QFontEngine::DesignMetrics; + if (!needsDesignMetrics && (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC + || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL + || renderMode == DWRITE_RENDERING_MODE_ALIASED)) { hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize), 1.0f, NULL, - TRUE, + renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL, glyphIndices.data(), glyphIndices.size(), glyphMetrics.data()); @@ -665,7 +671,8 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const { - return true; + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); + return renderMode != DWRITE_RENDERING_MODE_ALIASED; } QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const @@ -768,7 +775,10 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, if (SUCCEEDED(hr)) { RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED + ? DWRITE_TEXTURE_ALIASED_1x1 + : DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect); if (rect.top == rect.bottom || rect.left == rect.right) return QImage(); @@ -849,7 +859,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, colorGlyphsAnalysis, - boundingRect); + boundingRect, + renderMode); } colorGlyphsAnalysis->Release(); @@ -876,7 +887,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, glyphAnalysis, - boundingRect); + boundingRect, + renderMode); } glyphAnalysis->Release(); @@ -894,7 +906,8 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, - const QRect &boundingRect) + const QRect &boundingRect, + DWRITE_RENDERING_MODE renderMode) { const int width = destination->width(); const int height = destination->height(); @@ -915,12 +928,14 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, BYTE *alphaValues = alphaValueArray.data(); memset(alphaValues, 0, size); - HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + HRESULT hr = glyphAnalysis->CreateAlphaTexture(renderMode == DWRITE_RENDERING_MODE_ALIASED + ? DWRITE_TEXTURE_ALIASED_1x1 + : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, alphaValues, size); if (SUCCEEDED(hr)) { - if (destination->hasAlphaChannel()) { + if (destination->hasAlphaChannel()) { // Color glyphs for (int y = 0; y < height; ++y) { uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); BYTE *src = alphaValues + width * 3 * y; @@ -938,7 +953,16 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); } } + } else if (renderMode == DWRITE_RENDERING_MODE_ALIASED) { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); + BYTE *src = alphaValues + width * y; + for (int x = 0; x < width; ++x) { + int alpha = *(src++); + dest[x] = (alpha << 16) + (alpha << 8) + alpha; + } + } } else { for (int y = 0; y < height; ++y) { uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); @@ -1092,7 +1116,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph if (SUCCEEDED(hr)) { RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED ? DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); glyphAnalysis->Release(); int margin = glyphMargin(format); diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index df6df1ad172..44e466789c8 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(directwrite); #include <QtGui/private/qfontengine_p.h> #include <QtCore/QSharedPointer> +#include <dwrite.h> struct IDWriteFont; struct IDWriteFontFace; @@ -108,8 +109,16 @@ private: const QTransform &xform, const QColor &color = QColor()); void collectMetrics(); - void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect); + void renderGlyphRun(QImage *destination, + float r, + float g, + float b, + float a, + IDWriteGlyphRunAnalysis *glyphAnalysis, + const QRect &boundingRect, + DWRITE_RENDERING_MODE renderMode); static QString filenameFromFontFile(IDWriteFontFile *fontFile); + DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) const; const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; |