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

Last change on this file since 605 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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