1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QT_NO_DIRECTWRITE
44 #include "qfontenginedirectwrite_p.h"
48 #include <private/qnativeimage_p.h>
54 // Convert from design units to logical pixels
55 #define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \
56 QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize)
60 class GeometrySink: public IDWriteGeometrySink
63 GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0)
65 Q_ASSERT(m_path != 0);
68 IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount);
69 IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount);
70 IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);
72 IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
73 IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
74 IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
76 IFACEMETHOD_(unsigned long, AddRef)();
77 IFACEMETHOD_(unsigned long, Release)();
78 IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject);
81 inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp)
83 return QPointF(inp.x, inp.y);
86 unsigned long m_refCount;
91 void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers,
94 for (uint i=0; i<bezierCount; ++i) {
95 QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1);
96 QPointF c2 = fromD2D1_POINT_2F(beziers[i].point2);
97 QPointF p2 = fromD2D1_POINT_2F(beziers[i].point3);
99 m_path->cubicTo(c1, c2, p2);
103 void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount)
105 for (uint i=0; i<pointsCount; ++i)
106 m_path->lineTo(fromD2D1_POINT_2F(points[i]));
109 void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint,
110 D2D1_FIGURE_BEGIN /*figureBegin*/)
112 m_startPoint = fromD2D1_POINT_2F(startPoint);
113 m_path->moveTo(m_startPoint);
116 IFACEMETHODIMP GeometrySink::Close()
121 void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
123 if (figureEnd == D2D1_FIGURE_END_CLOSED)
124 m_path->closeSubpath();
127 void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
129 m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE
134 void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/)
136 /* Not implemented */
139 IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef()
141 return InterlockedIncrement(&m_refCount);
144 IFACEMETHODIMP_(unsigned long) GeometrySink::Release()
146 unsigned long newCount = InterlockedDecrement(&m_refCount);
156 IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject)
158 if (__uuidof(IDWriteGeometrySink) == riid) {
160 } else if (__uuidof(IUnknown) == riid) {
173 QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory,
174 IDWriteFontFace *directWriteFontFace,
176 : m_directWriteFontFace(directWriteFontFace)
177 , m_directWriteFactory(directWriteFactory)
178 , m_directWriteBitmapRenderTarget(0)
179 , m_lineThickness(-1)
186 m_directWriteFactory->AddRef();
187 m_directWriteFontFace->AddRef();
189 fontDef.pixelSize = pixelSize;
193 QFontEngineDirectWrite::~QFontEngineDirectWrite()
195 m_directWriteFactory->Release();
196 m_directWriteFontFace->Release();
198 if (m_directWriteBitmapRenderTarget != 0)
199 m_directWriteBitmapRenderTarget->Release();
202 void QFontEngineDirectWrite::collectMetrics()
204 if (m_directWriteFontFace != 0) {
205 DWRITE_FONT_METRICS metrics;
207 m_directWriteFontFace->GetMetrics(&metrics);
208 m_unitsPerEm = metrics.designUnitsPerEm;
210 m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness);
211 m_ascent = DESIGN_TO_LOGICAL(metrics.ascent);
212 m_descent = DESIGN_TO_LOGICAL(metrics.descent);
213 m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight);
214 m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap);
218 QFixed QFontEngineDirectWrite::lineThickness() const
220 if (m_lineThickness > 0)
221 return m_lineThickness;
223 return QFontEngine::lineThickness();
226 bool QFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const
228 if (m_directWriteFontFace) {
229 DWORD t = qbswap<quint32>(tag);
231 const void *tableData = 0;
232 void *tableContext = 0;
235 HRESULT hr = m_directWriteFontFace->TryGetFontTable(
236 t, &tableData, &tableSize, &tableContext, &exists
246 } else if (*length < tableSize) {
250 qMemCopy(buffer, tableData, tableSize);
251 m_directWriteFontFace->ReleaseFontTable(tableContext);
255 qErrnoWarning("QFontEngineDirectWrite::getSfntTableData: TryGetFontTable failed");
262 QFixed QFontEngineDirectWrite::emSquareSize() const
264 if (m_unitsPerEm > 0)
267 return QFontEngine::emSquareSize();
270 inline unsigned int getChar(const QChar *str, int &i, const int len)
272 unsigned int uc = str[i].unicode();
273 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
274 uint low = str[i+1].unicode();
275 if (low >= 0xdc00 && low < 0xe000) {
276 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
283 bool QFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
284 int *nglyphs, QTextEngine::ShaperFlags flags) const
286 if (m_directWriteFontFace != 0) {
287 QVarLengthArray<UINT32> codePoints(len);
288 for (int i=0; i<len; ++i) {
289 codePoints[i] = getChar(str, i, len);
290 if (flags & QTextEngine::RightToLeft)
291 codePoints[i] = QChar::mirroredChar(codePoints[i]);
294 QVarLengthArray<UINT16> glyphIndices(len);
295 HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(),
297 glyphIndices.data());
300 for (int i=0; i<len; ++i)
301 glyphs->glyphs[i] = glyphIndices[i];
305 if (!(flags & QTextEngine::GlyphIndicesOnly))
306 recalcAdvances(glyphs, 0);
310 qErrnoWarning("QFontEngineDirectWrite::stringToCMap: GetGlyphIndicesW failed");
317 void QFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
319 if (m_directWriteFontFace == 0)
322 QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
325 for(int i=0; i<glyphs->numGlyphs; i++)
326 glyphIndices[i] = UINT16(glyphs->glyphs[i]);
328 QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
329 HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
331 glyphMetrics.data());
333 for (int i=0; i<glyphs->numGlyphs; ++i) {
334 glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
335 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
336 glyphs->advances_x[i] = glyphs->advances_x[i].round();
337 glyphs->advances_y[i] = 0;
340 qErrnoWarning("QFontEngineDirectWrite::recalcAdvances: GetDesignGlyphMetrics failed");
344 void QFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
345 QPainterPath *path, QTextItem::RenderFlags flags)
347 if (m_directWriteFontFace == 0)
350 QVarLengthArray<UINT16> glyphIndices(nglyphs);
351 QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs);
352 QVarLengthArray<FLOAT> glyphAdvances(nglyphs);
354 for (int i=0; i<nglyphs; ++i) {
355 glyphIndices[i] = glyphs[i];
356 glyphOffsets[i].advanceOffset = positions[i].x.toReal();
357 glyphOffsets[i].ascenderOffset = -positions[i].y.toReal();
358 glyphAdvances[i] = 0.0;
361 GeometrySink geometrySink(path);
362 HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(
365 glyphAdvances.data(),
369 flags & QTextItem::RightToLeft,
374 qErrnoWarning("QFontEngineDirectWrite::addGlyphsToPath: GetGlyphRunOutline failed");
377 glyph_metrics_t QFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs)
379 if (glyphs.numGlyphs == 0)
380 return glyph_metrics_t();
382 bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
385 for (int i = 0; i < glyphs.numGlyphs; ++i) {
386 w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i);
390 return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0);
393 glyph_metrics_t QFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition,
394 const QTransform &matrix,
395 GlyphFormat /*format*/)
397 glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance
399 UINT16 glyphIndex = glyph;
400 FLOAT glyphAdvance = 0;
402 DWRITE_GLYPH_OFFSET glyphOffset;
403 glyphOffset.advanceOffset = 0;
404 glyphOffset.ascenderOffset = 0;
406 DWRITE_GLYPH_RUN glyphRun;
407 glyphRun.fontFace = m_directWriteFontFace;
408 glyphRun.fontEmSize = fontDef.pixelSize;
409 glyphRun.glyphCount = 1;
410 glyphRun.glyphIndices = &glyphIndex;
411 glyphRun.glyphAdvances = &glyphAdvance;
412 glyphRun.isSideways = false;
413 glyphRun.bidiLevel = 0;
414 glyphRun.glyphOffsets = &glyphOffset;
416 DWRITE_MATRIX transform;
417 transform.dx = subPixelPosition.toReal();
419 transform.m11 = matrix.m11();
420 transform.m12 = matrix.m12();
421 transform.m21 = matrix.m21();
422 transform.m22 = matrix.m22();
424 IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
425 HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis(
429 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
430 DWRITE_MEASURING_MODE_NATURAL,
437 glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
438 glyphAnalysis->Release();
440 return glyph_metrics_t(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
441 bbox.xoff, bbox.yoff);
443 return glyph_metrics_t();
447 glyph_metrics_t QFontEngineDirectWrite::boundingBox(glyph_t g)
449 if (m_directWriteFontFace == 0)
450 return glyph_metrics_t();
452 UINT16 glyphIndex = g;
454 DWRITE_GLYPH_METRICS glyphMetrics;
455 HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics);
457 QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth);
458 QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing);
459 QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing);
460 QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight);
461 QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY);
463 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
464 advanceWidth = advanceWidth.round();
465 advanceHeight = advanceHeight.round();
468 QFixed width = advanceWidth - leftSideBearing - rightSideBearing;
470 return glyph_metrics_t(-leftSideBearing, -verticalOriginY,
471 width, m_ascent + m_descent,
472 advanceWidth, advanceHeight);
474 qErrnoWarning("QFontEngineDirectWrite::boundingBox: GetDesignGlyphMetrics failed");
477 return glyph_metrics_t();
480 QFixed QFontEngineDirectWrite::ascent() const
482 return fontDef.styleStrategy & QFont::ForceIntegerMetrics
487 QFixed QFontEngineDirectWrite::descent() const
489 return fontDef.styleStrategy & QFont::ForceIntegerMetrics
490 ? (m_descent - 1).round()
494 QFixed QFontEngineDirectWrite::leading() const
496 return fontDef.styleStrategy & QFont::ForceIntegerMetrics
501 QFixed QFontEngineDirectWrite::xHeight() const
503 return fontDef.styleStrategy & QFont::ForceIntegerMetrics
508 qreal QFontEngineDirectWrite::maxCharWidth() const
514 extern uint qt_pow_gamma[256];
516 QImage QFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
517 const QTransform &xform)
519 QImage im = imageForGlyph(glyph, subPixelPosition, 0, xform);
521 QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
522 QVector<QRgb> colors(256);
523 for (int i=0; i<256; ++i)
524 colors[i] = qRgba(0, 0, 0, i);
525 indexed.setColorTable(colors);
527 for (int y=0; y<im.height(); ++y) {
528 uint *src = (uint*) im.scanLine(y);
529 uchar *dst = indexed.scanLine(y);
530 for (int x=0; x<im.width(); ++x) {
531 *dst = 255 - (qt_pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
540 bool QFontEngineDirectWrite::supportsSubPixelPositions() const
545 QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
546 QFixed subPixelPosition,
548 const QTransform &xform)
550 UINT16 glyphIndex = t;
551 FLOAT glyphAdvance = 0;
553 DWRITE_GLYPH_OFFSET glyphOffset;
554 glyphOffset.advanceOffset = 0;
555 glyphOffset.ascenderOffset = 0;
557 DWRITE_GLYPH_RUN glyphRun;
558 glyphRun.fontFace = m_directWriteFontFace;
559 glyphRun.fontEmSize = fontDef.pixelSize;
560 glyphRun.glyphCount = 1;
561 glyphRun.glyphIndices = &glyphIndex;
562 glyphRun.glyphAdvances = &glyphAdvance;
563 glyphRun.isSideways = false;
564 glyphRun.bidiLevel = 0;
565 glyphRun.glyphOffsets = &glyphOffset;
567 DWRITE_MATRIX transform;
568 transform.dx = subPixelPosition.toReal();
570 transform.m11 = xform.m11();
571 transform.m12 = xform.m12();
572 transform.m21 = xform.m21();
573 transform.m22 = xform.m22();
575 IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
576 HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis(
580 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
581 DWRITE_MEASURING_MODE_NATURAL,
588 glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
592 rect.right += margin;
593 rect.bottom += margin;
595 int width = rect.right - rect.left;
596 int height = rect.bottom - rect.top;
598 int size = width * height * 3;
600 BYTE *alphaValues = new BYTE[size];
601 qMemSet(alphaValues, size, 0);
603 hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
609 QImage img(width, height, QImage::Format_RGB32);
610 img.fill(0xffffffff);
612 for (int y=0; y<height; ++y) {
613 uint *dest = reinterpret_cast<uint *>(img.scanLine(y));
614 BYTE *src = alphaValues + width * 3 * y;
616 for (int x=0; x<width; ++x) {
617 dest[x] = *(src) << 16
625 delete[] alphaValues;
626 glyphAnalysis->Release();
630 delete[] alphaValues;
631 glyphAnalysis->Release();
633 qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateAlphaTexture failed");
637 qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateGlyphRunAnalysis failed");
643 QImage QFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
644 QFixed subPixelPosition,
646 const QTransform &xform)
648 QImage mask = imageForGlyph(t, subPixelPosition, margin, xform);
649 return mask.depth() == 32
651 : mask.convertToFormat(QImage::Format_RGB32);
654 const char *QFontEngineDirectWrite::name() const
659 bool QFontEngineDirectWrite::canRender(const QChar *string, int len)
661 QVarLengthArray<UINT32> codePoints(len);
662 int actualLength = 0;
663 for (int i=0; i<len; ++i, actualLength++)
664 codePoints[actualLength] = getChar(string, i, len);
666 QVarLengthArray<UINT16> glyphIndices(actualLength);
667 HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength,
668 glyphIndices.data());
670 qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed");
673 for (int i=0; i<glyphIndices.size(); ++i) {
674 if (glyphIndices.at(i) == 0)
682 QFontEngine::Type QFontEngineDirectWrite::type() const
684 return QFontEngine::DirectWrite;
687 QFontEngine *QFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const
689 QFontEngine *fontEngine = new QFontEngineDirectWrite(m_directWriteFactory, m_directWriteFontFace,
692 fontEngine->fontDef = fontDef;
693 fontEngine->fontDef.pixelSize = pixelSize;
700 #endif // QT_NO_DIRECTWRITE