Fix font printing on Windows using the native engine.
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowsfontengine.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #if _WIN32_WINNT < 0x0500
43 #undef _WIN32_WINNT
44 #define _WIN32_WINNT 0x0500
45 #endif
46
47 #include "qwindowsintegration.h"
48 #include "qwindowsfontengine.h"
49 #include "qwindowsnativeimage.h"
50 #include "qwindowscontext.h"
51 #include "qwindowsfontdatabase.h"
52 #include "qtwindows_additional.h"
53
54 #include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
55 #include <QtGui/private/qguiapplication_p.h>
56 #include <QtGui/QPaintDevice>
57 #include <QtGui/QBitmap>
58 #include <QtGui/QPainter>
59 #include <QtGui/private/qpainter_p.h>
60 #include <QtGui/QPaintEngine>
61 #include <QtGui/private/qpaintengine_raster_p.h>
62
63 #include <QtCore/QtEndian>
64 #include <QtCore/qmath.h>
65 #include <QtCore/QThreadStorage>
66 #include <QtCore/private/qsystemlibrary_p.h>
67
68 #include <QtCore/private/qunicodetables_p.h>
69 #include <QtCore/QDebug>
70
71 #include <limits.h>
72
73 #ifdef Q_OS_WINCE
74 #  include "qplatformfunctions_wince.h"
75 #endif
76
77 QT_BEGIN_NAMESPACE
78
79 //### mingw needed define
80 #ifndef TT_PRIM_CSPLINE
81 #define TT_PRIM_CSPLINE 3
82 #endif
83
84 #ifdef MAKE_TAG
85 #undef MAKE_TAG
86 #endif
87 // GetFontData expects the tags in little endian ;(
88 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
89     (((quint32)(ch4)) << 24) | \
90     (((quint32)(ch3)) << 16) | \
91     (((quint32)(ch2)) << 8) | \
92     ((quint32)(ch1)) \
93    )
94
95 // common DC for all fonts
96
97 typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
98 static PtrGetCharWidthI ptrGetCharWidthI = 0;
99 static bool resolvedGetCharWidthI = false;
100
101 static void resolveGetCharWidthI()
102 {
103     if (resolvedGetCharWidthI)
104         return;
105     resolvedGetCharWidthI = true;
106     ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI");
107 }
108
109 // defined in qtextengine_win.cpp
110 typedef void *SCRIPT_CACHE;
111 typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
112 extern fScriptFreeCache ScriptFreeCache;
113
114 static inline quint32 getUInt(unsigned char *p)
115 {
116     quint32 val;
117     val = *p++ << 24;
118     val |= *p++ << 16;
119     val |= *p++ << 8;
120     val |= *p;
121
122     return val;
123 }
124
125 static inline quint16 getUShort(unsigned char *p)
126 {
127     quint16 val;
128     val = *p++ << 8;
129     val |= *p;
130
131     return val;
132 }
133
134 // general font engine
135
136 QFixed QWindowsFontEngine::lineThickness() const
137 {
138     if(lineWidth > 0)
139         return lineWidth;
140
141     return QFontEngine::lineThickness();
142 }
143
144 static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
145 {
146     int size;
147     size = GetOutlineTextMetrics(hdc, 0, 0);
148     OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
149     GetOutlineTextMetrics(hdc, size, otm);
150     return otm;
151 }
152
153 void QWindowsFontEngine::getCMap()
154 {
155     ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
156     HDC hdc = m_fontEngineData->hdc;
157     SelectObject(hdc, hfont);
158     bool symb = false;
159     if (ttf) {
160         cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
161         int size = 0;
162         cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
163                        cmapTable.size(), &symb, &size);
164     }
165     if (!cmap) {
166         ttf = false;
167         symb = false;
168     }
169     symbol = symb;
170     designToDevice = 1;
171     _faceId.index = 0;
172     if(cmap) {
173         OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
174         designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
175         unitsPerEm = otm->otmEMSquare;
176         x_height = (int)otm->otmsXHeight;
177         loadKerningPairs(designToDevice);
178         _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
179         lineWidth = otm->otmsUnderscoreSize;
180         fsType = otm->otmfsType;
181         free(otm);
182     } else {
183         unitsPerEm = tm.tmHeight;
184     }
185 }
186
187 // ### Qt 5.1: replace with QStringIterator
188 inline unsigned int getChar(const QChar *str, int &i, const int len)
189 {
190     uint uc = str[i].unicode();
191     if (QChar::isHighSurrogate(uc) && i < len-1) {
192         uint low = str[i+1].unicode();
193         if (QChar::isLowSurrogate(low)) {
194             uc = QChar::surrogateToUcs4(uc, low);
195             ++i;
196         }
197     }
198     return uc;
199 }
200
201 int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
202 {
203     int i = 0;
204     int glyph_pos = 0;
205     if (mirrored) {
206 #if defined(Q_OS_WINCE)
207         {
208 #else
209         if (symbol) {
210             for (; i < numChars; ++i, ++glyph_pos) {
211                 unsigned int uc = getChar(str, i, numChars);
212                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
213                 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
214                     glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
215             }
216         } else if (ttf) {
217             for (; i < numChars; ++i, ++glyph_pos) {
218                 unsigned int uc = getChar(str, i, numChars);
219                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
220             }
221         } else {
222 #endif
223             wchar_t first = tm.tmFirstChar;
224             wchar_t last = tm.tmLastChar;
225
226             for (; i < numChars; ++i, ++glyph_pos) {
227                 uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
228                 if (
229 #ifdef Q_WS_WINCE
230                     tm.tmFirstChar > 60000 ||
231 #endif
232                          ucs >= first && ucs <= last)
233                     glyphs->glyphs[glyph_pos] = ucs;
234                 else
235                     glyphs->glyphs[glyph_pos] = 0;
236             }
237         }
238     } else {
239 #if defined(Q_OS_WINCE)
240         {
241 #else
242         if (symbol) {
243             for (; i < numChars; ++i, ++glyph_pos) {
244                 unsigned int uc = getChar(str, i, numChars);
245                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
246                 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
247                     glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
248             }
249         } else if (ttf) {
250             for (; i < numChars; ++i, ++glyph_pos) {
251                 unsigned int uc = getChar(str, i, numChars);
252                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
253             }
254         } else {
255 #endif
256             wchar_t first = tm.tmFirstChar;
257             wchar_t last = tm.tmLastChar;
258
259             for (; i < numChars; ++i, ++glyph_pos) {
260                 uint uc = getChar(str, i, numChars);
261                 if (
262 #ifdef Q_WS_WINCE
263                     tm.tmFirstChar > 60000 ||
264 #endif
265                          uc >= first && uc <= last)
266                     glyphs->glyphs[glyph_pos] = uc;
267                 else
268                     glyphs->glyphs[glyph_pos] = 0;
269             }
270         }
271     }
272     glyphs->numGlyphs = glyph_pos;
273     return glyph_pos;
274 }
275
276 /*!
277     \class QWindowsFontEngine
278     \brief Standard Windows font engine.
279     \ingroup qt-lighthouse-win
280
281     Will probably be superseded by a common Free Type font engine in Qt 5.X.
282 */
283
284 QWindowsFontEngine::QWindowsFontEngine(const QString &name,
285                                HFONT _hfont, bool stockFontIn, LOGFONT lf,
286                                const QSharedPointer<QWindowsFontEngineData> &fontEngineData) :
287     m_fontEngineData(fontEngineData),
288     _name(name),
289     hfont(_hfont),
290     m_logfont(lf),
291     stockFont(stockFontIn),
292     ttf(0),
293     hasOutline(0),
294     lw(0),
295     cmap(0),
296     lbearing(SHRT_MIN),
297     rbearing(SHRT_MIN),
298     x_height(-1),
299     synthesized_flags(-1),
300     lineWidth(-1),
301     widthCache(0),
302     widthCacheSize(0),
303     designAdvances(0),
304     designAdvancesSize(0)
305 {
306     if (QWindowsContext::verboseFonts)
307         qDebug("%s: font='%s', size=%ld", __FUNCTION__, qPrintable(name), lf.lfHeight);
308     HDC hdc = m_fontEngineData->hdc;
309     SelectObject(hdc, hfont);
310     fontDef.pixelSize = -lf.lfHeight;
311     const BOOL res = GetTextMetrics(hdc, &tm);
312     fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
313     if (!res) {
314         qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
315         ZeroMemory(&tm, sizeof(TEXTMETRIC));
316     }
317
318     cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
319     getCMap();
320
321     if (!resolvedGetCharWidthI)
322         resolveGetCharWidthI();
323 }
324
325 QWindowsFontEngine::~QWindowsFontEngine()
326 {
327     if (designAdvances)
328         free(designAdvances);
329
330     if (widthCache)
331         free(widthCache);
332
333     // make sure we aren't by accident still selected
334     SelectObject(m_fontEngineData->hdc, (HFONT)GetStockObject(SYSTEM_FONT));
335
336     if (!stockFont) {
337         if (!DeleteObject(hfont))
338             qErrnoWarning("%s: QFontEngineWin: failed to delete non-stock font... failed", __FUNCTION__);
339     }
340     if (QWindowsContext::verboseFonts)
341         if (QWindowsContext::verboseFonts)
342             qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name));
343
344     if (!uniqueFamilyName.isEmpty()) {
345         QPlatformFontDatabase *pfdb = QWindowsIntegration::instance()->fontDatabase();
346         static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
347     }
348 }
349
350 HGDIOBJ QWindowsFontEngine::selectDesignFont() const
351 {
352     LOGFONT f = m_logfont;
353     f.lfHeight = unitsPerEm;
354     HFONT designFont = CreateFontIndirect(&f);
355     return SelectObject(m_fontEngineData->hdc, designFont);
356 }
357
358 bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
359 {
360     if (*nglyphs < len) {
361         *nglyphs = len;
362         return false;
363     }
364
365     *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
366
367     if (flags & QTextEngine::GlyphIndicesOnly)
368         return true;
369
370     recalcAdvances(glyphs, flags);
371     return true;
372 }
373
374 inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
375 {
376 #if defined(Q_OS_WINCE)
377     GetCharWidth32(hdc, glyph, glyph, &width);
378 #else
379     if (ptrGetCharWidthI)
380         ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
381 #endif
382 }
383
384 void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
385 {
386     HGDIOBJ oldFont = 0;
387     HDC hdc = m_fontEngineData->hdc;
388     if (ttf && (flags & QTextEngine::DesignMetrics)) {
389         for(int i = 0; i < glyphs->numGlyphs; i++) {
390             unsigned int glyph = glyphs->glyphs[i];
391             if(int(glyph) >= designAdvancesSize) {
392                 int newSize = (glyph + 256) >> 8 << 8;
393                 designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
394                             newSize*sizeof(QFixed)));
395                 for(int i = designAdvancesSize; i < newSize; ++i)
396                     designAdvances[i] = -1000000;
397                 designAdvancesSize = newSize;
398             }
399             if (designAdvances[glyph] < -999999) {
400                 if (!oldFont)
401                     oldFont = selectDesignFont();
402
403                 int width = 0;
404                 calculateTTFGlyphWidth(hdc, glyph, width);
405                 designAdvances[glyph] = QFixed(width) / designToDevice;
406             }
407             glyphs->advances_x[i] = designAdvances[glyph];
408             glyphs->advances_y[i] = 0;
409         }
410         if(oldFont)
411             DeleteObject(SelectObject(hdc, oldFont));
412     } else {
413         for(int i = 0; i < glyphs->numGlyphs; i++) {
414             unsigned int glyph = glyphs->glyphs[i];
415
416             glyphs->advances_y[i] = 0;
417
418             if (glyph >= widthCacheSize) {
419                 int newSize = (glyph + 256) >> 8 << 8;
420                 widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
421                             newSize*sizeof(QFixed)));
422                 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
423                 widthCacheSize = newSize;
424             }
425             glyphs->advances_x[i] = widthCache[glyph];
426             // font-width cache failed
427             if (glyphs->advances_x[i] == 0) {
428                 int width = 0;
429                 if (!oldFont)
430                     oldFont = SelectObject(hdc, hfont);
431
432                 if (!ttf) {
433                     QChar ch[2] = { ushort(glyph), 0 };
434                     int chrLen = 1;
435                     if (QChar::requiresSurrogates(glyph)) {
436                         ch[0] = QChar::highSurrogate(glyph);
437                         ch[1] = QChar::lowSurrogate(glyph);
438                         ++chrLen;
439                     }
440                     SIZE size = {0, 0};
441                     GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
442                     width = size.cx;
443                 } else {
444                     calculateTTFGlyphWidth(hdc, glyph, width);
445                 }
446                 glyphs->advances_x[i] = width;
447                 // if glyph's within cache range, store it for later
448                 if (width > 0 && width < 0x100)
449                     widthCache[glyph] = width;
450             }
451         }
452
453         if (oldFont)
454             SelectObject(hdc, oldFont);
455     }
456 }
457
458 glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs)
459 {
460     if (glyphs.numGlyphs == 0)
461         return glyph_metrics_t();
462
463     QFixed w = 0;
464     for (int i = 0; i < glyphs.numGlyphs; ++i)
465         w += glyphs.effectiveAdvance(i);
466
467     return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
468 }
469 #ifndef Q_OS_WINCE
470 bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
471 {
472     Q_ASSERT(metrics != 0);
473
474     HDC hdc = m_fontEngineData->hdc;
475
476     GLYPHMETRICS gm;
477     DWORD res = 0;
478     MAT2 mat;
479     mat.eM11.value = mat.eM22.value = 1;
480     mat.eM11.fract = mat.eM22.fract = 0;
481     mat.eM21.value = mat.eM12.value = 0;
482     mat.eM21.fract = mat.eM12.fract = 0;
483
484     if (t.type() > QTransform::TxTranslate) {
485         // We need to set the transform using the HDC's world
486         // matrix rather than using the MAT2 above, because the
487         // results provided when transforming via MAT2 does not
488         // match the glyphs that are drawn using a WorldTransform
489         XFORM xform;
490         xform.eM11 = t.m11();
491         xform.eM12 = t.m12();
492         xform.eM21 = t.m21();
493         xform.eM22 = t.m22();
494         xform.eDx = 0;
495         xform.eDy = 0;
496         SetGraphicsMode(hdc, GM_ADVANCED);
497         SetWorldTransform(hdc, &xform);
498     }
499
500     uint format = GGO_METRICS;
501     if (ttf)
502         format |= GGO_GLYPH_INDEX;
503     res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
504
505     if (t.type() > QTransform::TxTranslate) {
506         XFORM xform;
507         xform.eM11 = xform.eM22 = 1;
508         xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
509         SetWorldTransform(hdc, &xform);
510         SetGraphicsMode(hdc, GM_COMPATIBLE);
511     }
512
513     if (res != GDI_ERROR) {
514         *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
515                                   (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
516         return true;
517     } else {
518         return false;
519     }
520 }
521 #endif
522
523 glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t)
524 {
525 #ifndef Q_OS_WINCE
526     HDC hdc = m_fontEngineData->hdc;
527     SelectObject(hdc, hfont);
528
529     glyph_metrics_t glyphMetrics;
530     bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
531
532     if (!ttf && !success) {
533         // Bitmap fonts
534         wchar_t ch = glyph;
535         ABCFLOAT abc;
536         GetCharABCWidthsFloat(hdc, ch, ch, &abc);
537         int width = qRound(abc.abcfB);
538
539         return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
540     }
541
542     return glyphMetrics;
543 #else
544     HDC hdc = m_fontEngineData->hdc;
545     HGDIOBJ oldFont = SelectObject(hdc, hfont);
546
547     ABC abc;
548     int width;
549     int advance;
550 #ifdef GWES_MGTT    // true type fonts
551     if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
552         width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
553         advance = abc.abcA + abc.abcB + abc.abcC;
554     }
555     else
556 #endif
557 #if defined(GWES_MGRAST) || defined(GWES_MGRAST2)   // raster fonts
558     if (GetCharWidth32(hdc, glyph, glyph, &width)) {
559         advance = width;
560     }
561     else
562 #endif
563     {   // fallback
564         width = tm.tmMaxCharWidth;
565         advance = width;
566     }
567
568     SelectObject(hdc, oldFont);
569     return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
570 #endif
571 }
572
573 QFixed QWindowsFontEngine::ascent() const
574 {
575     return tm.tmAscent;
576 }
577
578 QFixed QWindowsFontEngine::descent() const
579 {
580     return tm.tmDescent;
581 }
582
583 QFixed QWindowsFontEngine::leading() const
584 {
585     return tm.tmExternalLeading;
586 }
587
588
589 QFixed QWindowsFontEngine::xHeight() const
590 {
591     if(x_height >= 0)
592         return x_height;
593     return QFontEngine::xHeight();
594 }
595
596 QFixed QWindowsFontEngine::averageCharWidth() const
597 {
598     return tm.tmAveCharWidth;
599 }
600
601 qreal QWindowsFontEngine::maxCharWidth() const
602 {
603     return tm.tmMaxCharWidth;
604 }
605
606 enum { max_font_count = 256 };
607 static const ushort char_table[] = {
608         40,
609         67,
610         70,
611         75,
612         86,
613         88,
614         89,
615         91,
616         102,
617         114,
618         124,
619         127,
620         205,
621         645,
622         884,
623         922,
624         1070,
625         12386,
626         0
627 };
628
629 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
630
631 #ifndef Q_CC_MINGW
632 void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
633 {
634     HDC hdc = m_fontEngineData->hdc;
635     SelectObject(hdc, hfont);
636
637 #ifndef Q_OS_WINCE
638     if (ttf)
639 #endif
640     {
641         ABC abcWidths;
642         GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
643         if (leftBearing)
644             *leftBearing = abcWidths.abcA;
645         if (rightBearing)
646             *rightBearing = abcWidths.abcC;
647     }
648 #ifndef Q_OS_WINCE
649     else {
650         QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
651     }
652 #endif
653 }
654 #endif // Q_CC_MINGW
655
656 qreal QWindowsFontEngine::minLeftBearing() const
657 {
658     if (lbearing == SHRT_MIN)
659         minRightBearing(); // calculates both
660
661     return lbearing;
662 }
663
664 qreal QWindowsFontEngine::minRightBearing() const
665 {
666 #ifndef Q_OS_WINCE
667     if (rbearing == SHRT_MIN) {
668         int ml = 0;
669         int mr = 0;
670         HDC hdc = m_fontEngineData->hdc;
671         SelectObject(hdc, hfont);
672         if (ttf) {
673             ABC *abc = 0;
674             int n = tm.tmLastChar - tm.tmFirstChar;
675             if (n <= max_font_count) {
676                 abc = new ABC[n+1];
677                 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
678             } else {
679                 abc = new ABC[char_table_entries+1];
680                 for(int i = 0; i < char_table_entries; i++)
681                     GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
682                 n = char_table_entries;
683             }
684             ml = abc[0].abcA;
685             mr = abc[0].abcC;
686             for (int i = 1; i < n; i++) {
687                 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
688                     ml = qMin(ml,abc[i].abcA);
689                     mr = qMin(mr,abc[i].abcC);
690                 }
691             }
692             delete [] abc;
693         } else {
694             ABCFLOAT *abc = 0;
695             int n = tm.tmLastChar - tm.tmFirstChar+1;
696             if (n <= max_font_count) {
697                 abc = new ABCFLOAT[n];
698                 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
699             } else {
700                 abc = new ABCFLOAT[char_table_entries];
701                 for(int i = 0; i < char_table_entries; i++)
702                     GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
703                 n = char_table_entries;
704             }
705             float fml = abc[0].abcfA;
706             float fmr = abc[0].abcfC;
707             for (int i=1; i<n; i++) {
708                 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
709                     fml = qMin(fml,abc[i].abcfA);
710                     fmr = qMin(fmr,abc[i].abcfC);
711                 }
712             }
713             ml = int(fml - 0.9999);
714             mr = int(fmr - 0.9999);
715             delete [] abc;
716         }
717         lbearing = ml;
718         rbearing = mr;
719     }
720
721     return rbearing;
722 #else // !Q_OS_WINCE
723     if (rbearing == SHRT_MIN) {
724         int ml = 0;
725         int mr = 0;
726         HDC hdc = m_fontEngineData->hdc;
727         SelectObject(hdc, hfont);
728         if (ttf) {
729             ABC *abc = 0;
730             int n = tm.tmLastChar - tm.tmFirstChar;
731             if (n <= max_font_count) {
732                 abc = new ABC[n+1];
733                 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
734             } else {
735                 abc = new ABC[char_table_entries+1];
736                 for (int i = 0; i < char_table_entries; i++)
737                     GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
738                 n = char_table_entries;
739             }
740             ml = abc[0].abcA;
741             mr = abc[0].abcC;
742             for (int i = 1; i < n; i++) {
743                 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
744                     ml = qMin(ml,abc[i].abcA);
745                     mr = qMin(mr,abc[i].abcC);
746                 }
747             }
748             delete [] abc;
749         }
750         lbearing = ml;
751         rbearing = mr;
752     }
753
754     return rbearing;
755 #endif // Q_OS_WINCE
756 }
757
758
759 const char *QWindowsFontEngine::name() const
760 {
761     return 0;
762 }
763
764 bool QWindowsFontEngine::canRender(const QChar *string,  int len)
765 {
766     if (symbol) {
767         for (int i = 0; i < len; ++i) {
768             unsigned int uc = getChar(string, i, len);
769             if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
770                 if (uc < 0x100) {
771                     if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
772                         return false;
773                 } else {
774                     return false;
775                 }
776             }
777         }
778     } else if (ttf) {
779         for (int i = 0; i < len; ++i) {
780             unsigned int uc = getChar(string, i, len);
781             if (getTrueTypeGlyphIndex(cmap, uc) == 0)
782                 return false;
783         }
784     } else {
785         while(len--) {
786             if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
787                 return false;
788         }
789     }
790     return true;
791 }
792
793 QFontEngine::Type QWindowsFontEngine::type() const
794 {
795     return QFontEngine::Win;
796 }
797
798 static inline double qt_fixed_to_double(const FIXED &p) {
799     return ((p.value << 16) + p.fract) / 65536.0;
800 }
801
802 static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
803     return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
804 }
805
806 #ifndef GGO_UNHINTED
807 #define GGO_UNHINTED 0x0100
808 #endif
809
810 static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
811                            QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
812 {
813     MAT2 mat;
814     mat.eM11.value = mat.eM22.value = 1;
815     mat.eM11.fract = mat.eM22.fract = 0;
816     mat.eM21.value = mat.eM12.value = 0;
817     mat.eM21.fract = mat.eM12.fract = 0;
818     uint glyphFormat = GGO_NATIVE;
819
820     if (ttf)
821         glyphFormat |= GGO_GLYPH_INDEX;
822
823     GLYPHMETRICS gMetric;
824     memset(&gMetric, 0, sizeof(GLYPHMETRICS));
825     int bufferSize = GDI_ERROR;
826     bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
827     if ((DWORD)bufferSize == GDI_ERROR) {
828         return false;
829     }
830
831     void *dataBuffer = new char[bufferSize];
832     DWORD ret = GDI_ERROR;
833     ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
834     if (ret == GDI_ERROR) {
835         delete [](char *)dataBuffer;
836         return false;
837     }
838
839     if(metric) {
840         // #### obey scale
841         *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
842                                   (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
843                                   gMetric.gmCellIncX, gMetric.gmCellIncY);
844     }
845
846     int offset = 0;
847     int headerOffset = 0;
848     TTPOLYGONHEADER *ttph = 0;
849
850     QPointF oset = position.toPointF();
851     while (headerOffset < bufferSize) {
852         ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
853
854         QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
855         path->moveTo(lastPoint + oset);
856         offset += sizeof(TTPOLYGONHEADER);
857         TTPOLYCURVE *curve;
858         while (offset<int(headerOffset + ttph->cb)) {
859             curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
860             switch (curve->wType) {
861             case TT_PRIM_LINE: {
862                 for (int i=0; i<curve->cpfx; ++i) {
863                     QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
864                     path->lineTo(p);
865                 }
866                 break;
867             }
868             case TT_PRIM_QSPLINE: {
869                 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
870                 QPointF prev(elm.x, elm.y);
871                 QPointF endPoint;
872                 for (int i=0; i<curve->cpfx - 1; ++i) {
873                     QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
874                     QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
875                     if (i < curve->cpfx - 2) {
876                         endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
877                     } else {
878                         endPoint = p2;
879                     }
880
881                     path->quadTo(p1, endPoint);
882                     prev = endPoint;
883                 }
884
885                 break;
886             }
887             case TT_PRIM_CSPLINE: {
888                 for (int i=0; i<curve->cpfx; ) {
889                     QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
890                     QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
891                     QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
892                     path->cubicTo(p2, p3, p4);
893                 }
894                 break;
895             }
896             default:
897                 qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
898             }
899             offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
900         }
901         path->closeSubpath();
902         headerOffset += ttph->cb;
903     }
904     delete [] (char*)dataBuffer;
905
906     return true;
907 }
908
909 void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
910                                      QPainterPath *path, QTextItem::RenderFlags)
911 {
912     LOGFONT lf = m_logfont;
913     // The sign must be negative here to make sure we match against character height instead of
914     // hinted cell height. This ensures that we get linear matching, and we need this for
915     // paths since we later on apply a scaling transform to the glyph outline to get the
916     // font at the correct pixel size.
917     lf.lfHeight = -unitsPerEm;
918     lf.lfWidth = 0;
919     HFONT hf = CreateFontIndirect(&lf);
920     HDC hdc = m_fontEngineData->hdc;
921     HGDIOBJ oldfont = SelectObject(hdc, hf);
922
923     for(int i = 0; i < nglyphs; ++i) {
924         if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
925                             qreal(fontDef.pixelSize) / unitsPerEm)) {
926             // Some windows fonts, like "Modern", are vector stroke
927             // fonts, which are reported as TMPF_VECTOR but do not
928             // support GetGlyphOutline, and thus we set this bit so
929             // that addOutLineToPath can check it and return safely...
930             hasOutline = false;
931             break;
932         }
933     }
934     DeleteObject(SelectObject(hdc, oldfont));
935 }
936
937 void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
938                                       QPainterPath *path, QTextItem::RenderFlags flags)
939 {
940     if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
941         hasOutline = true;
942         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
943         if (hasOutline)  {
944             // has_outline is set to false if addGlyphToPath gets
945             // false from GetGlyphOutline, meaning its not an outline
946             // font.
947             return;
948         }
949     }
950     QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
951 }
952
953 QFontEngine::FaceId QWindowsFontEngine::faceId() const
954 {
955     return _faceId;
956 }
957
958 QT_BEGIN_INCLUDE_NAMESPACE
959 #include <qdebug.h>
960 QT_END_INCLUDE_NAMESPACE
961
962 int QWindowsFontEngine::synthesized() const
963 {
964     if(synthesized_flags == -1) {
965         synthesized_flags = 0;
966         if(ttf) {
967             const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
968             HDC hdc = m_fontEngineData->hdc;
969             SelectObject(hdc, hfont);
970             uchar data[4];
971             GetFontData(hdc, HEAD, 44, &data, 4);
972             USHORT macStyle = getUShort(data);
973             if (tm.tmItalic && !(macStyle & 2))
974                 synthesized_flags = SynthesizedItalic;
975             if (fontDef.stretch != 100 && ttf)
976                 synthesized_flags |= SynthesizedStretch;
977             if (tm.tmWeight >= 500 && !(macStyle & 1))
978                 synthesized_flags |= SynthesizedBold;
979             //qDebug() << "font is" << _name <<
980             //    "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
981         }
982     }
983     return synthesized_flags;
984 }
985
986 QFixed QWindowsFontEngine::emSquareSize() const
987 {
988     return unitsPerEm;
989 }
990
991 QFontEngine::Properties QWindowsFontEngine::properties() const
992 {
993     LOGFONT lf = m_logfont;
994     lf.lfHeight = unitsPerEm;
995     HFONT hf = CreateFontIndirect(&lf);
996     HDC hdc = m_fontEngineData->hdc;
997     HGDIOBJ oldfont = SelectObject(hdc, hf);
998     OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
999     Properties p;
1000     p.emSquare = unitsPerEm;
1001     p.italicAngle = otm->otmItalicAngle;
1002     p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
1003     p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
1004     p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
1005     p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
1006                            otm->otmrcFontBox.right - otm->otmrcFontBox.left,
1007                            otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
1008     p.ascent = otm->otmAscent;
1009     p.descent = -otm->otmDescent;
1010     p.leading = (int)otm->otmLineGap;
1011     p.capHeight = 0;
1012     p.lineWidth = otm->otmsUnderscoreSize;
1013     free(otm);
1014     DeleteObject(SelectObject(hdc, oldfont));
1015     return p;
1016 }
1017
1018 void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1019 {
1020     LOGFONT lf = m_logfont;
1021     lf.lfHeight = unitsPerEm;
1022     int flags = synthesized();
1023     if(flags & SynthesizedItalic)
1024         lf.lfItalic = false;
1025     lf.lfWidth = 0;
1026     HFONT hf = CreateFontIndirect(&lf);
1027     HDC hdc = m_fontEngineData->hdc;
1028     HGDIOBJ oldfont = SelectObject(hdc, hf);
1029     QFixedPoint p;
1030     p.x = 0;
1031     p.y = 0;
1032     addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
1033     DeleteObject(SelectObject(hdc, oldfont));
1034 }
1035
1036 bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1037 {
1038     if (!ttf)
1039         return false;
1040     HDC hdc = m_fontEngineData->hdc;
1041     SelectObject(hdc, hfont);
1042     DWORD t = qbswap<quint32>(tag);
1043     *length = GetFontData(hdc, t, 0, buffer, *length);
1044     return *length != GDI_ERROR;
1045 }
1046
1047 #if !defined(CLEARTYPE_QUALITY)
1048 #    define CLEARTYPE_QUALITY       5
1049 #endif
1050
1051 QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
1052                                                   const QTransform &t,
1053                                                   QImage::Format mask_format)
1054 {
1055     Q_UNUSED(mask_format)
1056     glyph_metrics_t gm = boundingBox(glyph);
1057
1058 //     printf(" -> for glyph %4x\n", glyph);
1059
1060     int gx = gm.x.toInt();
1061     int gy = gm.y.toInt();
1062     int iw = gm.width.toInt();
1063     int ih = gm.height.toInt();
1064
1065     if (iw <= 0 || iw <= 0)
1066         return 0;
1067
1068     bool has_transformation = t.type() > QTransform::TxTranslate;
1069
1070 #ifndef Q_OS_WINCE
1071     unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
1072     XFORM xform;
1073
1074     if (has_transformation) {
1075         xform.eM11 = t.m11();
1076         xform.eM12 = t.m12();
1077         xform.eM21 = t.m21();
1078         xform.eM22 = t.m22();
1079         xform.eDx = margin;
1080         xform.eDy = margin;
1081
1082         HDC hdc = CreateCompatibleDC(QWindowsContext::instance()->displayContext());
1083
1084         SetGraphicsMode(hdc, GM_ADVANCED);
1085         SetWorldTransform(hdc, &xform);
1086         HGDIOBJ old_font = SelectObject(hdc, font);
1087
1088         int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
1089         GLYPHMETRICS tgm;
1090         MAT2 mat;
1091         memset(&mat, 0, sizeof(mat));
1092         mat.eM11.value = mat.eM22.value = 1;
1093
1094         if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
1095             qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
1096             return 0;
1097         }
1098
1099         iw = tgm.gmBlackBoxX;
1100         ih = tgm.gmBlackBoxY;
1101
1102         xform.eDx -= tgm.gmptGlyphOrigin.x;
1103         xform.eDy += tgm.gmptGlyphOrigin.y;
1104
1105         SetGraphicsMode(hdc, GM_COMPATIBLE);
1106         SelectObject(hdc, old_font);
1107         ReleaseDC(0, hdc);
1108     }
1109 #else // else wince
1110     unsigned int options = 0;
1111 #ifdef DEBUG
1112     Q_ASSERT(!has_transformation);
1113 #else
1114     Q_UNUSED(has_transformation);
1115 #endif
1116 #endif // wince
1117     QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4,
1118                                                       ih + 2 * margin + 4,
1119                                                       QWindowsNativeImage::systemFormat());
1120
1121     /*If cleartype is enabled we use the standard system format even on Windows CE
1122       and not the special textbuffer format we have to use if cleartype is disabled*/
1123
1124     ni->image().fill(0xffffffff);
1125
1126     HDC hdc = ni->hdc();
1127
1128     SelectObject(hdc, GetStockObject(NULL_BRUSH));
1129     SelectObject(hdc, GetStockObject(BLACK_PEN));
1130     SetTextColor(hdc, RGB(0,0,0));
1131     SetBkMode(hdc, TRANSPARENT);
1132     SetTextAlign(hdc, TA_BASELINE);
1133
1134     HGDIOBJ old_font = SelectObject(hdc, font);
1135
1136 #ifndef Q_OS_WINCE
1137     if (has_transformation) {
1138         SetGraphicsMode(hdc, GM_ADVANCED);
1139         SetWorldTransform(hdc, &xform);
1140         ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
1141     } else
1142 #endif // !Q_OS_WINCE
1143     {
1144         ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
1145     }
1146
1147     SelectObject(hdc, old_font);
1148     return ni;
1149 }
1150
1151 QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
1152 {
1153     HFONT font = hfont;
1154     if (m_fontEngineData->clearTypeEnabled) {
1155         LOGFONT lf = m_logfont;
1156         lf.lfQuality = ANTIALIASED_QUALITY;
1157         font = CreateFontIndirect(&lf);
1158     }
1159     QImage::Format mask_format = QWindowsNativeImage::systemFormat();
1160     mask_format = QImage::Format_RGB32;
1161
1162     QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1163     if (mask == 0)
1164         return QImage();
1165
1166     QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
1167
1168     // ### This part is kinda pointless, but we'll crash later if we don't because some
1169     // code paths expects there to be colortables for index8-bit...
1170     QVector<QRgb> colors(256);
1171     for (int i=0; i<256; ++i)
1172         colors[i] = qRgba(0, 0, 0, i);
1173     indexed.setColorTable(colors);
1174
1175     // Copy data... Cannot use QPainter here as GDI has messed up the
1176     // Alpha channel of the ni.image pixels...
1177     for (int y=0; y<mask->height(); ++y) {
1178         uchar *dest = indexed.scanLine(y);
1179         if (mask->image().format() == QImage::Format_RGB16) {
1180             const qint16 *src = (qint16 *) ((const QImage &) mask->image()).scanLine(y);
1181             for (int x=0; x<mask->width(); ++x)
1182                 dest[x] = 255 - qGray(src[x]);
1183         } else {
1184             const uint *src = (uint *) ((const QImage &) mask->image()).scanLine(y);
1185             for (int x=0; x<mask->width(); ++x) {
1186                 if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
1187                     dest[x] = 255 - qGray(src[x]);
1188                 else
1189                     dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1190             }
1191         }
1192     }
1193
1194     // Cleanup...
1195     delete mask;
1196     if (m_fontEngineData->clearTypeEnabled) {
1197         DeleteObject(font);
1198     }
1199
1200     return indexed;
1201 }
1202
1203 #define SPI_GETFONTSMOOTHINGCONTRAST           0x200C
1204 #define SPI_SETFONTSMOOTHINGCONTRAST           0x200D
1205
1206 QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t)
1207 {
1208     HFONT font = hfont;
1209
1210     int contrast;
1211     SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1212     SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
1213
1214     int margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask);
1215     QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1216     SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
1217
1218     if (mask == 0)
1219         return QImage();
1220
1221     // Gracefully handle the odd case when the display is 16-bit
1222     const QImage source = mask->image().depth() == 32
1223                           ? mask->image()
1224                           : mask->image().convertToFormat(QImage::Format_RGB32);
1225
1226     QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1227     for (int y=0; y<mask->height(); ++y) {
1228         uint *dest = (uint *) rgbMask.scanLine(y);
1229         const uint *src = (uint *) source.scanLine(y);
1230         for (int x=0; x<mask->width(); ++x) {
1231             dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1232         }
1233     }
1234
1235     delete mask;
1236
1237     return rgbMask;
1238 }
1239
1240 QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
1241 {
1242     QFontDef request = fontDef;
1243     QString actualFontName = request.family;
1244     if (!uniqueFamilyName.isEmpty())
1245         request.family = uniqueFamilyName;
1246     request.pixelSize = pixelSize;
1247     // Disable font merging, as otherwise createEngine will return a multi-engine
1248     // instance instead of the specific engine we wish to clone.
1249     request.styleStrategy |= QFont::NoFontMerging;
1250
1251     QFontEngine *fontEngine =
1252         QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
1253                                            QWindowsContext::instance()->defaultDPI(),
1254                                            false,
1255                                            QStringList(), m_fontEngineData);
1256     if (fontEngine) {
1257         fontEngine->fontDef.family = actualFontName;
1258         if (!uniqueFamilyName.isEmpty()) {
1259             static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1260             QPlatformFontDatabase *pfdb = QWindowsIntegration::instance()->fontDatabase();
1261             static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1262         }
1263     }
1264     return fontEngine;
1265 }
1266
1267 void QWindowsFontEngine::initFontInfo(const QFontDef &request,
1268                                       HDC fontHdc,
1269                                       int dpi)
1270 {
1271     fontDef = request; // most settings are equal
1272     HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : m_fontEngineData->hdc;
1273     SelectObject(dc, hfont);
1274     wchar_t n[64];
1275     GetTextFace(dc, 64, n);
1276     fontDef.family = QString::fromWCharArray(n);
1277     fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1278     if (fontDef.pointSize < 0) {
1279         fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1280     } else if (fontDef.pixelSize == -1) {
1281         fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1282     }
1283 }
1284
1285 /*!
1286     \class QWindowsMultiFontEngine
1287     \brief Standard Windows Multi font engine.
1288     \ingroup qt-lighthouse-win
1289
1290     "Merges" several font engines that have gaps in the
1291     supported writing systems.
1292
1293     Will probably be superseded by a common Free Type font engine in Qt 5.X.
1294 */
1295
1296 QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks)
1297         : QFontEngineMulti(fallbacks.size()+1),
1298           fallbacks(fallbacks)
1299 {
1300     if (QWindowsContext::verboseFonts)
1301         qDebug() <<  __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks;
1302     engines[0] = first;
1303     first->ref.ref();
1304     fontDef = engines[0]->fontDef;
1305     cache_cost = first->cache_cost;
1306 }
1307
1308 QWindowsMultiFontEngine::~QWindowsMultiFontEngine()
1309 {
1310     if (QWindowsContext::verboseFonts)
1311         qDebug("%s", __FUNCTION__);
1312 }
1313
1314 void QWindowsMultiFontEngine::loadEngine(int at)
1315 {
1316     Q_ASSERT(at < engines.size());
1317     Q_ASSERT(engines.at(at) == 0);
1318
1319     const QString fam = fallbacks.at(at-1);
1320     QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(engines.at(0));
1321     LOGFONT lf = fe->logFont();
1322     memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32));  // 32 = Windows hard-coded
1323     HFONT hfont = CreateFontIndirect(&lf);
1324
1325     bool stockFont = false;
1326     if (hfont == 0) {
1327         hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1328         stockFont = true;
1329     }
1330     engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, fe->fontEngineData());
1331     engines[at]->ref.ref();
1332     engines[at]->fontDef = fontDef;
1333     if (QWindowsContext::verboseFonts)
1334         qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam));
1335
1336
1337     // TODO: increase cost in QFontCache for the font engine loaded here
1338 }
1339
1340 QT_END_NAMESPACE
1341