diff options
Diffstat (limited to 'src/gui/text/windows/qwindowsfontenginedirectwrite.cpp')
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite.cpp | 185 |
1 files changed, 157 insertions, 28 deletions
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index bc8e0b7ed1..2070deb296 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -12,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> @@ -65,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); @@ -76,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) @@ -129,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; @@ -158,10 +162,13 @@ 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) { + 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 @@ -212,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() @@ -354,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 @@ -466,7 +475,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 +487,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()); @@ -500,6 +512,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) { @@ -539,7 +598,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) @@ -618,7 +679,37 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, 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, @@ -694,7 +785,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(); @@ -775,7 +869,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, colorGlyphsAnalysis, - boundingRect); + boundingRect, + renderMode); } colorGlyphsAnalysis->Release(); @@ -802,7 +897,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, glyphAnalysis, - boundingRect); + boundingRect, + renderMode); } glyphAnalysis->Release(); @@ -820,7 +916,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(); @@ -841,12 +938,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; @@ -864,7 +963,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)); @@ -933,6 +1041,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) @@ -1018,7 +1147,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); |