Move ForceIntegerMetrics testing out of the loop
[qt:qtbase.git] / src / plugins / platforms / windows / qwindowsfontenginedirectwrite.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QT_NO_DIRECTWRITE
43
44 #include "qwindowsfontenginedirectwrite.h"
45 #include "qwindowsfontdatabase.h"
46 #include "qwindowscontext.h"
47
48 #include <QtCore/QSettings>
49 #include <QtCore/QtEndian>
50 #include <QtCore/QVarLengthArray>
51
52 #include <dwrite.h>
53 #include <d2d1.h>
54
55 QT_BEGIN_NAMESPACE
56
57 // Convert from design units to logical pixels
58 #define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \
59     QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize)
60
61 namespace {
62
63     class GeometrySink: public IDWriteGeometrySink
64     {
65     public:
66         GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0)
67         {
68             Q_ASSERT(m_path != 0);
69         }
70
71         IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount);
72         IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount);
73         IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);
74         IFACEMETHOD(Close)();
75         IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
76         IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
77         IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
78
79         IFACEMETHOD_(unsigned long, AddRef)();
80         IFACEMETHOD_(unsigned long, Release)();
81         IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject);
82
83     private:
84         inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp)
85         {
86             return QPointF(inp.x, inp.y);
87         }
88
89         unsigned long m_refCount;
90         QPointF m_startPoint;
91         QPainterPath *m_path;
92     };
93
94     void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers,
95                                   UINT bezierCount)
96     {
97         for (uint i=0; i<bezierCount; ++i) {
98             QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1);
99             QPointF c2 = fromD2D1_POINT_2F(beziers[i].point2);
100             QPointF p2 = fromD2D1_POINT_2F(beziers[i].point3);
101
102             m_path->cubicTo(c1, c2, p2);
103         }
104     }
105
106     void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount)
107     {
108         for (uint i=0; i<pointsCount; ++i)
109             m_path->lineTo(fromD2D1_POINT_2F(points[i]));
110     }
111
112     void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint,
113                                    D2D1_FIGURE_BEGIN /*figureBegin*/)
114     {
115         m_startPoint = fromD2D1_POINT_2F(startPoint);
116         m_path->moveTo(m_startPoint);
117     }
118
119     IFACEMETHODIMP GeometrySink::Close()
120     {
121         return E_NOTIMPL;
122     }
123
124     void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
125     {
126         if (figureEnd == D2D1_FIGURE_END_CLOSED)
127             m_path->closeSubpath();
128     }
129
130     void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
131     {
132         m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE
133                             ? Qt::OddEvenFill
134                             : Qt::WindingFill);
135     }
136
137     void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/)
138     {
139         /* Not implemented */
140     }
141
142     IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef()
143     {
144         return InterlockedIncrement(&m_refCount);
145     }
146
147     IFACEMETHODIMP_(unsigned long) GeometrySink::Release()
148     {
149         unsigned long newCount = InterlockedDecrement(&m_refCount);
150         if (newCount == 0)
151         {
152             delete this;
153             return 0;
154         }
155
156         return newCount;
157     }
158
159     IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject)
160     {
161         if (__uuidof(IDWriteGeometrySink) == riid) {
162             *ppvObject = this;
163         } else if (__uuidof(IUnknown) == riid) {
164             *ppvObject = this;
165         } else {
166             *ppvObject = NULL;
167             return E_FAIL;
168         }
169
170         AddRef();
171         return S_OK;
172     }
173
174 }
175
176 /*!
177     \class QWindowsFontEngineDirectWrite
178     \brief Windows font engine using Direct Write.
179     \internal
180     \ingroup qt-lighthouse-win
181
182     Font engine for subpixel positioned text on Windows Vista
183     (with platform update) and Windows 7. If selected during
184     configuration, the engine will be selected only when the hinting
185     preference of a font is set to None or Vertical hinting. The font
186     database uses most of the same logic but creates a direct write
187     font based on the LOGFONT rather than a GDI handle.
188
189     The engine is currently regarded as experimental, meaning that code
190     using it should do substantial testing to make sure it covers their
191     use cases.
192
193     Will probably be superseded by a common Free Type font engine in Qt 5.X.
194 */
195
196 QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
197                                                qreal pixelSize,
198                                                const QSharedPointer<QWindowsFontEngineData> &d)
199
200     : m_fontEngineData(d)
201     , m_directWriteFontFace(directWriteFontFace)
202     , m_directWriteBitmapRenderTarget(0)
203     , m_lineThickness(-1)
204     , m_unitsPerEm(-1)
205     , m_ascent(-1)
206     , m_descent(-1)
207     , m_xHeight(-1)
208     , m_lineGap(-1)
209 {
210     if (QWindowsContext::verboseFonts)
211         qDebug("%s %g", __FUNCTION__, pixelSize);
212
213     d->directWriteFactory->AddRef();
214     m_directWriteFontFace->AddRef();
215
216     fontDef.pixelSize = pixelSize;
217     collectMetrics();
218 }
219
220 QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite()
221 {
222     if (QWindowsContext::verboseFonts)
223         qDebug("%s", __FUNCTION__);
224
225     m_fontEngineData->directWriteFactory->Release();
226     m_directWriteFontFace->Release();
227
228     if (m_directWriteBitmapRenderTarget != 0)
229         m_directWriteBitmapRenderTarget->Release();
230 }
231
232 void QWindowsFontEngineDirectWrite::collectMetrics()
233 {
234     if (m_directWriteFontFace != 0) {
235         DWRITE_FONT_METRICS metrics;
236
237         m_directWriteFontFace->GetMetrics(&metrics);
238         m_unitsPerEm = metrics.designUnitsPerEm;
239
240         m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness);
241         m_ascent = DESIGN_TO_LOGICAL(metrics.ascent);
242         m_descent = DESIGN_TO_LOGICAL(metrics.descent);
243         m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight);
244         m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap);
245         m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition);
246     }
247 }
248
249 QFixed QWindowsFontEngineDirectWrite::underlinePosition() const
250 {
251     if (m_underlinePosition > 0)
252         return m_underlinePosition;
253     else
254         return QFontEngine::underlinePosition();
255 }
256
257 QFixed QWindowsFontEngineDirectWrite::lineThickness() const
258 {
259     if (m_lineThickness > 0)
260         return m_lineThickness;
261     else
262         return QFontEngine::lineThickness();
263 }
264
265 bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const
266 {
267     bool ret = false;
268
269     if (m_directWriteFontFace) {
270         DWORD t = qbswap<quint32>(tag);
271
272         const void *tableData = 0;
273         void *tableContext = 0;
274         UINT32 tableSize;
275         BOOL exists;
276         HRESULT hr = m_directWriteFontFace->TryGetFontTable(
277                     t, &tableData, &tableSize, &tableContext, &exists
278                     );
279
280         if (SUCCEEDED(hr)) {
281             if (exists) {
282                 if (!buffer) {
283                     *length = tableSize;
284                     ret = true;
285                 } else if (*length >= tableSize) {
286                     memcpy(buffer, tableData, tableSize);
287                     ret = true;
288                 }
289             }
290             m_directWriteFontFace->ReleaseFontTable(tableContext);
291         } else {
292             qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__);
293         }
294     }
295
296     return ret;
297 }
298
299 QFixed QWindowsFontEngineDirectWrite::emSquareSize() const
300 {
301     if (m_unitsPerEm > 0)
302         return m_unitsPerEm;
303     else
304         return QFontEngine::emSquareSize();
305 }
306
307 // ### Qt 5.1: replace with QStringIterator
308 inline unsigned int getChar(const QChar *str, int &i, const int len)
309 {
310     uint uc = str[i].unicode();
311     if (QChar::isHighSurrogate(uc) && i < len-1) {
312         uint low = str[i+1].unicode();
313         if (QChar::isLowSurrogate(low)) {
314             uc = QChar::surrogateToUcs4(uc, low);
315             ++i;
316         }
317     }
318     return uc;
319 }
320
321 bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
322                                                  int *nglyphs, QFontEngine::ShaperFlags flags) const
323 {
324     if (m_directWriteFontFace != 0) {
325         QVarLengthArray<UINT32> codePoints(len);
326         for (int i=0; i<len; ++i) {
327             codePoints[i] = getChar(str, i, len);
328             if (flags & QFontEngine::RightToLeft)
329                 codePoints[i] = QChar::mirroredChar(codePoints[i]);
330         }
331
332         QVarLengthArray<UINT16> glyphIndices(len);
333         HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(),
334                                                              len,
335                                                              glyphIndices.data());
336
337         if (SUCCEEDED(hr)) {
338             for (int i=0; i<len; ++i)
339                 glyphs->glyphs[i] = glyphIndices[i];
340
341             *nglyphs = len;
342             glyphs->numGlyphs = len;
343
344             if (!(flags & GlyphIndicesOnly))
345                 recalcAdvances(glyphs, 0);
346
347             return true;
348         } else {
349             qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__);
350         }
351     }
352
353     return false;
354 }
355
356 void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
357 {
358     if (m_directWriteFontFace == 0)
359         return;
360
361     QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
362
363     // ### Caching?
364     for(int i=0; i<glyphs->numGlyphs; i++)
365         glyphIndices[i] = UINT16(glyphs->glyphs[i]);
366
367     QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
368     HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
369                                                               glyphIndices.size(),
370                                                               glyphMetrics.data());
371     if (SUCCEEDED(hr)) {
372         for (int i=0; i<glyphs->numGlyphs; ++i) {
373             glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
374             glyphs->advances_y[i] = 0;
375         }
376         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
377             for (int i = 0; i < glyphs->numGlyphs; ++i)
378                 glyphs->advances_x[i] = glyphs->advances_x[i].round();
379         }
380     } else {
381         qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
382     }
383 }
384
385 void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
386                                              QPainterPath *path, QTextItem::RenderFlags flags)
387 {
388     if (m_directWriteFontFace == 0)
389         return;
390
391     QVarLengthArray<UINT16> glyphIndices(nglyphs);
392     QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs);
393     QVarLengthArray<FLOAT> glyphAdvances(nglyphs);
394
395     for (int i=0; i<nglyphs; ++i) {
396         glyphIndices[i] = glyphs[i];
397         glyphOffsets[i].advanceOffset  = positions[i].x.toReal();
398         glyphOffsets[i].ascenderOffset = -positions[i].y.toReal();
399         glyphAdvances[i] = 0.0;
400     }
401
402     GeometrySink geometrySink(path);
403     HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(
404                 fontDef.pixelSize,
405                 glyphIndices.data(),
406                 glyphAdvances.data(),
407                 glyphOffsets.data(),
408                 nglyphs,
409                 false,
410                 flags & QTextItem::RightToLeft,
411                 &geometrySink
412                 );
413
414     if (FAILED(hr))
415         qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__);
416 }
417
418 glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs)
419 {
420     if (glyphs.numGlyphs == 0)
421         return glyph_metrics_t();
422
423     bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
424
425     QFixed w = 0;
426     for (int i = 0; i < glyphs.numGlyphs; ++i) {
427         w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i);
428
429     }
430
431     return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0);
432 }
433
434 glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g)
435 {
436     if (m_directWriteFontFace == 0)
437         return glyph_metrics_t();
438
439     UINT16 glyphIndex = g;
440
441     DWRITE_GLYPH_METRICS glyphMetrics;
442     HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics);
443     if (SUCCEEDED(hr)) {
444         QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth);
445         QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing);
446         QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing);
447         QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight);
448         QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY);
449         QFixed topSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.topSideBearing);
450         QFixed bottomSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.bottomSideBearing);
451
452         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
453             advanceWidth = advanceWidth.round();
454             advanceHeight = advanceHeight.round();
455         }
456
457         QFixed width = advanceWidth - leftSideBearing - rightSideBearing;
458         QFixed height = advanceHeight - topSideBearing - bottomSideBearing;
459         return glyph_metrics_t(leftSideBearing,
460                                -verticalOriginY + topSideBearing,
461                                width,
462                                height,
463                                advanceWidth,
464                                advanceHeight);
465     } else {
466         qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
467     }
468
469     return glyph_metrics_t();
470 }
471
472 QFixed QWindowsFontEngineDirectWrite::ascent() const
473 {
474     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
475             ? m_ascent.round()
476             : m_ascent;
477 }
478
479 QFixed QWindowsFontEngineDirectWrite::descent() const
480 {
481     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
482            ? (m_descent - 1).round()
483            : (m_descent - 1);
484 }
485
486 QFixed QWindowsFontEngineDirectWrite::leading() const
487 {
488     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
489            ? m_lineGap.round()
490            : m_lineGap;
491 }
492
493 QFixed QWindowsFontEngineDirectWrite::xHeight() const
494 {
495     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
496            ? m_xHeight.round()
497            : m_xHeight;
498 }
499
500 qreal QWindowsFontEngineDirectWrite::maxCharWidth() const
501 {
502     // ###
503     return 0;
504 }
505
506 QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
507 {
508     QImage im = imageForGlyph(glyph, subPixelPosition, 0, QTransform());
509
510     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
511     QVector<QRgb> colors(256);
512     for (int i=0; i<256; ++i)
513         colors[i] = qRgba(0, 0, 0, i);
514     indexed.setColorTable(colors);
515
516     for (int y=0; y<im.height(); ++y) {
517         uint *src = (uint*) im.scanLine(y);
518         uchar *dst = indexed.scanLine(y);
519         for (int x=0; x<im.width(); ++x) {
520             *dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
521             ++dst;
522             ++src;
523         }
524     }
525
526     return indexed;
527 }
528
529 bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const
530 {
531     return true;
532 }
533
534 QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
535                                              QFixed subPixelPosition,
536                                              int margin,
537                                              const QTransform &xform)
538 {
539     glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform);
540     int width = (metrics.width + margin * 2 + 4).ceil().toInt() ;
541     int height = (metrics.height + margin * 2 + 4).ceil().toInt();
542
543     UINT16 glyphIndex = t;
544     FLOAT glyphAdvance = metrics.xoff.toReal();
545
546     DWRITE_GLYPH_OFFSET glyphOffset;
547     glyphOffset.advanceOffset = 0;
548     glyphOffset.ascenderOffset = 0;
549
550     DWRITE_GLYPH_RUN glyphRun;
551     glyphRun.fontFace = m_directWriteFontFace;
552     glyphRun.fontEmSize = fontDef.pixelSize;
553     glyphRun.glyphCount = 1;
554     glyphRun.glyphIndices = &glyphIndex;
555     glyphRun.glyphAdvances = &glyphAdvance;
556     glyphRun.isSideways = false;
557     glyphRun.bidiLevel = 0;
558     glyphRun.glyphOffsets = &glyphOffset;
559
560     QFixed x = margin - metrics.x.floor() + subPixelPosition;
561     QFixed y = margin - metrics.y.floor();
562
563     DWRITE_MATRIX transform;
564     transform.dx = x.toReal();
565     transform.dy = y.toReal();
566     transform.m11 = xform.m11();
567     transform.m12 = xform.m12();
568     transform.m21 = xform.m21();
569     transform.m22 = xform.m22();
570
571     IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
572     HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
573                 &glyphRun,
574                 1.0f,
575                 &transform,
576                 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
577                 DWRITE_MEASURING_MODE_NATURAL,
578                 0.0, 0.0,
579                 &glyphAnalysis
580                 );
581
582     if (SUCCEEDED(hr)) {
583         RECT rect;
584         rect.left = 0;
585         rect.top = 0;
586         rect.right = width;
587         rect.bottom = height;
588
589         int size = width * height * 3;
590         BYTE *alphaValues = new BYTE[size];
591         memset(alphaValues, size, 0);
592
593         hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
594                                                &rect,
595                                                alphaValues,
596                                                size);
597
598         if (SUCCEEDED(hr)) {
599             QImage img(width, height, QImage::Format_RGB32);
600             img.fill(0xffffffff);
601
602             for (int y=0; y<height; ++y) {
603                 uint *dest = reinterpret_cast<uint *>(img.scanLine(y));
604                 BYTE *src = alphaValues + width * 3 * y;
605
606                 for (int x=0; x<width; ++x) {
607                     dest[x] = *(src) << 16
608                             | *(src + 1) << 8
609                             | *(src + 2);
610
611                     src += 3;
612                 }
613             }
614
615             delete[] alphaValues;
616             glyphAnalysis->Release();
617
618             return img;
619         } else {
620             delete[] alphaValues;
621             glyphAnalysis->Release();
622
623             qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__);
624         }
625
626     } else {
627         qErrnoWarning("%s: CreateGlyphRunAnalysis failed", __FUNCTION__);
628     }
629
630     return QImage();
631 }
632
633 QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
634                                                           QFixed subPixelPosition,
635                                                           const QTransform &xform)
636 {
637     QImage mask = imageForGlyph(t,
638                                 subPixelPosition,
639                                 glyphMargin(QFontEngineGlyphCache::Raster_RGBMask),
640                                 xform);
641
642     return mask.depth() == 32
643            ? mask
644            : mask.convertToFormat(QImage::Format_RGB32);
645 }
646
647 const char *QWindowsFontEngineDirectWrite::name() const
648 {
649     return 0;
650 }
651
652 bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len)
653 {
654     QVarLengthArray<UINT32> codePoints(len);
655     int actualLength = 0;
656     for (int i=0; i<len; ++i, actualLength++)
657         codePoints[actualLength] = getChar(string, i, len);
658
659     QVarLengthArray<UINT16> glyphIndices(actualLength);
660     HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength,
661                                                         glyphIndices.data());
662     if (FAILED(hr)) {
663         qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__);
664         return false;
665     } else {
666         for (int i=0; i<glyphIndices.size(); ++i) {
667             if (glyphIndices.at(i) == 0)
668                 return false;
669         }
670
671         return true;
672     }
673 }
674
675 QFontEngine::Type QWindowsFontEngineDirectWrite::type() const
676 {
677     return QFontEngine::DirectWrite;
678 }
679
680 QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const
681 {
682     QFontEngine *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace,
683                                                                 pixelSize, m_fontEngineData);
684
685     fontEngine->fontDef = fontDef;
686     fontEngine->fontDef.pixelSize = pixelSize;
687
688     return fontEngine;
689 }
690
691 void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request,
692                                                  int dpi, IDWriteFont *font)
693 {
694     fontDef = request;
695
696     IDWriteFontFamily *fontFamily = NULL;
697     HRESULT hr = font->GetFontFamily(&fontFamily);
698
699     IDWriteLocalizedStrings *familyNames = NULL;
700     if (SUCCEEDED(hr))
701         hr = fontFamily->GetFamilyNames(&familyNames);
702
703     UINT32 index = 0;
704
705     if (SUCCEEDED(hr)) {
706         BOOL exists = false;
707
708         wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
709         int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
710         if (defaultLocaleSuccess)
711             hr = familyNames->FindLocaleName(localeName, &index, &exists);
712
713         if (SUCCEEDED(hr) && !exists)
714             hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
715
716         if (!exists)
717             index = 0;
718     }
719
720     // Get the family name.
721     if (SUCCEEDED(hr)) {
722         UINT32 length = 0;
723
724         hr = familyNames->GetStringLength(index, &length);
725
726         if (SUCCEEDED(hr)) {
727             QVarLengthArray<wchar_t, 128> name(length+1);
728
729             hr = familyNames->GetString(index, name.data(), name.size());
730
731             if (SUCCEEDED(hr))
732                 fontDef.family = QString::fromWCharArray(name.constData());
733         }
734     }
735
736     if (familyNames != NULL)
737         familyNames->Release();
738
739     if (FAILED(hr))
740         qErrnoWarning(hr, "initFontInfo: Failed to get family name");
741
742     if (fontDef.pointSize < 0)
743         fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
744     else if (fontDef.pixelSize == -1)
745         fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
746 }
747
748 QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName)
749 {
750     static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\"
751                                "FontSubstitutes";
752     return QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
753 }
754
755 QT_END_NAMESPACE
756
757 #endif // QT_NO_DIRECTWRITE