source: trunk/src/gui/text/qfontengine_win.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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