diff options
Diffstat (limited to 'src/gui/text/windows/qwindowsfontenginedirectwrite.cpp')
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite.cpp | 414 |
1 files changed, 289 insertions, 125 deletions
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index c17139ab8b..47b8a7ee3c 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qwindowsfontenginedirectwrite_p.h" #include "qwindowsfontdatabase_p.h" @@ -48,10 +12,14 @@ #include <QtCore/private/qwinregistry_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> -#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qpainterpath.h> -#include <dwrite_2.h> +#if QT_CONFIG(directwrite3) +# include "qwindowsdirectwritefontdatabase_p.h" +# include <dwrite_3.h> +#else +# include <dwrite_2.h> +#endif #include <d2d1.h> @@ -77,17 +45,17 @@ namespace { } virtual ~GeometrySink() = default; - IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); - IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); - IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin); - IFACEMETHOD(Close)(); - IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd); - IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode); - IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags); + IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount) override; + IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount) override; + IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) override; + IFACEMETHOD(Close)() override; + IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd) override; + IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) override; + IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) override; - IFACEMETHOD_(unsigned long, AddRef)(); - IFACEMETHOD_(unsigned long, Release)(); - IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject); + IFACEMETHOD_(unsigned long, AddRef)() override; + IFACEMETHOD_(unsigned long, Release)() override; + IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject) override; private: inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp) @@ -101,7 +69,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 +80,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 +133,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; @@ -194,10 +162,19 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende } } -static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference) +DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const { - if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) - hintingPreference = QFont::PreferVerticalHinting; + if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB) + return DWRITE_RENDERING_MODE_ALIASED; + + QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference); + if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting) { + // Microsoft documentation recommends using asymmetric rendering for small fonts + // at pixel size 16 and less, and symmetric for larger fonts. + hintingPreference = fontDef.pixelSize > 16.0 + ? QFont::PreferNoHinting + : QFont::PreferVerticalHinting; + } switch (hintingPreference) { case QFont::PreferNoHinting: @@ -242,7 +219,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di fontDef.pixelSize = pixelSize; collectMetrics(); - cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000; + cache_cost = m_xHeight.toInt() * m_xHeight.toInt() * 2000; } QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() @@ -337,6 +314,22 @@ QString QWindowsFontEngineDirectWrite::filenameFromFontFile(IDWriteFontFile *fon return ret; } +HFONT QWindowsFontEngineDirectWrite::createHFONT() const +{ + if (m_fontEngineData == nullptr || m_directWriteFontFace == nullptr) + return NULL; + + LOGFONT lf; + HRESULT hr = m_fontEngineData->directWriteGdiInterop->ConvertFontFaceToLOGFONT(m_directWriteFontFace, + &lf); + if (SUCCEEDED(hr)) { + lf.lfHeight = -qRound(fontDef.pixelSize); + return CreateFontIndirect(&lf); + } else { + return NULL; + } +} + void QWindowsFontEngineDirectWrite::initializeHeightMetrics() const { DWRITE_FONT_METRICS metrics; @@ -368,12 +361,14 @@ void QWindowsFontEngineDirectWrite::collectMetrics() fontFile->Release(); } - QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); + QByteArray table = getSfntTable(QFont::Tag("hhea").value()); const int advanceWidthMaxLocation = 10; if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) { quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation); m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); } + + loadKerningPairs(emSquareSize() / QFixed::fromReal(fontDef.pixelSize)); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -440,13 +435,13 @@ glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const return glyphIndex; } -bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const +int QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; - return false; + return -1; } QVarLengthArray<UINT32> codePoints(len); @@ -460,11 +455,15 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly glyphIndices.data()); if (FAILED(hr)) { qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - return false; + return -1; } - for (int i = 0; i < actualLength; ++i) + int mappedGlyphs = 0; + for (int i = 0; i < actualLength; ++i) { glyphs->glyphs[i] = glyphIndices.at(i); + if (glyphs->glyphs[i] != 0 || isIgnorableChar(codePoints.at(i))) + mappedGlyphs++; + } *nglyphs = actualLength; glyphs->numGlyphs = actualLength; @@ -472,7 +471,7 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, {}); - return true; + return mappedGlyphs; } QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const @@ -480,7 +479,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); @@ -491,12 +490,15 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size()); HRESULT hr; - DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) { + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); + 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()); @@ -514,9 +516,57 @@ 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) { + Q_UNUSED(flags); QVarLengthArray<UINT16> glyphIndices(nglyphs); QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); QVarLengthArray<FLOAT> glyphAdvances(nglyphs); @@ -536,7 +586,7 @@ void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint glyphOffsets.data(), nglyphs, false, - flags & QTextItem::RightToLeft, + false, &geometrySink ); @@ -552,7 +602,9 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g for (int i = 0; i < glyphs.numGlyphs; ++i) w += glyphs.effectiveAdvance(i); - return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent() + descent(), w, 0); + const QFixed leftBearing = firstLeftBearing(glyphs); + return glyph_metrics_t(leftBearing, -ascent(), w - leftBearing - lastRightBearing(glyphs), + ascent() + descent(), w, 0); } glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) @@ -602,7 +654,9 @@ qreal QWindowsFontEngineDirectWrite::maxCharWidth() const return m_maxAdvanceWidth.toReal(); } -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, + const QFixedPoint &subPixelPosition, + const QTransform &t) { QImage im = imageForGlyph(glyph, subPixelPosition, glyphMargin(Format_A8), t); @@ -621,21 +675,52 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed sub return alphaMap; } -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, + const QFixedPoint &subPixelPosition) { return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); } -bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const +bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const { - return true; + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); + return (renderMode != DWRITE_RENDERING_MODE_GDI_CLASSIC + && renderMode != DWRITE_RENDERING_MODE_GDI_NATURAL + && renderMode != DWRITE_RENDERING_MODE_ALIASED); +} + +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, - QFixed subPixelPosition, - int margin, - const QTransform &originalTransform, - const QColor &color) + const QFixedPoint &subPixelPosition, + int margin, + const QTransform &originalTransform, + const QColor &color) { UINT16 glyphIndex = t; FLOAT glyphAdvance = 0; @@ -659,32 +744,55 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, xform.scale(fontDef.stretch / 100.0, 1.0); DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); + transform.dx = subPixelPosition.x.toReal(); transform.dy = 0; transform.m11 = xform.m11(); transform.m12 = xform.m12(); transform.m21 = xform.m21(); transform.m22 = xform.m22(); - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode); + DWRITE_GRID_FIT_MODE gridFitMode = fontDef.hintingPreference == QFont::PreferNoHinting + ? DWRITE_GRID_FIT_MODE_DISABLED + : DWRITE_GRID_FIT_MODE_DEFAULT; + + IDWriteFactory2 *factory2 = nullptr; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + reinterpret_cast<void **>(&factory2)); IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - measureMode, - 0.0, 0.0, - &glyphAnalysis - ); + if (!SUCCEEDED(hr)) { + qErrnoWarning(hr, "%s: Failed to query IDWriteFactory2 interface.", __FUNCTION__); + hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + renderMode, + measureMode, + 0.0, 0.0, + &glyphAnalysis + ); + } else { + hr = factory2->CreateGlyphRunAnalysis( + &glyphRun, + &transform, + renderMode, + measureMode, + gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, + 0.0, 0.0, + &glyphAnalysis + ); + } 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(); @@ -701,10 +809,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, QImage image; HRESULT hr = DWRITE_E_NOCOLOR; IDWriteColorGlyphRunEnumerator *enumerator = 0; - IDWriteFactory2 *factory2 = nullptr; - if (glyphFormat == QFontEngine::Format_ARGB - && SUCCEEDED(m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), - reinterpret_cast<void **>(&factory2)))) { + if (glyphFormat == QFontEngine::Format_ARGB && factory2 != nullptr) { hr = factory2->TranslateColorGlyphRun(0.0f, 0.0f, &glyphRun, @@ -732,15 +837,17 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, } IDWriteGlyphRunAnalysis *colorGlyphsAnalysis = NULL; - hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + hr = factory2->CreateGlyphRunAnalysis( &colorGlyphRun->glyphRun, - 1.0f, &transform, renderMode, measureMode, + gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, 0.0, 0.0, &colorGlyphsAnalysis ); + if (FAILED(hr)) { qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed for color run", __FUNCTION__); break; @@ -766,7 +873,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, colorGlyphsAnalysis, - boundingRect); + boundingRect, + renderMode); } colorGlyphsAnalysis->Release(); @@ -793,7 +901,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, glyphAnalysis, - boundingRect); + boundingRect, + renderMode); } glyphAnalysis->Release(); @@ -811,7 +920,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(); @@ -832,12 +942,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; @@ -855,7 +967,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)); @@ -880,7 +1001,7 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, } QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, - QFixed subPixelPosition, + const QFixedPoint &subPixelPosition, const QTransform &xform) { QImage mask = imageForGlyph(t, @@ -924,6 +1045,27 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, fontDef.pointSize = fontDef.pixelSize * 72. / dpi; else if (fontDef.pixelSize == -1) fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); + + m_faceId.variableAxes = request.variableAxisValues; + +#if QT_CONFIG(directwrite3) + IDWriteFontFace3 *face3 = nullptr; + if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace3), + reinterpret_cast<void **>(&face3)))) { + IDWriteLocalizedStrings *names; + if (SUCCEEDED(face3->GetFaceNames(&names))) { + wchar_t englishLocale[] = L"en-us"; + fontDef.styleName = QWindowsDirectWriteFontDatabase::localeString(names, englishLocale); + names->Release(); + } + + // Color font + if (face3->GetPaletteEntryCount() > 0) + glyphFormat = QFontEngine::Format_ARGB; + + face3->Release(); + } +#endif } QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) @@ -936,7 +1078,7 @@ QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyN } glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, - QFixed subPixelPosition, + const QFixedPoint &subPixelPosition, const QTransform &originalTransform, GlyphFormat format) { @@ -966,31 +1108,50 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph glyphRun.glyphOffsets = &glyphOffset; DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); + transform.dx = subPixelPosition.x.toReal(); transform.dy = 0; transform.m11 = matrix.m11(); transform.m12 = matrix.m12(); transform.m21 = matrix.m21(); transform.m22 = matrix.m22(); - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode); + DWRITE_GRID_FIT_MODE gridFitMode = fontDef.hintingPreference == QFont::PreferNoHinting + ? DWRITE_GRID_FIT_MODE_DISABLED + : DWRITE_GRID_FIT_MODE_DEFAULT; + + IDWriteFactory2 *factory2 = nullptr; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + reinterpret_cast<void **>(&factory2)); IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - measureMode, - 0.0, 0.0, - &glyphAnalysis - ); + if (SUCCEEDED(hr)) { + hr = factory2->CreateGlyphRunAnalysis( + &glyphRun, + &transform, + renderMode, + measureMode, + gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, + 0.0, 0.0, + &glyphAnalysis + ); + } else { + hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + renderMode, + measureMode, + 0.0, 0.0, + &glyphAnalysis + ); + } 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); @@ -1008,7 +1169,10 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph } } -QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) +QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, + const QFixedPoint &subPixelPosition, + const QTransform &t, + const QColor &color) { return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_ARGB), t, color); } |