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

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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