diff options
Diffstat (limited to 'src')
4 files changed, 232 insertions, 63 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 966be8c991..68a8fc5390 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -62,7 +62,11 @@ #endif #if !defined(QT_NO_DIRECTWRITE) -# include <dwrite.h> +# if defined(QT_USE_DIRECTWRITE2) +# include <dwrite_2.h> +# else +# include <dwrite.h> +# endif # include <d2d1.h> #endif @@ -86,17 +90,27 @@ static inline DWriteCreateFactoryType resolveDWriteCreateFactory() return reinterpret_cast<DWriteCreateFactoryType>(result); } -static IDWriteFactory *createDirectWriteFactory() +static void createDirectWriteFactory(IDWriteFactory **factory) { + *factory = Q_NULLPTR; + static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); if (!dWriteCreateFactory) - return Q_NULLPTR; - IUnknown *result = Q_NULLPTR; - if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { - qErrnoWarning("DWriteCreateFactory failed"); - return Q_NULLPTR; + return; + + IUnknown *result = NULL; +#if defined(QT_USE_DIRECTWRITE2) + dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); +#endif + + if (result == NULL) { + if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { + qErrnoWarning("DWriteCreateFactory failed"); + return; + } } - return reinterpret_cast<IDWriteFactory *>(result); + + *factory = static_cast<IDWriteFactory *>(result); } #endif // !QT_NO_DIRECTWRITE @@ -506,8 +520,10 @@ namespace { class CustomFontFileLoader { public: - CustomFontFileLoader() : m_directWriteFactory(createDirectWriteFactory()), m_directWriteFontFileLoader(0) + CustomFontFileLoader() : m_directWriteFontFileLoader(Q_NULLPTR) { + createDirectWriteFactory(&m_directWriteFactory); + if (m_directWriteFactory) { m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); @@ -606,7 +622,7 @@ qreal QWindowsFontDatabase::fontSmoothingGamma() static inline bool initDirectWrite(QWindowsFontEngineData *d) { if (!d->directWriteFactory) { - d->directWriteFactory = createDirectWriteFactory(); + createDirectWriteFactory(&d->directWriteFactory); if (!d->directWriteFactory) return false; } @@ -1757,10 +1773,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, } #if !defined(QT_NO_DIRECTWRITE) - bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting) - || (request.hintingPreference == QFont::PreferVerticalHinting) - || (QHighDpiScaling::isActive() && request.hintingPreference == QFont::PreferDefaultHinting); - if (useDirectWrite && initDirectWrite(data.data())) { + if (initDirectWrite(data.data())) { const QString fam = QString::fromWCharArray(lf.lfFaceName); const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); if (nameSubstitute != fam) { @@ -1782,18 +1795,38 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, qWarning().noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed (" << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi; } else { - QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, - request.pixelSize, - data); - - wchar_t n[64]; - GetTextFace(data->hdc, 64, n); - - QFontDef fontDef = request; - fontDef.family = QString::fromWCharArray(n); + bool isColorFont = false; +#if defined(QT_USE_DIRECTWRITE2) + IDWriteFontFace2 *directWriteFontFace2 = Q_NULLPTR; + if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), + reinterpret_cast<void **>(&directWriteFontFace2)))) { + if (directWriteFontFace2->IsColorFont()) + isColorFont = true; + } +#endif - fedw->initFontInfo(fontDef, dpi); - fe = fedw; + bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting) + || (request.hintingPreference == QFont::PreferVerticalHinting) + || (QHighDpiScaling::isActive() && request.hintingPreference == QFont::PreferDefaultHinting) + || isColorFont; + if (useDirectWrite) { + QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, + request.pixelSize, + data); + + wchar_t n[64]; + GetTextFace(data->hdc, 64, n); + + QFontDef fontDef = request; + fontDef.family = QString::fromWCharArray(n); + + if (isColorFont) + fedw->glyphFormat = QFontEngine::Format_ARGB; + fedw->initFontInfo(fontDef, dpi); + fe = fedw; + } else { + directWriteFontFace->Release(); + } } SelectObject(data->hdc, oldFont); diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 9dbfac34ef..5408ff41e5 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -49,7 +49,12 @@ #include <private/qstringiterator_p.h> #include <QtCore/private/qsystemlibrary_p.h> -#include <dwrite.h> +#if defined(QT_USE_DIRECTWRITE2) +# include <dwrite_2.h> +#else +# include <dwrite.h> +#endif + #include <d2d1.h> QT_BEGIN_NAMESPACE @@ -562,61 +567,181 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, RECT rect; glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - rect.left -= margin; - rect.top -= margin; - rect.right += margin; - rect.bottom += margin; + 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; + + QImage image; +#if defined(QT_USE_DIRECTWRITE2) + HRESULT hr = DWRITE_E_NOCOLOR; + IDWriteColorGlyphRunEnumerator *enumerator = 0; + IDWriteFactory2 *factory2 = Q_NULLPTR; + if (glyphFormat == QFontEngine::Format_ARGB + && SUCCEEDED(m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + reinterpret_cast<void **>(&factory2)))) { + hr = factory2->TranslateColorGlyphRun(0.0f, + 0.0f, + &glyphRun, + NULL, + DWRITE_MEASURING_MODE_NATURAL, + NULL, + 0, + &enumerator); + image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(0); + } else +#endif + { + image = QImage(width, height, QImage::Format_RGB32); + image.fill(0xffffffff); + } + +#if defined(QT_USE_DIRECTWRITE2) + BOOL ok = true; + if (SUCCEEDED(hr)) { + while (SUCCEEDED(hr) && 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 = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &colorGlyphRun->glyphRun, + 1.0f, + &transform, + renderMode, + DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, + &colorGlyphsAnalysis + ); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed for color run", __FUNCTION__); + break; + } + + float r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); + float g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); + float b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); + float a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); + + if (!qFuzzyIsNull(a)) { + renderGlyphRun(&image, + r, + g, + b, + a, + colorGlyphsAnalysis, + boundingRect); + } + colorGlyphsAnalysis->Release(); + + hr = enumerator->MoveNext(&ok); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); + break; + } + } + } else +#endif + { + renderGlyphRun(&image, + 0.0, + 0.0, + 0.0, + 1.0, + glyphAnalysis, + boundingRect); + } + + glyphAnalysis->Release(); + return image; + } else { + qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed", __FUNCTION__); + return QImage(); + } +} + - const int width = rect.right - rect.left; - const int height = rect.bottom - rect.top; +void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, + float r, + float g, + float b, + float a, + IDWriteGlyphRunAnalysis *glyphAnalysis, + const QRect &boundingRect) +{ + const int width = destination->width(); + const int height = destination->height(); - const int size = width * height * 3; - if (size > 0) { - BYTE *alphaValues = new BYTE[size]; - memset(alphaValues, 0, size); + r *= 255.0; + g *= 255.0; + b *= 255.0; - hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, - &rect, - alphaValues, - size); + const int size = width * height * 3; + if (size > 0) { + RECT rect; + rect.left = boundingRect.left(); + rect.top = boundingRect.top(); + rect.right = boundingRect.right(); + rect.bottom = boundingRect.bottom(); + + QVarLengthArray<BYTE, 1024> alphaValueArray(size); + BYTE *alphaValues = alphaValueArray.data(); + memset(alphaValues, 0, size); + + HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect, + alphaValues, + size); + if (SUCCEEDED(hr)) { + if (destination->hasAlphaChannel()) { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); + BYTE *src = alphaValues + width * 3 * y; - if (SUCCEEDED(hr)) { - QImage img(width, height, QImage::Format_RGB32); - img.fill(0xffffffff); + for (int x = 0; x < width; ++x) { + float redAlpha = a * *src++ / 255.0; + float greenAlpha = a * *src++ / 255.0; + float blueAlpha = a * *src++ / 255.0; + float averageAlpha = (redAlpha + greenAlpha + blueAlpha) / 3.0; + + QRgb currentRgb = dest[x]; + dest[x] = qRgba(qRound(qRed(currentRgb) * (1.0 - averageAlpha) + averageAlpha * r), + qRound(qGreen(currentRgb) * (1.0 - averageAlpha) + averageAlpha * g), + qRound(qBlue(currentRgb) * (1.0 - averageAlpha) + averageAlpha * b), + qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); + } + } - for (int y=0; y<height; ++y) { - uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); + } else { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); BYTE *src = alphaValues + width * 3 * y; - for (int x=0; x<width; ++x) { - dest[x] = *(src) << 16 + for (int x = 0; x < width; ++x) { + dest[x] = *(src + 0) << 16 | *(src + 1) << 8 | *(src + 2); src += 3; } } - - delete[] alphaValues; - glyphAnalysis->Release(); - - return img; - } else { - delete[] alphaValues; - glyphAnalysis->Release(); - - qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); } } else { - glyphAnalysis->Release(); - qWarning("%s: Glyph has no bounds", __FUNCTION__); + qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); } - } else { - qErrnoWarning("%s: CreateGlyphRunAnalysis failed", __FUNCTION__); + glyphAnalysis->Release(); + qWarning("%s: Glyph has no bounds", __FUNCTION__); } - - return QImage(); } QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, @@ -734,6 +859,11 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph } } +QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) +{ + return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_A32), t); +} + QT_END_NAMESPACE #endif // QT_NO_DIRECTWRITE diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 0aa7e41500..f038dcfde4 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -52,6 +52,7 @@ struct IDWriteFontFace; struct IDWriteFactory; struct IDWriteBitmapRenderTarget; struct IDWriteGdiInterop; +struct IDWriteGlyphRunAnalysis; QT_BEGIN_NAMESPACE @@ -96,6 +97,7 @@ public: QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) Q_DECL_OVERRIDE; QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) Q_DECL_OVERRIDE; + QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; Qt::HANDLE handle() const Q_DECL_OVERRIDE; @@ -109,6 +111,7 @@ public: private: QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); + void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect); const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index d46cfbc43a..f4dbd10a49 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -13,6 +13,9 @@ wince: DEFINES *= QT_LIBINFIX=L"\"\\\"$${QT_LIBINFIX}\\\"\"" DEFINES *= QT_NO_CAST_FROM_ASCII contains(QT_CONFIG, directwrite) { + contains(QT_CONFIG, directwrite2): \ + DEFINES *= QT_USE_DIRECTWRITE2 + SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp HEADERS += $$PWD/qwindowsfontenginedirectwrite.h } else { |