1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QT_NO_DIRECTWRITE
43 
44 #include "qfontenginedirectwrite_p.h"
45 
46 #include <qendian.h>
47 #include <dwrite.h>
48 #include <private/qnativeimage_p.h>
49 
50 #include <d2d1.h>
51 
52 QT_BEGIN_NAMESPACE
53 
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)
57 
58 namespace {
59 
60     class GeometrySink: public IDWriteGeometrySink
61     {
62     public:
GeometrySink(QPainterPath * path)63         GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0)
64         {
65             Q_ASSERT(m_path != 0);
66         }
67 
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);
71         IFACEMETHOD(Close)();
72         IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
73         IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
74         IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
75 
76         IFACEMETHOD_(unsigned long, AddRef)();
77         IFACEMETHOD_(unsigned long, Release)();
78         IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject);
79 
80     private:
fromD2D1_POINT_2F(const D2D1_POINT_2F & inp)81         inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp)
82         {
83             return QPointF(inp.x, inp.y);
84         }
85 
86         unsigned long m_refCount;
87         QPointF m_startPoint;
88         QPainterPath *m_path;
89     };
90 
AddBeziers(const D2D1_BEZIER_SEGMENT * beziers,UINT bezierCount)91     void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers,
92                                   UINT bezierCount)
93     {
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);
98 
99             m_path->cubicTo(c1, c2, p2);
100         }
101     }
102 
AddLines(const D2D1_POINT_2F * points,UINT pointsCount)103     void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount)
104     {
105         for (uint i=0; i<pointsCount; ++i)
106             m_path->lineTo(fromD2D1_POINT_2F(points[i]));
107     }
108 
BeginFigure(D2D1_POINT_2F startPoint,D2D1_FIGURE_BEGIN)109     void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint,
110                                    D2D1_FIGURE_BEGIN /*figureBegin*/)
111     {
112         m_startPoint = fromD2D1_POINT_2F(startPoint);
113         m_path->moveTo(m_startPoint);
114     }
115 
Close()116     IFACEMETHODIMP GeometrySink::Close()
117     {
118         return E_NOTIMPL;
119     }
120 
EndFigure(D2D1_FIGURE_END figureEnd)121     void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
122     {
123         if (figureEnd == D2D1_FIGURE_END_CLOSED)
124             m_path->closeSubpath();
125     }
126 
SetFillMode(D2D1_FILL_MODE fillMode)127     void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
128     {
129         m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE
130                             ? Qt::OddEvenFill
131                             : Qt::WindingFill);
132     }
133 
SetSegmentFlags(D2D1_PATH_SEGMENT)134     void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/)
135     {
136         /* Not implemented */
137     }
138 
IFACEMETHODIMP_(unsigned long)139     IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef()
140     {
141         return InterlockedIncrement(&m_refCount);
142     }
143 
IFACEMETHODIMP_(unsigned long)144     IFACEMETHODIMP_(unsigned long) GeometrySink::Release()
145     {
146         unsigned long newCount = InterlockedDecrement(&m_refCount);
147         if (newCount == 0)
148         {
149             delete this;
150             return 0;
151         }
152 
153         return newCount;
154     }
155 
QueryInterface(IID const & riid,void ** ppvObject)156     IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject)
157     {
158         if (__uuidof(IDWriteGeometrySink) == riid) {
159             *ppvObject = this;
160         } else if (__uuidof(IUnknown) == riid) {
161             *ppvObject = this;
162         } else {
163             *ppvObject = NULL;
164             return E_FAIL;
165         }
166 
167         AddRef();
168         return S_OK;
169     }
170 
171 }
172 
QFontEngineDirectWrite(IDWriteFactory * directWriteFactory,IDWriteFontFace * directWriteFontFace,qreal pixelSize)173 QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory,
174                                                IDWriteFontFace *directWriteFontFace,
175                                                qreal pixelSize)
176     : m_directWriteFontFace(directWriteFontFace)
177     , m_directWriteFactory(directWriteFactory)
178     , m_directWriteBitmapRenderTarget(0)
179     , m_lineThickness(-1)
180     , m_unitsPerEm(-1)
181     , m_ascent(-1)
182     , m_descent(-1)
183     , m_xHeight(-1)
184     , m_lineGap(-1)
185 {
186     m_directWriteFactory->AddRef();
187     m_directWriteFontFace->AddRef();
188 
189     fontDef.pixelSize = pixelSize;
190     collectMetrics();
191 }
192 
~QFontEngineDirectWrite()193 QFontEngineDirectWrite::~QFontEngineDirectWrite()
194 {
195     m_directWriteFactory->Release();
196     m_directWriteFontFace->Release();
197 
198     if (m_directWriteBitmapRenderTarget != 0)
199         m_directWriteBitmapRenderTarget->Release();
200 }
201 
collectMetrics()202 void QFontEngineDirectWrite::collectMetrics()
203 {
204     if (m_directWriteFontFace != 0) {
205         DWRITE_FONT_METRICS metrics;
206 
207         m_directWriteFontFace->GetMetrics(&metrics);
208         m_unitsPerEm = metrics.designUnitsPerEm;
209 
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);
215     }
216 }
217 
lineThickness() const218 QFixed QFontEngineDirectWrite::lineThickness() const
219 {
220     if (m_lineThickness > 0)
221         return m_lineThickness;
222     else
223         return QFontEngine::lineThickness();
224 }
225 
getSfntTableData(uint tag,uchar * buffer,uint * length) const226 bool QFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const
227 {
228     if (m_directWriteFontFace) {
229         DWORD t = qbswap<quint32>(tag);
230 
231         const void *tableData = 0;
232         void *tableContext = 0;
233         UINT32 tableSize;
234         BOOL exists;
235         HRESULT hr = m_directWriteFontFace->TryGetFontTable(
236                     t, &tableData, &tableSize, &tableContext, &exists
237                     );
238 
239         if (SUCCEEDED(hr)) {
240             if (!exists)
241                 return false;
242 
243             if (buffer == 0) {
244                 *length = tableSize;
245                 return true;
246             } else if (*length < tableSize) {
247                 return false;
248             }
249 
250             qMemCopy(buffer, tableData, tableSize);
251             m_directWriteFontFace->ReleaseFontTable(tableContext);
252 
253             return true;
254         } else {
255             qErrnoWarning("QFontEngineDirectWrite::getSfntTableData: TryGetFontTable failed");
256         }
257     }
258 
259     return false;
260 }
261 
emSquareSize() const262 QFixed QFontEngineDirectWrite::emSquareSize() const
263 {
264     if (m_unitsPerEm > 0)
265         return m_unitsPerEm;
266     else
267         return QFontEngine::emSquareSize();
268 }
269 
getChar(const QChar * str,int & i,const int len)270 inline unsigned int getChar(const QChar *str, int &i, const int len)
271 {
272     uint ucs4 = str[i].unicode();
273     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
274         ++i;
275         ucs4 = QChar::surrogateToUcs4( ucs4, str[i].unicode());
276     }
277     return ucs4;
278 }
279 
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QTextEngine::ShaperFlags flags) const280 bool QFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
281                                           int *nglyphs, QTextEngine::ShaperFlags flags) const
282 {
283     if (m_directWriteFontFace != 0) {
284         QVarLengthArray<UINT32> codePoints(len);
285         for (int i=0; i<len; ++i) {
286             codePoints[i] = getChar(str, i, len);
287             if (flags & QTextEngine::RightToLeft)
288                 codePoints[i] = QChar::mirroredChar(codePoints[i]);
289         }
290 
291         QVarLengthArray<UINT16> glyphIndices(len);
292         HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(),
293                                                              len,
294                                                              glyphIndices.data());
295 
296         if (SUCCEEDED(hr)) {
297             for (int i=0; i<len; ++i)
298                 glyphs->glyphs[i] = glyphIndices[i];
299 
300             *nglyphs = len;
301 
302             if (!(flags & QTextEngine::GlyphIndicesOnly))
303                 recalcAdvances(glyphs, 0);
304 
305             return true;
306         } else {
307             qErrnoWarning("QFontEngineDirectWrite::stringToCMap: GetGlyphIndicesW failed");
308         }
309     }
310 
311     return false;
312 }
313 
recalcAdvances(QGlyphLayout * glyphs,QTextEngine::ShaperFlags) const314 void QFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
315 {
316     if (m_directWriteFontFace == 0)
317         return;
318 
319     QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
320 
321     // ### Caching?
322     for(int i=0; i<glyphs->numGlyphs; i++)
323         glyphIndices[i] = UINT16(glyphs->glyphs[i]);
324 
325     QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
326     HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
327                                                               glyphIndices.size(),
328                                                               glyphMetrics.data());
329     if (SUCCEEDED(hr)) {
330         for (int i=0; i<glyphs->numGlyphs; ++i) {
331             glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
332             if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
333                 glyphs->advances_x[i] = glyphs->advances_x[i].round();
334             glyphs->advances_y[i] = 0;
335         }
336     } else {
337         qErrnoWarning("QFontEngineDirectWrite::recalcAdvances: GetDesignGlyphMetrics failed");
338     }
339 }
340 
addGlyphsToPath(glyph_t * glyphs,QFixedPoint * positions,int nglyphs,QPainterPath * path,QTextItem::RenderFlags flags)341 void QFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
342                                              QPainterPath *path, QTextItem::RenderFlags flags)
343 {
344     if (m_directWriteFontFace == 0)
345         return;
346 
347     QVarLengthArray<UINT16> glyphIndices(nglyphs);
348     QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs);
349     QVarLengthArray<FLOAT> glyphAdvances(nglyphs);
350 
351     for (int i=0; i<nglyphs; ++i) {
352         glyphIndices[i] = glyphs[i];
353         glyphOffsets[i].advanceOffset  = positions[i].x.toReal();
354         glyphOffsets[i].ascenderOffset = -positions[i].y.toReal();
355         glyphAdvances[i] = 0.0;
356     }
357 
358     GeometrySink geometrySink(path);
359     HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(
360                 fontDef.pixelSize,
361                 glyphIndices.data(),
362                 glyphAdvances.data(),
363                 glyphOffsets.data(),
364                 nglyphs,
365                 false,
366                 flags & QTextItem::RightToLeft,
367                 &geometrySink
368                 );
369 
370     if (FAILED(hr))
371         qErrnoWarning("QFontEngineDirectWrite::addGlyphsToPath: GetGlyphRunOutline failed");
372 }
373 
boundingBox(const QGlyphLayout & glyphs)374 glyph_metrics_t QFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs)
375 {
376     if (glyphs.numGlyphs == 0)
377         return glyph_metrics_t();
378 
379     bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
380 
381     QFixed w = 0;
382     for (int i = 0; i < glyphs.numGlyphs; ++i) {
383         w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i);
384 
385     }
386 
387     return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0);
388 }
389 
alphaMapBoundingBox(glyph_t glyph,QFixed subPixelPosition,const QTransform & matrix,GlyphFormat)390 glyph_metrics_t QFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition,
391                                                             const QTransform &matrix,
392                                                             GlyphFormat /*format*/)
393 {
394     glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance
395 
396     UINT16 glyphIndex = glyph;
397     FLOAT glyphAdvance = 0;
398 
399     DWRITE_GLYPH_OFFSET glyphOffset;
400     glyphOffset.advanceOffset = 0;
401     glyphOffset.ascenderOffset = 0;
402 
403     DWRITE_GLYPH_RUN glyphRun;
404     glyphRun.fontFace = m_directWriteFontFace;
405     glyphRun.fontEmSize = fontDef.pixelSize;
406     glyphRun.glyphCount = 1;
407     glyphRun.glyphIndices = &glyphIndex;
408     glyphRun.glyphAdvances = &glyphAdvance;
409     glyphRun.isSideways = false;
410     glyphRun.bidiLevel = 0;
411     glyphRun.glyphOffsets = &glyphOffset;
412 
413     DWRITE_MATRIX transform;
414     transform.dx = subPixelPosition.toReal();
415     transform.dy = 0;
416     transform.m11 = matrix.m11();
417     transform.m12 = matrix.m12();
418     transform.m21 = matrix.m21();
419     transform.m22 = matrix.m22();
420 
421     IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
422     HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis(
423                 &glyphRun,
424                 1.0f,
425                 &transform,
426                 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
427                 DWRITE_MEASURING_MODE_NATURAL,
428                 0.0, 0.0,
429                 &glyphAnalysis
430                 );
431 
432     if (SUCCEEDED(hr)) {
433         RECT rect;
434         glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
435         glyphAnalysis->Release();
436 
437         return glyph_metrics_t(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
438                                bbox.xoff, bbox.yoff);
439     } else {
440         return glyph_metrics_t();
441     }
442 }
443 
boundingBox(glyph_t g)444 glyph_metrics_t QFontEngineDirectWrite::boundingBox(glyph_t g)
445 {
446     if (m_directWriteFontFace == 0)
447         return glyph_metrics_t();
448 
449     UINT16 glyphIndex = g;
450 
451     DWRITE_GLYPH_METRICS glyphMetrics;
452     HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics);
453     if (SUCCEEDED(hr)) {
454         QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth);
455         QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing);
456         QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing);
457         QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight);
458         QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY);
459 
460         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
461             advanceWidth = advanceWidth.round();
462             advanceHeight = advanceHeight.round();
463         }
464 
465         QFixed width = advanceWidth - leftSideBearing - rightSideBearing;
466 
467         return glyph_metrics_t(-leftSideBearing, -verticalOriginY,
468                                width, m_ascent + m_descent,
469                                advanceWidth, advanceHeight);
470     } else {
471         qErrnoWarning("QFontEngineDirectWrite::boundingBox: GetDesignGlyphMetrics failed");
472     }
473 
474     return glyph_metrics_t();
475 }
476 
ascent() const477 QFixed QFontEngineDirectWrite::ascent() const
478 {
479     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
480             ? m_ascent.round()
481             : m_ascent;
482 }
483 
descent() const484 QFixed QFontEngineDirectWrite::descent() const
485 {
486     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
487            ? (m_descent - 1).round()
488            : (m_descent - 1);
489 }
490 
leading() const491 QFixed QFontEngineDirectWrite::leading() const
492 {
493     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
494            ? m_lineGap.round()
495            : m_lineGap;
496 }
497 
xHeight() const498 QFixed QFontEngineDirectWrite::xHeight() const
499 {
500     return fontDef.styleStrategy & QFont::ForceIntegerMetrics
501            ? m_xHeight.round()
502            : m_xHeight;
503 }
504 
maxCharWidth() const505 qreal QFontEngineDirectWrite::maxCharWidth() const
506 {
507     // ###
508     return 0;
509 }
510 
511 extern uint qt_pow_gamma[256];
512 
alphaMapForGlyph(glyph_t glyph,QFixed subPixelPosition,const QTransform & xform)513 QImage QFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
514                                                 const QTransform &xform)
515 {
516     QImage im = imageForGlyph(glyph, subPixelPosition, 0, xform);
517 
518     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
519     QVector<QRgb> colors(256);
520     for (int i=0; i<256; ++i)
521         colors[i] = qRgba(0, 0, 0, i);
522     indexed.setColorTable(colors);
523 
524     for (int y=0; y<im.height(); ++y) {
525         uint *src = (uint*) im.scanLine(y);
526         uchar *dst = indexed.scanLine(y);
527         for (int x=0; x<im.width(); ++x) {
528             *dst = 255 - (qt_pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
529             ++dst;
530             ++src;
531         }
532     }
533 
534     return indexed;
535 }
536 
supportsSubPixelPositions() const537 bool QFontEngineDirectWrite::supportsSubPixelPositions() const
538 {
539     return true;
540 }
541 
imageForGlyph(glyph_t t,QFixed subPixelPosition,int margin,const QTransform & xform)542 QImage QFontEngineDirectWrite::imageForGlyph(glyph_t t,
543                                              QFixed subPixelPosition,
544                                              int margin,
545                                              const QTransform &xform)
546 {
547     UINT16 glyphIndex = t;
548     FLOAT glyphAdvance = 0;
549 
550     DWRITE_GLYPH_OFFSET glyphOffset;
551     glyphOffset.advanceOffset = 0;
552     glyphOffset.ascenderOffset = 0;
553 
554     DWRITE_GLYPH_RUN glyphRun;
555     glyphRun.fontFace = m_directWriteFontFace;
556     glyphRun.fontEmSize = fontDef.pixelSize;
557     glyphRun.glyphCount = 1;
558     glyphRun.glyphIndices = &glyphIndex;
559     glyphRun.glyphAdvances = &glyphAdvance;
560     glyphRun.isSideways = false;
561     glyphRun.bidiLevel = 0;
562     glyphRun.glyphOffsets = &glyphOffset;
563 
564     DWRITE_MATRIX transform;
565     transform.dx = subPixelPosition.toReal();
566     transform.dy = 0;
567     transform.m11 = xform.m11();
568     transform.m12 = xform.m12();
569     transform.m21 = xform.m21();
570     transform.m22 = xform.m22();
571 
572     IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
573     HRESULT hr = m_directWriteFactory->CreateGlyphRunAnalysis(
574                 &glyphRun,
575                 1.0f,
576                 &transform,
577                 DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
578                 DWRITE_MEASURING_MODE_NATURAL,
579                 0.0, 0.0,
580                 &glyphAnalysis
581                 );
582 
583     if (SUCCEEDED(hr)) {
584         RECT rect;
585         glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
586 
587         rect.left -= margin;
588         rect.top -= margin;
589         rect.right += margin;
590         rect.bottom += margin;
591 
592         int width = rect.right - rect.left;
593         int height = rect.bottom - rect.top;
594 
595         int size = width * height * 3;
596         if (size > 0) {
597             BYTE *alphaValues = new BYTE[size];
598             qMemSet(alphaValues, size, 0);
599 
600             hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
601                                                    &rect,
602                                                    alphaValues,
603                                                    size);
604 
605             if (SUCCEEDED(hr)) {
606                 QImage img(width, height, QImage::Format_RGB32);
607                 img.fill(0xffffffff);
608 
609                 for (int y=0; y<height; ++y) {
610                     uint *dest = reinterpret_cast<uint *>(img.scanLine(y));
611                     BYTE *src = alphaValues + width * 3 * y;
612 
613                     for (int x=0; x<width; ++x) {
614                         dest[x] = *(src) << 16
615                                 | *(src + 1) << 8
616                                 | *(src + 2);
617 
618                         src += 3;
619                     }
620                 }
621 
622                 delete[] alphaValues;
623                 glyphAnalysis->Release();
624 
625                 return img;
626             } else {
627                 delete[] alphaValues;
628                 glyphAnalysis->Release();
629 
630                 qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateAlphaTexture failed");
631             }
632         }
633     } else {
634         qErrnoWarning("QFontEngineDirectWrite::imageForGlyph: CreateGlyphRunAnalysis failed");
635     }
636 
637     return QImage();
638 }
639 
alphaRGBMapForGlyph(glyph_t t,QFixed subPixelPosition,int margin,const QTransform & xform)640 QImage QFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
641                                                    QFixed subPixelPosition,
642                                                    int margin,
643                                                    const QTransform &xform)
644 {
645     QImage mask = imageForGlyph(t, subPixelPosition, margin, xform);
646     return mask.depth() == 32
647            ? mask
648            : mask.convertToFormat(QImage::Format_RGB32);
649 }
650 
name() const651 const char *QFontEngineDirectWrite::name() const
652 {
653     return 0;
654 }
655 
canRender(const QChar * string,int len)656 bool QFontEngineDirectWrite::canRender(const QChar *string, int len)
657 {
658     QVarLengthArray<UINT32> codePoints(len);
659     int actualLength = 0;
660     for (int i=0; i<len; ++i, actualLength++)
661         codePoints[actualLength] = getChar(string, i, len);
662 
663     QVarLengthArray<UINT16> glyphIndices(actualLength);
664     HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength,
665                                                         glyphIndices.data());
666     if (FAILED(hr)) {
667         qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed");
668         return false;
669     } else {
670         for (int i=0; i<glyphIndices.size(); ++i) {
671             if (glyphIndices.at(i) == 0)
672                 return false;
673         }
674 
675         return true;
676     }
677 }
678 
type() const679 QFontEngine::Type QFontEngineDirectWrite::type() const
680 {
681     return QFontEngine::DirectWrite;
682 }
683 
cloneWithSize(qreal pixelSize) const684 QFontEngine *QFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const
685 {
686     QFontEngine *fontEngine = new QFontEngineDirectWrite(m_directWriteFactory, m_directWriteFontFace,
687                                                          pixelSize);
688 
689     fontEngine->fontDef = fontDef;
690     fontEngine->fontDef.pixelSize = pixelSize;
691 
692     return fontEngine;
693 }
694 
695 QT_END_NAMESPACE
696 
697 #endif // QT_NO_DIRECTWRITE
698