From 4bff9e35822891ec1b678863bfd9b62483464e87 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 20 Jan 2025 09:16:14 +0100 Subject: [PATCH] DirectWrite: Support embedded PNGs in color fonts This does some refactoring on the color font support in the DirectWrite backend and introduces support for loading embedded PNGs from the font. This gives us support for CBDT and SBIX fonts, which are both based on embedding image files. [ChangeLog][Windows] Added support for color font formats with embedded pixmaps in DirectWrite backend. Task-number: QTBUG-113458 Change-Id: I695901b62600c37619c80aa915f60de13a4fca3f Reviewed-by: Allan Sandfeld Jensen (cherry picked from commit 1b85143d217042876209794bf8d0361b7ce8834f) Reviewed-by: Qt Cherry-pick Bot --- .../windows/qwindowsfontenginedirectwrite.cpp | 563 ++++++++++++------ .../windows/qwindowsfontenginedirectwrite_p.h | 23 +- 2 files changed, 417 insertions(+), 169 deletions(-) diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index e0c5b762d58..23636c7bd91 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -17,8 +18,6 @@ #if QT_CONFIG(directwrite3) # include "qwindowsdirectwritefontdatabase_p.h" # include -#else -# include #endif #include @@ -788,6 +787,241 @@ QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const } } +bool QWindowsFontEngineDirectWrite::renderColr0GlyphRun(QImage *image, + const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun, + const DWRITE_MATRIX &transform, + DWRITE_RENDERING_MODE renderMode, + DWRITE_MEASURING_MODE measureMode, + DWRITE_GRID_FIT_MODE gridFitMode, + QColor color, + QRect boundingRect) const +{ + ComPtr factory2; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + &factory2); + if (FAILED(hr)) + return false; + + ComPtr colorGlyphsAnalysis; + hr = factory2->CreateGlyphRunAnalysis( + &colorGlyphRun->glyphRun, + &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__); + return false; + } + + float r, g, b, a; + if (colorGlyphRun->paletteIndex == 0xFFFF) { + r = float(color.redF()); + g = float(color.greenF()); + b = float(color.blueF()); + a = 1.0; + } else { + r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); + g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); + b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); + a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); + } + + if (!qFuzzyIsNull(a)) + renderGlyphRun(image, r, g, b, a, colorGlyphsAnalysis.Get(), boundingRect, renderMode); + + return true; +} + +QImage QWindowsFontEngineDirectWrite::renderColorGlyph(DWRITE_GLYPH_RUN *glyphRun, + const DWRITE_MATRIX &transform, + DWRITE_RENDERING_MODE renderMode, + DWRITE_MEASURING_MODE measureMode, + DWRITE_GRID_FIT_MODE gridFitMode, + QColor color, + QRect boundingRect) const +{ + QImage ret; + +#if QT_CONFIG(directwrite3) + ComPtr factory4; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory4), + &factory4); + if (SUCCEEDED(hr)) { + const DWRITE_GLYPH_IMAGE_FORMATS supportedBitmapFormats = + DWRITE_GLYPH_IMAGE_FORMATS(DWRITE_GLYPH_IMAGE_FORMATS_PNG + | DWRITE_GLYPH_IMAGE_FORMATS_JPEG + | DWRITE_GLYPH_IMAGE_FORMATS_TIFF); + + const DWRITE_GLYPH_IMAGE_FORMATS glyphFormats = + DWRITE_GLYPH_IMAGE_FORMATS(DWRITE_GLYPH_IMAGE_FORMATS_COLR + | supportedBitmapFormats + | DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE + | DWRITE_GLYPH_IMAGE_FORMATS_CFF); + + ComPtr enumerator; + hr = factory4->TranslateColorGlyphRun(D2D1::Point2F(0.0f, 0.0f), + glyphRun, + NULL, + glyphFormats, + measureMode, + NULL, + 0, + &enumerator); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: TranslateGlyphRun failed", __FUNCTION__); + return ret; + } + + BOOL ok = true; + while (SUCCEEDED(hr) && ok) { + hr = enumerator->MoveNext(&ok); + if (!ok) + break; + + const DWRITE_COLOR_GLYPH_RUN1 *colorGlyphRun = nullptr; + hr = enumerator->GetCurrentRun(&colorGlyphRun); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); + return QImage{}; + } + + if (colorGlyphRun->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_NONE) { + break; + } else if (colorGlyphRun->glyphImageFormat & DWRITE_GLYPH_IMAGE_FORMATS_COLR) { + if (ret.isNull()) { + ret = QImage(boundingRect.width() - 1, + boundingRect.height() - 1, + QImage::Format_ARGB32_Premultiplied); + ret.fill(0); + } + + if (!renderColr0GlyphRun(&ret, + reinterpret_cast(colorGlyphRun), // Broken inheritance in MinGW + transform, + renderMode, + measureMode, + gridFitMode, + color, + boundingRect)) { + return QImage{}; + } + } else if (colorGlyphRun->glyphImageFormat & supportedBitmapFormats) { + ComPtr face4; + if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace4), + &face4))) { + DWRITE_GLYPH_IMAGE_DATA data; + void *ctx; + Q_ASSERT(glyphRun->glyphCount == 1); + HRESULT hr = face4->GetGlyphImageData(glyphRun->glyphIndices[0], + fontDef.pixelSize, + DWRITE_GLYPH_IMAGE_FORMATS(colorGlyphRun->glyphImageFormat & supportedBitmapFormats), + &data, + &ctx); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphImageData failed", __FUNCTION__); + return QImage{}; + } + + const char *format; + switch (colorGlyphRun->glyphImageFormat) { + case DWRITE_GLYPH_IMAGE_FORMATS_JPEG: + format = "JPEG"; + break; + case DWRITE_GLYPH_IMAGE_FORMATS_TIFF: + format = "TIFF"; + break; + default: + format = "PNG"; + break; + }; + + ret = QImage::fromData(reinterpret_cast(data.imageData), + data.imageDataSize, + format); + + QTransform matrix(transform.m11, transform.m12, + transform.m21, transform.m22, + transform.dx, transform.dy); + + const qreal scale = fontDef.pixelSize / data.pixelsPerEm; + matrix.scale(scale, scale); + + if (!matrix.isIdentity()) + ret = ret.transformed(matrix, Qt::SmoothTransformation); + + face4->ReleaseGlyphImageData(ctx); + } + + } else { + qCDebug(lcQpaFonts) << "Found glyph run with unsupported format" + << colorGlyphRun->glyphImageFormat; + } + } + } +#endif // QT_CONFIG(directwrite3) + + if (ret.isNull()) { + ComPtr factory2; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + &factory2); + if (FAILED(hr)) + return ret; + + ComPtr enumerator; + hr = factory2->TranslateColorGlyphRun(0.0f, + 0.0f, + glyphRun, + NULL, + measureMode, + NULL, + 0, + &enumerator); + if (SUCCEEDED(hr)) { + ret = QImage(boundingRect.width() - 1, + boundingRect.height() - 1, + QImage::Format_ARGB32_Premultiplied); + ret.fill(0); + + BOOL ok = true; + while (SUCCEEDED(hr) && ok) { + hr = enumerator->MoveNext(&ok); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); + return QImage{}; + } + + if (ok) { + const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = nullptr; + hr = enumerator->GetCurrentRun(&colorGlyphRun); + if (FAILED(hr)) { // No colored runs, only outline + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); + return QImage{}; + } + + if (!renderColr0GlyphRun(&ret, + colorGlyphRun, + transform, + renderMode, + measureMode, + gridFitMode, + color, + boundingRect)) { + return QImage{}; + } + } + } + } + } + + return ret; +} + QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, int margin, @@ -824,17 +1058,15 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, transform.m22 = xform.m22(); DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); - DWRITE_MEASURING_MODE measureMode = - renderModeToMeasureMode(renderMode); - + 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; + ComPtr factory2; HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), - reinterpret_cast(&factory2)); - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; + &factory2); + ComPtr glyphAnalysis; if (!SUCCEEDED(hr)) { qErrnoWarning(hr, "%s: Failed to query IDWriteFactory2 interface.", __FUNCTION__); hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( @@ -860,106 +1092,39 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, } if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED - ? DWRITE_TEXTURE_ALIASED_1x1 - : DWRITE_TEXTURE_CLEARTYPE_3x1, - &rect); + QRect rect = alphaTextureBounds(t, transform); + if (rect.isEmpty()) + rect = colorBitmapBounds(t, transform); - if (rect.top == rect.bottom || rect.left == rect.right) { + if (rect.isEmpty()) { qCDebug(lcQpaFonts) << __FUNCTION__ << "Cannot get alpha texture bounds. Falling back to slower rendering path."; return QImage(); } - QRect boundingRect = QRect(QPoint(rect.left - margin, - rect.top - margin), - QPoint(rect.right + margin, - rect.bottom + margin)); - - - const int width = boundingRect.width() - 1; // -1 due to Qt's off-by-one definition of a QRect - const int height = boundingRect.height() - 1; + QRect boundingRect = QRect(QPoint(rect.left() - margin, + rect.top() - margin), + QPoint(rect.right() + margin, + rect.bottom() + margin)); QImage image; - HRESULT hr = DWRITE_E_NOCOLOR; - IDWriteColorGlyphRunEnumerator *enumerator = 0; - if (glyphFormat == QFontEngine::Format_ARGB && factory2 != nullptr) { - hr = factory2->TranslateColorGlyphRun(0.0f, - 0.0f, - &glyphRun, - NULL, - measureMode, - NULL, - 0, - &enumerator); - image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); - image.fill(0); - } else { - image = QImage(width, height, QImage::Format_RGB32); - image.fill(0xffffffff); + if (glyphFormat == QFontEngine::Format_ARGB) { + image = renderColorGlyph(&glyphRun, + transform, + renderMode, + measureMode, + gridFitMode, + color, + boundingRect); } - if (SUCCEEDED(hr)) { - BOOL ok = true; - while (SUCCEEDED(hr) && ok) { - hr = enumerator->MoveNext(&ok); - if (FAILED(hr)) { - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); - break; - } + // Not a color glyph, fall back to regular glyph rendering + if (image.isNull()) { + // -1 due to Qt's off-by-one definition of a QRect + image = QImage(boundingRect.width() - 1, + boundingRect.height() - 1, + QImage::Format_RGB32); + image.fill(0xffffffff); - if (ok) { - const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = 0; - hr = enumerator->GetCurrentRun(&colorGlyphRun); - if (FAILED(hr)) { // No colored runs, only outline - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); - break; - } - - IDWriteGlyphRunAnalysis *colorGlyphsAnalysis = NULL; - hr = factory2->CreateGlyphRunAnalysis( - &colorGlyphRun->glyphRun, - &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; - } - - float r, g, b, a; - if (colorGlyphRun->paletteIndex == 0xFFFF) { - r = float(color.redF()); - g = float(color.greenF()); - b = float(color.blueF()); - a = 1.0; - } else { - r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); - g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); - b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); - a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); - } - - if (!qFuzzyIsNull(a)) { - renderGlyphRun(&image, - r, - g, - b, - a, - colorGlyphsAnalysis, - boundingRect, - renderMode); - } - colorGlyphsAnalysis->Release(); - } - } - } else { float r, g, b, a; if (glyphFormat == QFontEngine::Format_ARGB) { r = float(color.redF()); @@ -975,12 +1140,11 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, g, b, a, - glyphAnalysis, + glyphAnalysis.Get(), boundingRect, renderMode); } - glyphAnalysis->Release(); return image; } else { qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed", __FUNCTION__); @@ -988,7 +1152,6 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, } } - void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, float r, float g, @@ -996,7 +1159,7 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect, - DWRITE_RENDERING_MODE renderMode) + DWRITE_RENDERING_MODE renderMode) const { const int width = destination->width(); const int height = destination->height(); @@ -1076,9 +1239,6 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, } else { qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); } - } else { - glyphAnalysis->Release(); - qWarning("%s: Glyph has no bounds", __FUNCTION__); } } @@ -1148,7 +1308,7 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, } // Color font - if (face3->GetPaletteEntryCount() > 0) + if (face3->IsColorFont()) glyphFormat = QFontEngine::Format_ARGB; face3->Release(); @@ -1165,19 +1325,9 @@ QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyN return substitute.isEmpty() ? familyName : substitute; } -glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, - const QFixedPoint &subPixelPosition, - const QTransform &originalTransform, - GlyphFormat format) +QRect QWindowsFontEngineDirectWrite::alphaTextureBounds(glyph_t glyph, + const DWRITE_MATRIX &transform) { - Q_UNUSED(format); - - QTransform matrix = originalTransform; - if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) - matrix.scale(fontDef.stretch / 100.0, 1.0); - - glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance - UINT16 glyphIndex = glyph; FLOAT glyphAdvance = 0; @@ -1195,6 +1345,120 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph glyphRun.bidiLevel = 0; glyphRun.glyphOffsets = &glyphOffset; + 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; + + ComPtr factory2 = nullptr; + HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + &factory2); + + ComPtr 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; + hr = glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED + ? DWRITE_TEXTURE_ALIASED_1x1 + : DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect); + if (FAILED(hr) || rect.left == rect.right || rect.top == rect.bottom) + return QRect{}; + + return QRect(QPoint(rect.left, rect.top), QPoint(rect.right, rect.bottom)); + } else { + return QRect{}; + } +} + +QRect QWindowsFontEngineDirectWrite::colorBitmapBounds(glyph_t glyph, const DWRITE_MATRIX &transform) +{ +#if QT_CONFIG(directwrite3) + ComPtr face4; + if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace4), + &face4))) { + DWRITE_GLYPH_IMAGE_FORMATS formats = face4->GetGlyphImageFormats(); + + const DWRITE_GLYPH_IMAGE_FORMATS supportedBitmapFormats = + DWRITE_GLYPH_IMAGE_FORMATS(DWRITE_GLYPH_IMAGE_FORMATS_PNG + | DWRITE_GLYPH_IMAGE_FORMATS_JPEG + | DWRITE_GLYPH_IMAGE_FORMATS_TIFF); + + if (formats & supportedBitmapFormats) { + DWRITE_GLYPH_IMAGE_DATA data; + void *ctx; + HRESULT hr = face4->GetGlyphImageData(glyph, + fontDef.pixelSize, + DWRITE_GLYPH_IMAGE_FORMATS(formats & supportedBitmapFormats), + &data, + &ctx); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphImageData failed", __FUNCTION__); + return QRect{}; + } + + QRect rect(-data.horizontalLeftOrigin.x, + -data.horizontalLeftOrigin.y, + data.pixelSize.width, + data.pixelSize.height); + + QTransform matrix(transform.m11, transform.m12, + transform.m21, transform.m22, + transform.dx, transform.dy); + + // GetGlyphImageData returns the closest matching size, which we need to scale down + const qreal scale = fontDef.pixelSize / data.pixelsPerEm; + matrix.scale(scale, scale); + + rect = matrix.mapRect(rect); + face4->ReleaseGlyphImageData(ctx); + + return rect; + } + } + + return QRect{}; +#else + Q_UNUSED(glyph); + Q_UNUSED(transform); + return QRect{}; +#endif // QT_CONFIG(directwrite3) +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, + const QFixedPoint &subPixelPosition, + const QTransform &originalTransform, + GlyphFormat format) +{ + QTransform matrix = originalTransform; + if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) + matrix.scale(fontDef.stretch / 100.0, 1.0); + + glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance + DWRITE_MATRIX transform; transform.dx = subPixelPosition.x.toReal(); transform.dy = 0; @@ -1203,58 +1467,23 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph transform.m21 = matrix.m21(); transform.m22 = matrix.m22(); - 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; + // Try general approach first (works with regular truetype glyphs as well as COLRv0) + QRect rect = alphaTextureBounds(glyph, transform); - IDWriteFactory2 *factory2 = nullptr; - HRESULT hr = m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), - reinterpret_cast(&factory2)); + // If this fails, we check if it is an embedded color bitmap + if (rect.isEmpty()) + rect = colorBitmapBounds(glyph, transform); - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - 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 we are unable to find metrics, just return the design metrics + if (rect.isEmpty()) + return bbox; - if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED ? DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - glyphAnalysis->Release(); - - int margin = glyphMargin(format); - - if (rect.left == rect.right || rect.top == rect.bottom) - return bbox; - - return glyph_metrics_t(rect.left, - rect.top, - rect.right - rect.left + margin * 2, - rect.bottom - rect.top + margin * 2, - bbox.xoff, bbox.yoff); - } else { - return glyph_metrics_t(); - } + int margin = glyphMargin(format); + return glyph_metrics_t(rect.left(), + rect.top(), + rect.right() - rect.left() + margin * 2, + rect.bottom() - rect.top() + margin * 2, + bbox.xoff, bbox.yoff); } QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index 874717fd118..2c1e844a579 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -22,7 +22,8 @@ QT_REQUIRE_CONFIG(directwrite); #include #include -#include + +#include struct IDWriteFont; struct IDWriteFontFace; @@ -31,6 +32,7 @@ struct IDWriteFactory; struct IDWriteBitmapRenderTarget; struct IDWriteGdiInterop; struct IDWriteGlyphRunAnalysis; +struct IDWriteColorGlyphRunEnumerator; QT_BEGIN_NAMESPACE @@ -105,6 +107,23 @@ public: QList variableAxes() const override; private: + QRect alphaTextureBounds(glyph_t glyph, const DWRITE_MATRIX &transform); + QRect colorBitmapBounds(glyph_t glyph, const DWRITE_MATRIX &transform); + bool renderColr0GlyphRun(QImage *image, + const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun, + const DWRITE_MATRIX &transform, + DWRITE_RENDERING_MODE renderMode, + DWRITE_MEASURING_MODE measureMode, + DWRITE_GRID_FIT_MODE gridFitMode, + QColor color, + QRect boundingRect) const; + QImage renderColorGlyph(DWRITE_GLYPH_RUN *glyphRun, + const DWRITE_MATRIX &transform, + DWRITE_RENDERING_MODE renderMode, + DWRITE_MEASURING_MODE measureMode, + DWRITE_GRID_FIT_MODE gridFitMode, + QColor color, + QRect boundingRect) const; QImage imageForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, int margin, @@ -118,7 +137,7 @@ private: float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect, - DWRITE_RENDERING_MODE renderMode); + DWRITE_RENDERING_MODE renderMode) const; static QString filenameFromFontFile(IDWriteFontFile *fontFile); DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) const;