1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsfontengine_p.h"
41 #include "qwindowsnativeimage_p.h"
42 #include "qwindowsfontdatabase_p.h"
43 #include <QtCore/qt_windows.h>
44 #include "qwindowsfontenginedirectwrite_p.h"
45 
46 #include <QtGui/qpa/qplatformintegration.h>
47 #include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
48 #include <QtGui/private/qguiapplication_p.h>
49 #include <QtGui/QPaintDevice>
50 #include <QtGui/QBitmap>
51 #include <QtGui/QPainter>
52 #include <QtGui/private/qpainter_p.h>
53 #include <QtGui/QPaintEngine>
54 #include <QtGui/private/qpaintengine_raster_p.h>
55 
56 #include <QtCore/QtEndian>
57 #include <QtCore/QFile>
58 #include <QtCore/qmath.h>
59 #include <QtCore/QTextStream>
60 #include <QtCore/QThreadStorage>
61 #include <QtCore/private/qsystemlibrary_p.h>
62 #include <QtCore/private/qstringiterator_p.h>
63 
64 #include <QtCore/QDebug>
65 
66 #include <limits.h>
67 
68 #if !defined(QT_NO_DIRECTWRITE)
69 #  include <dwrite.h>
70 #  include <comdef.h>
71 #endif
72 
73 QT_BEGIN_NAMESPACE
74 
75 //### mingw needed define
76 #ifndef TT_PRIM_CSPLINE
77 #define TT_PRIM_CSPLINE 3
78 #endif
79 
80 // GetFontData expects the tags in little endian ;(
81 #define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (\
82     (((quint32)(ch4)) << 24) | \
83     (((quint32)(ch3)) << 16) | \
84     (((quint32)(ch2)) << 8) | \
85     ((quint32)(ch1)) \
86    )
87 
88 // common DC for all fonts
89 
90 typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
91 static PtrGetCharWidthI ptrGetCharWidthI = 0;
92 static bool resolvedGetCharWidthI = false;
93 
resolveGetCharWidthI()94 static void resolveGetCharWidthI()
95 {
96     if (resolvedGetCharWidthI)
97         return;
98     resolvedGetCharWidthI = true;
99     ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI");
100 }
101 
102 // general font engine
103 
lineThickness() const104 QFixed QWindowsFontEngine::lineThickness() const
105 {
106     if(lineWidth > 0)
107         return lineWidth;
108 
109     return QFontEngine::lineThickness();
110 }
111 
getOutlineTextMetric(HDC hdc)112 static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
113 {
114     const auto size = GetOutlineTextMetrics(hdc, 0, nullptr);
115     auto otm = reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size));
116     GetOutlineTextMetrics(hdc, size, otm);
117     return otm;
118 }
119 
hasCFFTable() const120 bool QWindowsFontEngine::hasCFFTable() const
121 {
122     HDC hdc = m_fontEngineData->hdc;
123     SelectObject(hdc, hfont);
124     return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR;
125 }
126 
hasCMapTable() const127 bool QWindowsFontEngine::hasCMapTable() const
128 {
129     HDC hdc = m_fontEngineData->hdc;
130     SelectObject(hdc, hfont);
131     return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR;
132 }
133 
stringFromOutLineTextMetric(const OUTLINETEXTMETRIC * otm,PSTR offset)134 static inline QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset)
135 {
136     const uchar *p = reinterpret_cast<const uchar *>(otm) + quintptr(offset);
137     return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(p));
138 }
139 
getCMap()140 void QWindowsFontEngine::getCMap()
141 {
142     ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable();
143 
144     cffTable = hasCFFTable();
145 
146     HDC hdc = m_fontEngineData->hdc;
147     SelectObject(hdc, hfont);
148     bool symb = false;
149     if (ttf) {
150         cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
151         cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
152                        cmapTable.size(), &symb, &cmapSize);
153     }
154     if (!cmap) {
155         ttf = false;
156         symb = false;
157     }
158     symbol = symb;
159     designToDevice = 1;
160     _faceId.index = 0;
161     if(cmap) {
162         OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
163         unitsPerEm = int(otm->otmEMSquare);
164         const QFixed unitsPerEmF(unitsPerEm);
165         designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize);
166         x_height = int(otm->otmsXHeight);
167         loadKerningPairs(designToDevice);
168         _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName));
169         lineWidth = otm->otmsUnderscoreSize;
170         fsType = otm->otmfsType;
171         free(otm);
172 
173     } else {
174         unitsPerEm = tm.tmHeight;
175     }
176 }
177 
getGlyphIndexes(const QChar * str,int numChars,QGlyphLayout * glyphs) const178 int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const
179 {
180     int glyph_pos = 0;
181     {
182         if (symbol) {
183             QStringIterator it(str, str + numChars);
184             while (it.hasNext()) {
185                 const uint uc = it.next();
186                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
187                 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
188                     glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
189                 ++glyph_pos;
190             }
191         } else if (ttf) {
192             QStringIterator it(str, str + numChars);
193             while (it.hasNext()) {
194                 const uint uc = it.next();
195                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
196                 ++glyph_pos;
197             }
198         } else {
199             QStringIterator it(str, str + numChars);
200             while (it.hasNext()) {
201                 const uint uc = it.next();
202                 if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar)
203                     glyphs->glyphs[glyph_pos] = uc;
204                 else
205                     glyphs->glyphs[glyph_pos] = 0;
206                 ++glyph_pos;
207             }
208         }
209     }
210     glyphs->numGlyphs = glyph_pos;
211     return glyph_pos;
212 }
213 
214 /*!
215     \class QWindowsFontEngine
216     \brief Standard Windows font engine.
217     \internal
218 
219     Will probably be superseded by a common Free Type font engine in Qt 5.X.
220 */
221 
QWindowsFontEngine(const QString & name,LOGFONT lf,const QSharedPointer<QWindowsFontEngineData> & fontEngineData)222 QWindowsFontEngine::QWindowsFontEngine(const QString &name,
223                                        LOGFONT lf,
224                                const QSharedPointer<QWindowsFontEngineData> &fontEngineData)
225     : QFontEngine(Win),
226     m_fontEngineData(fontEngineData),
227     _name(name),
228     m_logfont(lf),
229     ttf(0),
230     hasOutline(0)
231 {
232     qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight;
233     hfont = CreateFontIndirect(&m_logfont);
234     if (!hfont) {
235         qErrnoWarning("%s: CreateFontIndirect failed for family '%s'", __FUNCTION__, qPrintable(name));
236         hfont = QWindowsFontDatabase::systemFont();
237     }
238 
239     HDC hdc = m_fontEngineData->hdc;
240     SelectObject(hdc, hfont);
241     const BOOL res = GetTextMetrics(hdc, &tm);
242     if (!res) {
243         qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
244         ZeroMemory(&tm, sizeof(TEXTMETRIC));
245     }
246 
247     fontDef.pixelSize = -lf.lfHeight;
248     fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
249 
250     cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
251     getCMap();
252 
253     if (!resolvedGetCharWidthI)
254         resolveGetCharWidthI();
255 
256     // ### Properties accessed by QWin32PrintEngine (QtPrintSupport)
257     QVariantMap userData;
258     userData.insert(QStringLiteral("logFont"), QVariant::fromValue(m_logfont));
259     userData.insert(QStringLiteral("hFont"), QVariant::fromValue(hfont));
260     userData.insert(QStringLiteral("trueType"), QVariant(bool(ttf)));
261     setUserData(userData);
262 
263     hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0;
264 }
265 
~QWindowsFontEngine()266 QWindowsFontEngine::~QWindowsFontEngine()
267 {
268     if (designAdvances)
269         free(designAdvances);
270 
271     if (widthCache)
272         free(widthCache);
273 
274     // make sure we aren't by accident still selected
275     SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont());
276 
277     if (!DeleteObject(hfont))
278         qErrnoWarning("%s: QFontEngineWin: failed to delete font...", __FUNCTION__);
279     qCDebug(lcQpaFonts) << __FUNCTION__ << _name;
280 
281     if (!uniqueFamilyName.isEmpty()) {
282         if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
283             QPlatformFontDatabase *pfdb = pi->fontDatabase();
284             static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
285         }
286     }
287 }
288 
glyphIndex(uint ucs4) const289 glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const
290 {
291     glyph_t glyph = 0;
292 
293     if (symbol) {
294         glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
295         if (glyph == 0 && ucs4 < 0x100)
296             glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
297     } else if (ttf) {
298         glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
299     } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
300         glyph = ucs4;
301     }
302 
303     return glyph;
304 }
305 
selectDesignFont() const306 HGDIOBJ QWindowsFontEngine::selectDesignFont() const
307 {
308     LOGFONT f = m_logfont;
309     f.lfHeight = -unitsPerEm;
310     f.lfWidth = 0;
311     HFONT designFont = CreateFontIndirect(&f);
312     return SelectObject(m_fontEngineData->hdc, designFont);
313 }
314 
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QFontEngine::ShaperFlags flags) const315 bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
316 {
317     Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
318     if (*nglyphs < len) {
319         *nglyphs = len;
320         return false;
321     }
322 
323     glyphs->numGlyphs = *nglyphs;
324     *nglyphs = getGlyphIndexes(str, len, glyphs);
325 
326     if (!(flags & GlyphIndicesOnly))
327         recalcAdvances(glyphs, flags);
328 
329     return true;
330 }
331 
calculateTTFGlyphWidth(HDC hdc,UINT glyph,int & width)332 inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
333 {
334     if (ptrGetCharWidthI)
335         ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
336 }
337 
recalcAdvances(QGlyphLayout * glyphs,QFontEngine::ShaperFlags flags) const338 void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
339 {
340     HGDIOBJ oldFont = 0;
341     HDC hdc = m_fontEngineData->hdc;
342     if (ttf && (flags & DesignMetrics)) {
343         for(int i = 0; i < glyphs->numGlyphs; i++) {
344             unsigned int glyph = glyphs->glyphs[i];
345             if(int(glyph) >= designAdvancesSize) {
346                 const int newSize = int(glyph + 256) >> 8 << 8;
347                 designAdvances = reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) * sizeof(QFixed)));
348                 Q_CHECK_PTR(designAdvances);
349                 for(int i = designAdvancesSize; i < newSize; ++i)
350                     designAdvances[i] = -1000000;
351                 designAdvancesSize = newSize;
352             }
353             if (designAdvances[glyph] < -999999) {
354                 if (!oldFont)
355                     oldFont = selectDesignFont();
356 
357                 int width = 0;
358                 calculateTTFGlyphWidth(hdc, glyph, width);
359                 designAdvances[glyph] = QFixed(width) / designToDevice;
360             }
361             glyphs->advances[i] = designAdvances[glyph];
362         }
363         if(oldFont)
364             DeleteObject(SelectObject(hdc, oldFont));
365     } else {
366         for(int i = 0; i < glyphs->numGlyphs; i++) {
367             unsigned int glyph = glyphs->glyphs[i];
368 
369             if (glyph >= widthCacheSize) {
370                 const uint newSize = (glyph + 256) >> 8 << 8;
371                 widthCache = reinterpret_cast<unsigned char *>(realloc(widthCache, newSize * sizeof(QFixed)));
372                 Q_CHECK_PTR(widthCache);
373                 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
374                 widthCacheSize = newSize;
375             }
376             glyphs->advances[i] = widthCache[glyph];
377             // font-width cache failed
378             if (glyphs->advances[i].value() == 0) {
379                 int width = 0;
380                 if (!oldFont)
381                     oldFont = SelectObject(hdc, hfont);
382 
383                 if (!ttf) {
384                     QChar ch[2] = { ushort(glyph), 0 };
385                     int chrLen = 1;
386                     if (QChar::requiresSurrogates(glyph)) {
387                         ch[0] = QChar::highSurrogate(glyph);
388                         ch[1] = QChar::lowSurrogate(glyph);
389                         ++chrLen;
390                     }
391                     SIZE size = {0, 0};
392                     GetTextExtentPoint32(hdc, reinterpret_cast<const wchar_t *>(ch), chrLen, &size);
393                     width = size.cx;
394                 } else {
395                     calculateTTFGlyphWidth(hdc, glyph, width);
396                 }
397                 glyphs->advances[i] = width;
398                 // if glyph's within cache range, store it for later
399                 if (width > 0 && width < 0x100)
400                     widthCache[glyph] = uchar(width);
401             }
402         }
403 
404         if (oldFont)
405             SelectObject(hdc, oldFont);
406     }
407 }
408 
boundingBox(const QGlyphLayout & glyphs)409 glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs)
410 {
411     if (glyphs.numGlyphs == 0)
412         return glyph_metrics_t();
413 
414     QFixed w = 0;
415     for (int i = 0; i < glyphs.numGlyphs; ++i)
416         w += glyphs.effectiveAdvance(i);
417 
418     return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
419 }
420 
getOutlineMetrics(glyph_t glyph,const QTransform & t,glyph_metrics_t * metrics) const421 bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
422 {
423     Q_ASSERT(metrics != 0);
424 
425     HDC hdc = m_fontEngineData->hdc;
426 
427     GLYPHMETRICS gm;
428     DWORD res = 0;
429     MAT2 mat;
430     mat.eM11.value = mat.eM22.value = 1;
431     mat.eM11.fract = mat.eM22.fract = 0;
432     mat.eM21.value = mat.eM12.value = 0;
433     mat.eM21.fract = mat.eM12.fract = 0;
434 
435     if (t.type() > QTransform::TxTranslate) {
436         // We need to set the transform using the HDC's world
437         // matrix rather than using the MAT2 above, because the
438         // results provided when transforming via MAT2 does not
439         // match the glyphs that are drawn using a WorldTransform
440         XFORM xform;
441         xform.eM11 = FLOAT(t.m11());
442         xform.eM12 = FLOAT(t.m12());
443         xform.eM21 = FLOAT(t.m21());
444         xform.eM22 = FLOAT(t.m22());
445         xform.eDx = 0;
446         xform.eDy = 0;
447         SetGraphicsMode(hdc, GM_ADVANCED);
448         SetWorldTransform(hdc, &xform);
449     }
450 
451     uint format = GGO_METRICS;
452     if (ttf)
453         format |= GGO_GLYPH_INDEX;
454     res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
455 
456     if (t.type() > QTransform::TxTranslate) {
457         XFORM xform;
458         xform.eM11 = xform.eM22 = 1;
459         xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
460         SetWorldTransform(hdc, &xform);
461         SetGraphicsMode(hdc, GM_COMPATIBLE);
462     }
463 
464     if (res != GDI_ERROR) {
465         *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
466                                    int(gm.gmBlackBoxX), int(gm.gmBlackBoxY),
467                                    gm.gmCellIncX, gm.gmCellIncY);
468         return true;
469     } else {
470         return false;
471     }
472 }
473 
boundingBox(glyph_t glyph,const QTransform & t)474 glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t)
475 {
476     HDC hdc = m_fontEngineData->hdc;
477     SelectObject(hdc, hfont);
478 
479     glyph_metrics_t glyphMetrics;
480     bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
481 
482     if (!ttf && !success) {
483         // Bitmap fonts
484         wchar_t ch = wchar_t(glyph);
485         ABCFLOAT abc;
486         GetCharABCWidthsFloat(hdc, ch, ch, &abc);
487         int width = qRound(abc.abcfB);
488 
489         return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
490     }
491 
492     return glyphMetrics;
493 }
494 
ascent() const495 QFixed QWindowsFontEngine::ascent() const
496 {
497     return tm.tmAscent;
498 }
499 
descent() const500 QFixed QWindowsFontEngine::descent() const
501 {
502     return tm.tmDescent;
503 }
504 
leading() const505 QFixed QWindowsFontEngine::leading() const
506 {
507     return tm.tmExternalLeading;
508 }
509 
510 namespace {
511 #   pragma pack(1)
512 
513     struct OS2Table
514     {
515         quint16 version;
516         qint16  avgCharWidth;
517         quint16 weightClass;
518         quint16 widthClass;
519         quint16 type;
520         qint16  subscriptXSize;
521         qint16  subscriptYSize;
522         qint16  subscriptXOffset;
523         qint16  subscriptYOffset;
524         qint16  superscriptXSize;
525         qint16  superscriptYSize;
526         qint16  superscriptXOffset;
527         qint16  superscriptYOffset;
528         qint16  strikeOutSize;
529         qint16  strikeOutPosition;
530         qint16  familyClass;
531         quint8  panose[10];
532         quint32 unicodeRanges[4];
533         quint8  vendorID[4];
534         quint16 selection;
535         quint16 firstCharIndex;
536         quint16 lastCharIndex;
537         qint16  typoAscender;
538         qint16  typoDescender;
539         qint16  typoLineGap;
540         quint16 winAscent;
541         quint16 winDescent;
542         quint32 codepageRanges[2];
543         qint16  height;
544         qint16  capHeight;
545         quint16 defaultChar;
546         quint16 breakChar;
547         quint16 maxContext;
548     };
549 
550 #   pragma pack()
551 }
552 
capHeight() const553 QFixed QWindowsFontEngine::capHeight() const
554 {
555     const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
556     if (size_t(tableData.size()) >= sizeof(OS2Table)) {
557         const OS2Table *table = reinterpret_cast<const OS2Table *>(tableData.constData());
558         if (qFromBigEndian<quint16>(table->version) >= 2) {
559             qint16 capHeight = qFromBigEndian<qint16>(table->capHeight);
560             if (capHeight > 0)
561                 return QFixed(capHeight) / designToDevice;
562         }
563     }
564     return calculatedCapHeight();
565 }
566 
xHeight() const567 QFixed QWindowsFontEngine::xHeight() const
568 {
569     if(x_height >= 0)
570         return x_height;
571     return QFontEngine::xHeight();
572 }
573 
averageCharWidth() const574 QFixed QWindowsFontEngine::averageCharWidth() const
575 {
576     return tm.tmAveCharWidth;
577 }
578 
maxCharWidth() const579 qreal QWindowsFontEngine::maxCharWidth() const
580 {
581     return tm.tmMaxCharWidth;
582 }
583 
584 enum { max_font_count = 256 };
585 static const ushort char_table[] = {
586         40,
587         67,
588         70,
589         75,
590         86,
591         88,
592         89,
593         91,
594         102,
595         114,
596         124,
597         127,
598         205,
599         645,
600         884,
601         922,
602         1070,
603         12386,
604         0
605 };
606 
607 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
608 
609 #ifndef Q_CC_MINGW
getGlyphBearings(glyph_t glyph,qreal * leftBearing,qreal * rightBearing)610 void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
611 {
612     HDC hdc = m_fontEngineData->hdc;
613     SelectObject(hdc, hfont);
614 
615     if (ttf) {
616         ABC abcWidths;
617         GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
618         if (leftBearing)
619             *leftBearing = abcWidths.abcA;
620         if (rightBearing)
621             *rightBearing = abcWidths.abcC;
622     } else {
623         QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
624     }
625 }
626 #endif // Q_CC_MINGW
627 
hasUnreliableGlyphOutline() const628 bool QWindowsFontEngine::hasUnreliableGlyphOutline() const
629 {
630     return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline();
631 }
632 
minLeftBearing() const633 qreal QWindowsFontEngine::minLeftBearing() const
634 {
635     if (lbearing == SHRT_MIN)
636         minRightBearing(); // calculates both
637 
638     return lbearing;
639 }
640 
minRightBearing() const641 qreal QWindowsFontEngine::minRightBearing() const
642 {
643     if (rbearing == SHRT_MIN) {
644         int ml = 0;
645         int mr = 0;
646         HDC hdc = m_fontEngineData->hdc;
647         SelectObject(hdc, hfont);
648         if (ttf) {
649             ABC *abc = 0;
650             int n = tm.tmLastChar - tm.tmFirstChar;
651             if (n <= max_font_count) {
652                 abc = new ABC[n+1];
653                 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
654             } else {
655                 abc = new ABC[char_table_entries+1];
656                 for(int i = 0; i < char_table_entries; i++)
657                     GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
658                 n = char_table_entries;
659             }
660             ml = abc[0].abcA;
661             mr = abc[0].abcC;
662             for (int i = 1; i < n; i++) {
663                 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
664                     ml = qMin(ml,abc[i].abcA);
665                     mr = qMin(mr,abc[i].abcC);
666                 }
667             }
668             delete [] abc;
669         } else {
670             ABCFLOAT *abc = 0;
671             int n = tm.tmLastChar - tm.tmFirstChar+1;
672             if (n <= max_font_count) {
673                 abc = new ABCFLOAT[n];
674                 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
675             } else {
676                 abc = new ABCFLOAT[char_table_entries];
677                 for(int i = 0; i < char_table_entries; i++)
678                     GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
679                 n = char_table_entries;
680             }
681             float fml = abc[0].abcfA;
682             float fmr = abc[0].abcfC;
683             for (int i=1; i<n; i++) {
684                 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
685                     fml = qMin(fml,abc[i].abcfA);
686                     fmr = qMin(fmr,abc[i].abcfC);
687                 }
688             }
689             ml = int(fml - 0.9999);
690             mr = int(fmr - 0.9999);
691             delete [] abc;
692         }
693         lbearing = ml;
694         rbearing = mr;
695     }
696 
697     return rbearing;
698 }
699 
qt_fixed_to_double(const FIXED & p)700 static inline double qt_fixed_to_double(const FIXED &p) {
701     return ((p.value << 16) + p.fract) / 65536.0;
702 }
703 
qt_to_qpointf(const POINTFX & pt,qreal scale,qreal stretch)704 static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) {
705     return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
706 }
707 
708 #ifndef GGO_UNHINTED
709 #define GGO_UNHINTED 0x0100
710 #endif
711 
addGlyphToPath(glyph_t glyph,const QFixedPoint & position,HDC hdc,QPainterPath * path,bool ttf,glyph_metrics_t * metric=0,qreal scale=1.0,qreal stretch=1.0)712 static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
713                            QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0,
714                            qreal scale = 1.0, qreal stretch = 1.0)
715 {
716     MAT2 mat;
717     mat.eM11.value = mat.eM22.value = 1;
718     mat.eM11.fract = mat.eM22.fract = 0;
719     mat.eM21.value = mat.eM12.value = 0;
720     mat.eM21.fract = mat.eM12.fract = 0;
721 
722     GLYPHMETRICS gMetric;
723     memset(&gMetric, 0, sizeof(GLYPHMETRICS));
724 
725     if (metric) {
726         // If metrics requested, retrieve first using GGO_METRICS, because the returned
727         // values are incorrect for OpenType PS fonts if obtained at the same time as the
728         // glyph paths themselves (ie. with GGO_NATIVE as the format).
729         uint format = GGO_METRICS;
730         if (ttf)
731             format |= GGO_GLYPH_INDEX;
732         if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR)
733             return false;
734         // #### obey scale
735         *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
736                                   int(gMetric.gmBlackBoxX), int(gMetric.gmBlackBoxY),
737                                   gMetric.gmCellIncX, gMetric.gmCellIncY);
738     }
739 
740     uint glyphFormat = GGO_NATIVE;
741 
742     if (ttf)
743         glyphFormat |= GGO_GLYPH_INDEX;
744 
745     const DWORD bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
746     if (bufferSize == GDI_ERROR)
747         return false;
748 
749     char *dataBuffer = new char[bufferSize];
750     DWORD ret = GDI_ERROR;
751     ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
752     if (ret == GDI_ERROR) {
753         delete [] dataBuffer;
754         return false;
755     }
756 
757     DWORD offset = 0;
758     DWORD headerOffset = 0;
759 
760     QPointF oset = position.toPointF();
761     while (headerOffset < bufferSize) {
762         const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset);
763 
764         QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
765         path->moveTo(lastPoint + oset);
766         offset += sizeof(TTPOLYGONHEADER);
767         while (offset < headerOffset + ttph->cb) {
768             const TTPOLYCURVE *curve = reinterpret_cast<const TTPOLYCURVE *>(dataBuffer + offset);
769             switch (curve->wType) {
770             case TT_PRIM_LINE: {
771                 for (int i=0; i<curve->cpfx; ++i) {
772                     QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
773                     path->lineTo(p);
774                 }
775                 break;
776             }
777             case TT_PRIM_QSPLINE: {
778                 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
779                 QPointF prev(elm.x, elm.y);
780                 QPointF endPoint;
781                 for (int i=0; i<curve->cpfx - 1; ++i) {
782                     QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
783                     QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
784                     if (i < curve->cpfx - 2) {
785                         endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
786                     } else {
787                         endPoint = p2;
788                     }
789 
790                     path->quadTo(p1, endPoint);
791                     prev = endPoint;
792                 }
793 
794                 break;
795             }
796             case TT_PRIM_CSPLINE: {
797                 for (int i=0; i<curve->cpfx; ) {
798                     QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
799                     QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
800                     QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
801                     path->cubicTo(p2, p3, p4);
802                 }
803                 break;
804             }
805             default:
806                 qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
807             }
808             offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
809         }
810         path->closeSubpath();
811         headerOffset += ttph->cb;
812     }
813     delete [] dataBuffer;
814 
815     return true;
816 }
817 
addGlyphsToPath(glyph_t * glyphs,QFixedPoint * positions,int nglyphs,QPainterPath * path,QTextItem::RenderFlags)818 void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
819                                      QPainterPath *path, QTextItem::RenderFlags)
820 {
821     LOGFONT lf = m_logfont;
822     // The sign must be negative here to make sure we match against character height instead of
823     // hinted cell height. This ensures that we get linear matching, and we need this for
824     // paths since we later on apply a scaling transform to the glyph outline to get the
825     // font at the correct pixel size.
826     lf.lfHeight = -unitsPerEm;
827     lf.lfWidth = 0;
828     HFONT hf = CreateFontIndirect(&lf);
829     HDC hdc = m_fontEngineData->hdc;
830     HGDIOBJ oldfont = SelectObject(hdc, hf);
831 
832     qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
833     qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
834     for(int i = 0; i < nglyphs; ++i) {
835         if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
836                             scale, stretch)) {
837             // Some windows fonts, like "Modern", are vector stroke
838             // fonts, which are reported as TMPF_VECTOR but do not
839             // support GetGlyphOutline, and thus we set this bit so
840             // that addOutLineToPath can check it and return safely...
841             hasOutline = false;
842             break;
843         }
844     }
845     DeleteObject(SelectObject(hdc, oldfont));
846 }
847 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)848 void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
849                                       QPainterPath *path, QTextItem::RenderFlags flags)
850 {
851     if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
852         hasOutline = true;
853         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
854         if (hasOutline)  {
855             // has_outline is set to false if addGlyphToPath gets
856             // false from GetGlyphOutline, meaning its not an outline
857             // font.
858             return;
859         }
860     }
861     QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
862 }
863 
faceId() const864 QFontEngine::FaceId QWindowsFontEngine::faceId() const
865 {
866     return _faceId;
867 }
868 
869 QT_BEGIN_INCLUDE_NAMESPACE
870 #include <qdebug.h>
871 QT_END_INCLUDE_NAMESPACE
872 
synthesized() const873 int QWindowsFontEngine::synthesized() const
874 {
875     if(synthesized_flags == -1) {
876         synthesized_flags = 0;
877         if(ttf) {
878             const DWORD HEAD = MAKE_LITTLE_ENDIAN_TAG('h', 'e', 'a', 'd');
879             HDC hdc = m_fontEngineData->hdc;
880             SelectObject(hdc, hfont);
881             uchar data[4];
882             GetFontData(hdc, HEAD, 44, &data, 4);
883             USHORT macStyle = qt_getUShort(data);
884             if (tm.tmItalic && !(macStyle & 2))
885                 synthesized_flags = SynthesizedItalic;
886             if (fontDef.stretch != 100 && ttf)
887                 synthesized_flags |= SynthesizedStretch;
888             if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1))
889                 synthesized_flags |= SynthesizedBold;
890             //qDebug() << "font is" << _name <<
891             //    "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
892         }
893     }
894     return synthesized_flags;
895 }
896 
emSquareSize() const897 QFixed QWindowsFontEngine::emSquareSize() const
898 {
899     return unitsPerEm;
900 }
901 
properties() const902 QFontEngine::Properties QWindowsFontEngine::properties() const
903 {
904     LOGFONT lf = m_logfont;
905     lf.lfHeight = unitsPerEm;
906     HFONT hf = CreateFontIndirect(&lf);
907     HDC hdc = m_fontEngineData->hdc;
908     HGDIOBJ oldfont = SelectObject(hdc, hf);
909     OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
910     Properties p;
911     p.emSquare = unitsPerEm;
912     p.italicAngle = otm->otmItalicAngle;
913     const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1()
914         + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1();
915     p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name);
916     p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
917                            otm->otmrcFontBox.right - otm->otmrcFontBox.left,
918                            otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
919     p.ascent = otm->otmAscent;
920     p.descent = -otm->otmDescent;
921     p.leading = int(otm->otmLineGap);
922     p.capHeight = 0;
923     p.lineWidth = otm->otmsUnderscoreSize;
924     free(otm);
925     DeleteObject(SelectObject(hdc, oldfont));
926     return p;
927 }
928 
getUnscaledGlyph(glyph_t glyph,QPainterPath * path,glyph_metrics_t * metrics)929 void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
930 {
931     LOGFONT lf = m_logfont;
932     lf.lfHeight = -unitsPerEm;
933     int flags = synthesized();
934     if(flags & SynthesizedItalic)
935         lf.lfItalic = false;
936     lf.lfWidth = 0;
937     HFONT hf = CreateFontIndirect(&lf);
938     HDC hdc = m_fontEngineData->hdc;
939     HGDIOBJ oldfont = SelectObject(hdc, hf);
940     QFixedPoint p;
941     p.x = 0;
942     p.y = 0;
943     addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
944     DeleteObject(SelectObject(hdc, oldfont));
945 }
946 
getSfntTableData(uint tag,uchar * buffer,uint * length) const947 bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
948 {
949     if (!ttf && !cffTable)
950         return false;
951     HDC hdc = m_fontEngineData->hdc;
952     SelectObject(hdc, hfont);
953     DWORD t = qbswap<quint32>(tag);
954     *length = GetFontData(hdc, t, 0, buffer, *length);
955     Q_ASSERT(*length == GDI_ERROR || int(*length) > 0);
956     return *length != GDI_ERROR;
957 }
958 
959 #if !defined(CLEARTYPE_QUALITY)
960 #    define CLEARTYPE_QUALITY       5
961 #endif
962 
drawGDIGlyph(HFONT font,glyph_t glyph,int margin,const QTransform & t,QImage::Format mask_format)963 QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
964                                                   const QTransform &t,
965                                                   QImage::Format mask_format)
966 {
967     Q_UNUSED(mask_format)
968     glyph_metrics_t gm = boundingBox(glyph);
969 
970 //     printf(" -> for glyph %4x\n", glyph);
971 
972     int gx = gm.x.toInt();
973     int gy = gm.y.toInt();
974     int iw = gm.width.toInt();
975     int ih = gm.height.toInt();
976 
977     if (iw <= 0 || ih <= 0)
978         return 0;
979 
980     bool has_transformation = t.type() > QTransform::TxTranslate;
981 
982     unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
983     XFORM xform;
984 
985     if (has_transformation) {
986         xform.eM11 = FLOAT(t.m11());
987         xform.eM12 = FLOAT(t.m12());
988         xform.eM21 = FLOAT(t.m21());
989         xform.eM22 = FLOAT(t.m22());
990         xform.eDx = margin;
991         xform.eDy = margin;
992 
993         const HDC hdc = m_fontEngineData->hdc;
994 
995         SetGraphicsMode(hdc, GM_ADVANCED);
996         SetWorldTransform(hdc, &xform);
997         HGDIOBJ old_font = SelectObject(hdc, font);
998 
999         const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
1000         GLYPHMETRICS tgm;
1001         MAT2 mat;
1002         memset(&mat, 0, sizeof(mat));
1003         mat.eM11.value = mat.eM22.value = 1;
1004 
1005         const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat);
1006 
1007         XFORM identity = {1, 0, 0, 1, 0, 0};
1008         SetWorldTransform(hdc, &identity);
1009         SetGraphicsMode(hdc, GM_COMPATIBLE);
1010         SelectObject(hdc, old_font);
1011 
1012         if (result == GDI_ERROR) {
1013             const int errorCode = int(GetLastError());
1014             qErrnoWarning(errorCode, "QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode);
1015             return 0;
1016         }
1017 
1018         iw = int(tgm.gmBlackBoxX);
1019         ih = int(tgm.gmBlackBoxY);
1020 
1021         xform.eDx -= tgm.gmptGlyphOrigin.x;
1022         xform.eDy += tgm.gmptGlyphOrigin.y;
1023     }
1024 
1025     // The padding here needs to be kept in sync with the values in alphaMapBoundingBox.
1026     QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin,
1027                                                       ih + 2 * margin,
1028                                                       QWindowsNativeImage::systemFormat());
1029 
1030     /*If cleartype is enabled we use the standard system format even on Windows CE
1031       and not the special textbuffer format we have to use if cleartype is disabled*/
1032 
1033     ni->image().fill(0xffffffff);
1034 
1035     HDC hdc = ni->hdc();
1036 
1037     SelectObject(hdc, GetStockObject(NULL_BRUSH));
1038     SelectObject(hdc, GetStockObject(BLACK_PEN));
1039     SetTextColor(hdc, RGB(0,0,0));
1040     SetBkMode(hdc, TRANSPARENT);
1041     SetTextAlign(hdc, TA_BASELINE);
1042 
1043     HGDIOBJ old_font = SelectObject(hdc, font);
1044 
1045     if (has_transformation) {
1046         SetGraphicsMode(hdc, GM_ADVANCED);
1047         SetWorldTransform(hdc, &xform);
1048         ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
1049     } else {
1050         ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
1051     }
1052 
1053     SelectObject(hdc, old_font);
1054     return ni;
1055 }
1056 
alphaMapBoundingBox(glyph_t glyph,QFixed,const QTransform & matrix,GlyphFormat format)1057 glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format)
1058 {
1059     int margin = 0;
1060     if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB)
1061         margin = glyphMargin(QFontEngine::Format_A32);
1062     glyph_metrics_t gm = boundingBox(glyph, matrix);
1063     gm.width += margin * 2;
1064     gm.height += margin * 2;
1065     return gm;
1066 }
1067 
alphaMapForGlyph(glyph_t glyph,const QTransform & xform)1068 QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
1069 {
1070     HFONT font = hfont;
1071 
1072     bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY);
1073     if (clearTypeTemporarilyDisabled) {
1074         LOGFONT lf = m_logfont;
1075         lf.lfQuality = ANTIALIASED_QUALITY;
1076         font = CreateFontIndirect(&lf);
1077     }
1078     QImage::Format mask_format = QWindowsNativeImage::systemFormat();
1079     mask_format = QImage::Format_RGB32;
1080 
1081     const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1082     if (mask == 0) {
1083         if (m_fontEngineData->clearTypeEnabled)
1084             DeleteObject(font);
1085         return QImage();
1086     }
1087 
1088     QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8);
1089 
1090 
1091     // Copy data... Cannot use QPainter here as GDI has messed up the
1092     // Alpha channel of the ni.image pixels...
1093     for (int y=0; y<mask->height(); ++y) {
1094         uchar *dest = alphaMap.scanLine(y);
1095         if (mask->image().format() == QImage::Format_RGB16) {
1096             const qint16 *src = reinterpret_cast<const qint16 *>(mask->image().constScanLine(y));
1097             for (int x=0; x<mask->width(); ++x)
1098                 dest[x] = 255 - qGray(src[x]);
1099         } else {
1100             const uint *src = reinterpret_cast<const uint *>(mask->image().constScanLine(y));
1101             for (int x=0; x<mask->width(); ++x) {
1102                 if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
1103                     dest[x] = 255 - qGray(src[x]);
1104                 else
1105                     dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1106             }
1107         }
1108     }
1109 
1110     // Cleanup...
1111     delete mask;
1112     if (clearTypeTemporarilyDisabled) {
1113         DeleteObject(font);
1114     }
1115 
1116     return alphaMap;
1117 }
1118 
1119 #define SPI_GETFONTSMOOTHINGCONTRAST           0x200C
1120 #define SPI_SETFONTSMOOTHINGCONTRAST           0x200D
1121 
alphaRGBMapForGlyph(glyph_t glyph,QFixed,const QTransform & t)1122 QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t)
1123 {
1124     HFONT font = hfont;
1125 
1126     UINT contrast;
1127     SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1128     SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(1000)), 0);
1129 
1130     int margin = glyphMargin(QFontEngine::Format_A32);
1131     QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1132     SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(contrast)), 0);
1133 
1134     if (mask == 0)
1135         return QImage();
1136 
1137     // Gracefully handle the odd case when the display is 16-bit
1138     const QImage source = mask->image().depth() == 32
1139                           ? mask->image()
1140                           : mask->image().convertToFormat(QImage::Format_RGB32);
1141 
1142     QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1143     for (int y=0; y<mask->height(); ++y) {
1144         auto dest = reinterpret_cast<uint *>(rgbMask.scanLine(y));
1145         const uint *src = reinterpret_cast<const uint *>(source.constScanLine(y));
1146         for (int x=0; x<mask->width(); ++x) {
1147             dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1148         }
1149     }
1150 
1151     delete mask;
1152 
1153     return rgbMask;
1154 }
1155 
cloneWithSize(qreal pixelSize) const1156 QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
1157 {
1158     QFontDef request = fontDef;
1159     QString actualFontName = request.family;
1160     if (!uniqueFamilyName.isEmpty())
1161         request.family = uniqueFamilyName;
1162     request.pixelSize = pixelSize;
1163     const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName);
1164 
1165     QFontEngine *fontEngine =
1166         QWindowsFontDatabase::createEngine(request, faceName,
1167                                            QWindowsFontDatabase::defaultVerticalDPI(),
1168                                            m_fontEngineData);
1169     if (fontEngine) {
1170         fontEngine->fontDef.family = actualFontName;
1171         if (!uniqueFamilyName.isEmpty()) {
1172             static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1173             if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
1174                 QPlatformFontDatabase *pfdb = pi->fontDatabase();
1175                 static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1176             }
1177         }
1178     }
1179     return fontEngine;
1180 }
1181 
handle() const1182 Qt::HANDLE QWindowsFontEngine::handle() const
1183 {
1184     return hfont;
1185 }
1186 
initFontInfo(const QFontDef & request,int dpi)1187 void QWindowsFontEngine::initFontInfo(const QFontDef &request,
1188                                       int dpi)
1189 {
1190     fontDef = request; // most settings are equal
1191     HDC dc = m_fontEngineData->hdc;
1192     SelectObject(dc, hfont);
1193     wchar_t n[64];
1194     GetTextFace(dc, 64, n);
1195     fontDef.family = QString::fromWCharArray(n);
1196     fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1197     if (fontDef.pointSize < 0) {
1198         fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1199     } else if (fontDef.pixelSize == -1) {
1200         fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1201     }
1202 }
1203 
supportsTransformation(const QTransform & transform) const1204 bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const
1205 {
1206     // Support all transformations for ttf files, and translations for raster fonts
1207     return ttf || transform.type() <= QTransform::TxTranslate;
1208 }
1209 
1210 QT_END_NAMESPACE
1211