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