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