1
/****************************************************************************
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the QtGui module of the Qt Toolkit.
9
** $QT_BEGIN_LICENSE:LGPL$
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
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.
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.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
40
****************************************************************************/
42
#include "qfontengine_p.h"
43
#include "qtextengine_p.h"
45
#include "qt_windows.h"
46
#include <private/qapplication_p.h>
49
#include <qpaintdevice.h>
55
#include <qthreadstorage.h>
57
#include <private/qunicodetables_p.h>
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>
67
#if defined(Q_WS_WINCE)
68
#include "qguifunctions_wince.h"
71
//### mingw needed define
72
#ifndef TT_PRIM_CSPLINE
73
#define TT_PRIM_CSPLINE 3
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) | \
87
// common DC for all fonts
97
HDC displayDC = GetDC(0);
98
_hdc = CreateCompatibleDC(displayDC);
99
ReleaseDC(0, displayDC);
113
Q_GLOBAL_STATIC(QThreadStorage<QtHDC *>, local_shared_dc)
116
QtHDC *&hdc = local_shared_dc()->localData();
128
typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
129
static PtrGetCharWidthI ptrGetCharWidthI = 0;
130
static bool resolvedGetCharWidthI = false;
132
static void resolveGetCharWidthI()
134
if (resolvedGetCharWidthI)
136
resolvedGetCharWidthI = true;
137
ptrGetCharWidthI = (PtrGetCharWidthI)QLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
140
// defined in qtextengine_win.cpp
141
typedef void *SCRIPT_CACHE;
142
typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
143
extern fScriptFreeCache ScriptFreeCache;
145
static inline quint32 getUInt(unsigned char *p)
156
static inline quint16 getUShort(unsigned char *p)
165
// general font engine
167
QFixed QFontEngineWin::lineThickness() const
172
return QFontEngine::lineThickness();
175
static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
178
size = GetOutlineTextMetrics(hdc, 0, 0);
179
OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
180
GetOutlineTextMetrics(hdc, size, otm);
184
void QFontEngineWin::getCMap()
186
ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
187
HDC hdc = shared_dc();
188
SelectObject(hdc, hfont);
191
cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
193
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
194
cmapTable.size(), &symb, &size);
204
OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
205
designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
206
unitsPerEm = otm->otmEMSquare;
207
x_height = (int)otm->otmsXHeight;
208
loadKerningPairs(designToDevice);
209
_faceId.filename = (char *)otm + (int)otm->otmpFullName;
210
lineWidth = otm->otmsUnderscoreSize;
211
fsType = otm->otmfsType;
214
unitsPerEm = tm.tmHeight;
219
inline unsigned int getChar(const QChar *str, int &i, const int len)
221
unsigned int uc = str[i].unicode();
222
if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
223
uint low = str[i+1].unicode();
224
if (low >= 0xdc00 && low < 0xe000) {
225
uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
232
int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
237
#if defined(Q_WS_WINCE)
241
for (; i < numChars; ++i, ++glyph_pos) {
242
unsigned int uc = getChar(str, i, numChars);
243
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
244
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
245
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
248
for (; i < numChars; ++i, ++glyph_pos) {
249
unsigned int uc = getChar(str, i, numChars);
250
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
254
wchar_t first = tm.tmFirstChar;
255
wchar_t last = tm.tmLastChar;
257
for (; i < numChars; ++i, ++glyph_pos) {
258
uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
261
tm.tmFirstChar > 60000 || // see line 375
263
ucs >= first && ucs <= last)
264
glyphs->glyphs[glyph_pos] = ucs;
266
glyphs->glyphs[glyph_pos] = 0;
270
#if defined(Q_WS_WINCE)
274
for (; i < numChars; ++i, ++glyph_pos) {
275
unsigned int uc = getChar(str, i, numChars);
276
glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
277
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
278
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
281
for (; i < numChars; ++i, ++glyph_pos) {
282
unsigned int uc = getChar(str, i, numChars);
283
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
287
wchar_t first = tm.tmFirstChar;
288
wchar_t last = tm.tmLastChar;
290
for (; i < numChars; ++i, ++glyph_pos) {
291
uint uc = getChar(str, i, numChars);
294
tm.tmFirstChar > 60000 || // see comment in QFontEngineWin
296
uc >= first && uc <= last)
297
glyphs->glyphs[glyph_pos] = uc;
299
glyphs->glyphs[glyph_pos] = 0;
303
glyphs->numGlyphs = glyph_pos;
308
QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf)
310
//qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight);
317
HDC hdc = shared_dc();
318
SelectObject(hdc, hfont);
319
this->stockFont = stockFont;
320
fontDef.pixelSize = -lf.lfHeight;
324
synthesized_flags = -1;
328
BOOL res = GetTextMetrics(hdc, &tm);
329
fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
331
qErrnoWarning("QFontEngineWin: GetTextMetrics failed");
332
ZeroMemory(&tm, sizeof(TEXTMETRIC));
335
cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
341
designAdvancesSize = 0;
343
if (!resolvedGetCharWidthI)
344
resolveGetCharWidthI();
347
QFontEngineWin::~QFontEngineWin()
350
free(designAdvances);
355
// make sure we aren't by accident still selected
356
SelectObject(shared_dc(), (HFONT)GetStockObject(SYSTEM_FONT));
359
if (!DeleteObject(hfont))
360
qErrnoWarning("QFontEngineWin: failed to delete non-stock font...");
364
HGDIOBJ QFontEngineWin::selectDesignFont() const
367
f.lfHeight = unitsPerEm;
368
HFONT designFont = CreateFontIndirect(&f);
369
return SelectObject(shared_dc(), designFont);
372
bool QFontEngineWin::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
374
if (*nglyphs < len) {
379
*nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
381
if (flags & QTextEngine::GlyphIndicesOnly)
384
#if defined(Q_WS_WINCE)
385
HDC hdc = shared_dc();
386
if (flags & QTextEngine::DesignMetrics) {
389
for(register int i = 0; i < len; i++) {
390
bool surrogate = (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00 && i < len-1
391
&& str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000);
392
unsigned int glyph = glyphs->glyphs[glyph_pos];
393
if(int(glyph) >= designAdvancesSize) {
394
int newSize = (glyph + 256) >> 8 << 8;
395
designAdvances = q_check_ptr((QFixed *)realloc(designAdvances, newSize*sizeof(QFixed)));
396
for(int i = designAdvancesSize; i < newSize; ++i)
397
designAdvances[i] = -1000000;
398
designAdvancesSize = newSize;
400
if(designAdvances[glyph] < -999999) {
402
oldFont = selectDesignFont();
404
GetTextExtentPoint32(hdc, (wchar_t *)(str+i), surrogate ? 2 : 1, &size);
405
designAdvances[glyph] = QFixed((int)size.cx)/designToDevice;
407
glyphs->advances_x[glyph_pos] = designAdvances[glyph];
408
glyphs->advances_y[glyph_pos] = 0;
414
DeleteObject(SelectObject(hdc, oldFont));
419
for(register int i = 0; i < len; i++) {
420
bool surrogate = (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00 && i < len-1
421
&& str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000);
422
unsigned int glyph = glyphs->glyphs[glyph_pos];
424
glyphs->advances_y[glyph_pos] = 0;
426
if (glyph >= widthCacheSize) {
427
int newSize = (glyph + 256) >> 8 << 8;
428
widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
429
newSize*sizeof(QFixed)));
430
memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
431
widthCacheSize = newSize;
433
glyphs->advances_x[glyph_pos] = widthCache[glyph];
434
// font-width cache failed
435
if (glyphs->advances_x[glyph_pos] == 0) {
438
oldFont = SelectObject(hdc, hfont);
439
GetTextExtentPoint32(hdc, (wchar_t *)str + i, surrogate ? 2 : 1, &size);
440
glyphs->advances_x[glyph_pos] = size.cx;
441
// if glyph's within cache range, store it for later
442
if (size.cx > 0 && size.cx < 0x100)
443
widthCache[glyph] = size.cx;
452
SelectObject(hdc, oldFont);
455
recalcAdvances(glyphs, flags);
460
void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
463
HDC hdc = shared_dc();
464
if (ttf && (flags & QTextEngine::DesignMetrics)) {
465
for(int i = 0; i < glyphs->numGlyphs; i++) {
466
unsigned int glyph = glyphs->glyphs[i];
467
if(int(glyph) >= designAdvancesSize) {
468
int newSize = (glyph + 256) >> 8 << 8;
469
designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
470
newSize*sizeof(QFixed)));
471
for(int i = designAdvancesSize; i < newSize; ++i)
472
designAdvances[i] = -1000000;
473
designAdvancesSize = newSize;
475
if (designAdvances[glyph] < -999999) {
477
oldFont = selectDesignFont();
480
if (ptrGetCharWidthI)
481
ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
482
designAdvances[glyph] = QFixed(width) / designToDevice;
484
glyphs->advances_x[i] = designAdvances[glyph];
485
glyphs->advances_y[i] = 0;
488
DeleteObject(SelectObject(hdc, oldFont));
490
for(int i = 0; i < glyphs->numGlyphs; i++) {
491
unsigned int glyph = glyphs->glyphs[i];
493
glyphs->advances_y[i] = 0;
495
if (glyph >= widthCacheSize) {
496
int newSize = (glyph + 256) >> 8 << 8;
497
widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
498
newSize*sizeof(QFixed)));
499
memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
500
widthCacheSize = newSize;
502
glyphs->advances_x[i] = widthCache[glyph];
503
// font-width cache failed
504
if (glyphs->advances_x[i] == 0) {
507
oldFont = SelectObject(hdc, hfont);
510
QChar ch[2] = { ushort(glyph), 0 };
512
if (glyph > 0xffff) {
513
ch[0] = QChar::highSurrogate(glyph);
514
ch[1] = QChar::lowSurrogate(glyph);
518
GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
520
} else if (ptrGetCharWidthI) {
521
ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
523
glyphs->advances_x[i] = width;
524
// if glyph's within cache range, store it for later
525
if (width > 0 && width < 0x100)
526
widthCache[glyph] = width;
531
SelectObject(hdc, oldFont);
535
glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
537
if (glyphs.numGlyphs == 0)
538
return glyph_metrics_t();
541
for (int i = 0; i < glyphs.numGlyphs; ++i)
542
w += glyphs.effectiveAdvance(i);
544
return glyph_metrics_t(0, -tm.tmAscent, w, tm.tmHeight, w, 0);
548
glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
553
HDC hdc = shared_dc();
554
SelectObject(hdc, hfont);
558
GetCharABCWidthsFloat(hdc, ch, ch, &abc);
559
int width = qRound(abc.abcfB);
561
return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
565
mat.eM11.value = mat.eM22.value = 1;
566
mat.eM11.fract = mat.eM22.fract = 0;
567
mat.eM21.value = mat.eM12.value = 0;
568
mat.eM21.fract = mat.eM12.fract = 0;
570
if (t.type() > QTransform::TxTranslate) {
571
// We need to set the transform using the HDC's world
572
// matrix rather than using the MAT2 above, because the
573
// results provided when transforming via MAT2 does not
574
// match the glyphs that are drawn using a WorldTransform
576
xform.eM11 = t.m11();
577
xform.eM12 = t.m12();
578
xform.eM21 = t.m21();
579
xform.eM22 = t.m22();
582
SetGraphicsMode(hdc, GM_ADVANCED);
583
SetWorldTransform(hdc, &xform);
586
res = GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 0, &mat);
588
if (t.type() > QTransform::TxTranslate) {
590
xform.eM11 = xform.eM22 = 1;
591
xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
592
SetWorldTransform(hdc, &xform);
593
SetGraphicsMode(hdc, GM_COMPATIBLE);
596
if (res != GDI_ERROR) {
597
return glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
598
(int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
601
return glyph_metrics_t();
603
HDC hdc = shared_dc();
604
HGDIOBJ oldFont = SelectObject(hdc, hfont);
609
#ifdef GWES_MGTT // true type fonts
610
if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
611
width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
612
advance = abc.abcA + abc.abcB + abc.abcC;
616
#if defined(GWES_MGRAST) || defined(GWES_MGRAST2) // raster fonts
617
if (GetCharWidth32(hdc, glyph, glyph, &width)) {
623
width = tm.tmMaxCharWidth;
627
SelectObject(hdc, oldFont);
628
return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
632
QFixed QFontEngineWin::ascent() const
637
QFixed QFontEngineWin::descent() const
642
QFixed QFontEngineWin::leading() const
644
return tm.tmExternalLeading;
648
QFixed QFontEngineWin::xHeight() const
652
return QFontEngine::xHeight();
655
QFixed QFontEngineWin::averageCharWidth() const
657
return tm.tmAveCharWidth;
660
qreal QFontEngineWin::maxCharWidth() const
662
return tm.tmMaxCharWidth;
665
enum { max_font_count = 256 };
666
static const ushort char_table[] = {
688
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
691
qreal QFontEngineWin::minLeftBearing() const
693
if (lbearing == SHRT_MIN)
694
minRightBearing(); // calculates both
699
qreal QFontEngineWin::minRightBearing() const
702
if (rbearing == SHRT_MIN) {
705
HDC hdc = shared_dc();
706
SelectObject(hdc, hfont);
709
int n = tm.tmLastChar - tm.tmFirstChar;
710
if (n <= max_font_count) {
712
GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
714
abc = new ABC[char_table_entries+1];
715
for(int i = 0; i < char_table_entries; i++)
716
GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
717
n = char_table_entries;
721
for (int i = 1; i < n; i++) {
722
if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
723
ml = qMin(ml,abc[i].abcA);
724
mr = qMin(mr,abc[i].abcC);
735
if (rbearing == SHRT_MIN) {
738
HDC hdc = shared_dc();
739
SelectObject(hdc, hfont);
742
int n = tm.tmLastChar - tm.tmFirstChar;
743
if (n <= max_font_count) {
745
GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
747
abc = new ABC[char_table_entries+1];
748
for(int i = 0; i < char_table_entries; i++)
749
GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
750
n = char_table_entries;
754
for (int i = 1; i < n; i++) {
755
if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
756
ml = qMin(ml,abc[i].abcA);
757
mr = qMin(mr,abc[i].abcC);
763
int n = tm.tmLastChar - tm.tmFirstChar+1;
764
if (n <= max_font_count) {
765
abc = new ABCFLOAT[n];
766
GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
768
abc = new ABCFLOAT[char_table_entries];
769
for(int i = 0; i < char_table_entries; i++)
770
GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
771
n = char_table_entries;
773
float fml = abc[0].abcfA;
774
float fmr = abc[0].abcfC;
775
for (int i=1; i<n; i++) {
776
if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
777
fml = qMin(fml,abc[i].abcfA);
778
fmr = qMin(fmr,abc[i].abcfC);
781
ml = int(fml - 0.9999);
782
mr = int(fmr - 0.9999);
794
const char *QFontEngineWin::name() const
799
bool QFontEngineWin::canRender(const QChar *string, int len)
802
for (int i = 0; i < len; ++i) {
803
unsigned int uc = getChar(string, i, len);
804
if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
806
if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
814
for (int i = 0; i < len; ++i) {
815
unsigned int uc = getChar(string, i, len);
816
if (getTrueTypeGlyphIndex(cmap, uc) == 0)
821
if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
828
QFontEngine::Type QFontEngineWin::type() const
830
return QFontEngine::Win;
833
static inline double qt_fixed_to_double(const FIXED &p) {
834
return ((p.value << 16) + p.fract) / 65536.0;
837
static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
838
return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
842
#define GGO_UNHINTED 0x0100
845
static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
846
QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
848
#if defined(Q_WS_WINCE)
853
mat.eM11.value = mat.eM22.value = 1;
854
mat.eM11.fract = mat.eM22.fract = 0;
855
mat.eM21.value = mat.eM12.value = 0;
856
mat.eM21.fract = mat.eM12.fract = 0;
857
uint glyphFormat = GGO_NATIVE;
860
glyphFormat |= GGO_GLYPH_INDEX;
862
GLYPHMETRICS gMetric;
863
memset(&gMetric, 0, sizeof(GLYPHMETRICS));
864
int bufferSize = GDI_ERROR;
865
#if !defined(Q_WS_WINCE)
866
bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
868
if ((DWORD)bufferSize == GDI_ERROR) {
872
void *dataBuffer = new char[bufferSize];
873
DWORD ret = GDI_ERROR;
874
#if !defined(Q_WS_WINCE)
875
ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
877
if (ret == GDI_ERROR) {
878
delete [](char *)dataBuffer;
884
*metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
885
(int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
886
gMetric.gmCellIncX, gMetric.gmCellIncY);
890
int headerOffset = 0;
891
TTPOLYGONHEADER *ttph = 0;
893
QPointF oset = position.toPointF();
894
while (headerOffset < bufferSize) {
895
ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
897
QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
898
path->moveTo(lastPoint + oset);
899
offset += sizeof(TTPOLYGONHEADER);
901
while (offset<int(headerOffset + ttph->cb)) {
902
curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
903
switch (curve->wType) {
905
for (int i=0; i<curve->cpfx; ++i) {
906
QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
911
case TT_PRIM_QSPLINE: {
912
const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
913
QPointF prev(elm.x, elm.y);
915
for (int i=0; i<curve->cpfx - 1; ++i) {
916
QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
917
QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
918
if (i < curve->cpfx - 2) {
919
endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
924
path->quadTo(p1, endPoint);
930
case TT_PRIM_CSPLINE: {
931
for (int i=0; i<curve->cpfx; ) {
932
QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
933
QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
934
QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
935
path->cubicTo(p2, p3, p4);
940
qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
942
offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
944
path->closeSubpath();
945
headerOffset += ttph->cb;
947
delete [] (char*)dataBuffer;
952
void QFontEngineWin::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
953
QPainterPath *path, QTextItem::RenderFlags)
955
LOGFONT lf = logfont;
956
// The sign must be negative here to make sure we match against character height instead of
957
// hinted cell height. This ensures that we get linear matching, and we need this for
958
// paths since we later on apply a scaling transform to the glyph outline to get the
959
// font at the correct pixel size.
960
lf.lfHeight = -unitsPerEm;
962
HFONT hf = CreateFontIndirect(&lf);
963
HDC hdc = shared_dc();
964
HGDIOBJ oldfont = SelectObject(hdc, hf);
966
for(int i = 0; i < nglyphs; ++i) {
967
if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
968
qreal(fontDef.pixelSize) / unitsPerEm)) {
969
// Some windows fonts, like "Modern", are vector stroke
970
// fonts, which are reported as TMPF_VECTOR but do not
971
// support GetGlyphOutline, and thus we set this bit so
972
// that addOutLineToPath can check it and return safely...
977
DeleteObject(SelectObject(hdc, oldfont));
980
void QFontEngineWin::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
981
QPainterPath *path, QTextItem::RenderFlags flags)
983
#if !defined(Q_WS_WINCE)
984
if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
986
QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
988
// has_outline is set to false if addGlyphToPath gets
989
// false from GetGlyphOutline, meaning its not an outline
995
QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
998
QFontEngine::FaceId QFontEngineWin::faceId() const
1003
QT_BEGIN_INCLUDE_NAMESPACE
1005
QT_END_INCLUDE_NAMESPACE
1007
int QFontEngineWin::synthesized() const
1009
if(synthesized_flags == -1) {
1010
synthesized_flags = 0;
1012
const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
1013
HDC hdc = shared_dc();
1014
SelectObject(hdc, hfont);
1016
GetFontData(hdc, HEAD, 44, &data, 4);
1017
USHORT macStyle = getUShort(data);
1018
if (tm.tmItalic && !(macStyle & 2))
1019
synthesized_flags = SynthesizedItalic;
1020
if (fontDef.stretch != 100 && ttf)
1021
synthesized_flags |= SynthesizedStretch;
1022
if (tm.tmWeight >= 500 && !(macStyle & 1))
1023
synthesized_flags |= SynthesizedBold;
1024
//qDebug() << "font is" << _name <<
1025
// "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
1028
return synthesized_flags;
1031
QFixed QFontEngineWin::emSquareSize() const
1036
QFontEngine::Properties QFontEngineWin::properties() const
1038
LOGFONT lf = logfont;
1039
lf.lfHeight = unitsPerEm;
1040
HFONT hf = CreateFontIndirect(&lf);
1041
HDC hdc = shared_dc();
1042
HGDIOBJ oldfont = SelectObject(hdc, hf);
1043
OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
1045
p.emSquare = unitsPerEm;
1046
p.italicAngle = otm->otmItalicAngle;
1047
p.postscriptName = (char *)otm + (int)otm->otmpFamilyName;
1048
p.postscriptName += (char *)otm + (int)otm->otmpStyleName;
1049
#ifndef QT_NO_PRINTER
1050
p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
1052
p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
1053
otm->otmrcFontBox.right - otm->otmrcFontBox.left,
1054
otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
1055
p.ascent = otm->otmAscent;
1056
p.descent = -otm->otmDescent;
1057
p.leading = (int)otm->otmLineGap;
1059
p.lineWidth = otm->otmsUnderscoreSize;
1061
DeleteObject(SelectObject(hdc, oldfont));
1065
void QFontEngineWin::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1067
LOGFONT lf = logfont;
1068
lf.lfHeight = unitsPerEm;
1069
int flags = synthesized();
1070
if(flags & SynthesizedItalic)
1071
lf.lfItalic = false;
1073
HFONT hf = CreateFontIndirect(&lf);
1074
HDC hdc = shared_dc();
1075
HGDIOBJ oldfont = SelectObject(hdc, hf);
1079
addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
1080
DeleteObject(SelectObject(hdc, oldfont));
1083
bool QFontEngineWin::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1087
HDC hdc = shared_dc();
1088
SelectObject(hdc, hfont);
1089
DWORD t = qbswap<quint32>(tag);
1090
*length = GetFontData(hdc, t, 0, buffer, *length);
1091
return *length != GDI_ERROR;
1094
#if !defined(CLEARTYPE_QUALITY)
1095
# define CLEARTYPE_QUALITY 5
1098
extern bool qt_cleartype_enabled;
1100
QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
1101
const QTransform &t, QImage::Format mask_format)
1103
Q_UNUSED(mask_format)
1104
glyph_metrics_t gm = boundingBox(glyph);
1106
// printf(" -> for glyph %4x\n", glyph);
1108
int gx = gm.x.toInt();
1109
int gy = gm.y.toInt();
1110
int iw = gm.width.toInt();
1111
int ih = gm.height.toInt();
1113
if (iw <= 0 || iw <= 0)
1116
bool has_transformation = t.type() > QTransform::TxTranslate;
1119
unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
1122
if (has_transformation) {
1123
xform.eM11 = t.m11();
1124
xform.eM12 = t.m12();
1125
xform.eM21 = t.m21();
1126
xform.eM22 = t.m22();
1131
HDC hdc = qthdc.hdc();
1133
SetGraphicsMode(hdc, GM_ADVANCED);
1134
SetWorldTransform(hdc, &xform);
1135
HGDIOBJ old_font = SelectObject(hdc, font);
1137
int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
1140
memset(&mat, 0, sizeof(mat));
1141
mat.eM11.value = mat.eM22.value = 1;
1143
if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
1144
qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
1148
iw = tgm.gmBlackBoxX;
1149
ih = tgm.gmBlackBoxY;
1151
xform.eDx -= tgm.gmptGlyphOrigin.x;
1152
xform.eDy += tgm.gmptGlyphOrigin.y;
1154
SetGraphicsMode(hdc, GM_COMPATIBLE);
1155
SelectObject(hdc, old_font);
1158
unsigned int options = 0;
1160
Q_ASSERT(!has_transformation);
1162
Q_UNUSED(has_transformation);
1166
QNativeImage *ni = new QNativeImage(iw + 2 * margin + 4,
1167
ih + 2 * margin + 4,
1168
QNativeImage::systemFormat(), !qt_cleartype_enabled);
1170
/*If cleartype is enabled we use the standard system format even on Windows CE
1171
and not the special textbuffer format we have to use if cleartype is disabled*/
1173
ni->image.fill(0xffffffff);
1177
SelectObject(hdc, GetStockObject(NULL_BRUSH));
1178
SelectObject(hdc, GetStockObject(BLACK_PEN));
1179
SetTextColor(hdc, RGB(0,0,0));
1180
SetBkMode(hdc, TRANSPARENT);
1181
SetTextAlign(hdc, TA_BASELINE);
1183
HGDIOBJ old_font = SelectObject(hdc, font);
1186
if (has_transformation) {
1187
SetGraphicsMode(hdc, GM_ADVANCED);
1188
SetWorldTransform(hdc, &xform);
1189
ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
1193
ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
1196
SelectObject(hdc, old_font);
1201
extern uint qt_pow_gamma[256];
1203
QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
1206
if (qt_cleartype_enabled) {
1207
LOGFONT lf = logfont;
1208
lf.lfQuality = ANTIALIASED_QUALITY;
1209
font = CreateFontIndirect(&lf);
1211
QImage::Format mask_format = QNativeImage::systemFormat();
1213
mask_format = QImage::Format_RGB32;
1216
QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1220
QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
1222
// ### This part is kinda pointless, but we'll crash later if we dont because some
1223
// code paths expects there to be colortables for index8-bit...
1224
QVector<QRgb> colors(256);
1225
for (int i=0; i<256; ++i)
1226
colors[i] = qRgba(0, 0, 0, i);
1227
indexed.setColorTable(colors);
1229
// Copy data... Cannot use QPainter here as GDI has messed up the
1230
// Alpha channel of the ni.image pixels...
1231
for (int y=0; y<mask->height(); ++y) {
1232
uchar *dest = indexed.scanLine(y);
1233
if (mask->image.format() == QImage::Format_RGB16) {
1234
const qint16 *src = (qint16 *) ((const QImage &) mask->image).scanLine(y);
1235
for (int x=0; x<mask->width(); ++x)
1236
dest[x] = 255 - qGray(src[x]);
1238
const uint *src = (uint *) ((const QImage &) mask->image).scanLine(y);
1239
for (int x=0; x<mask->width(); ++x) {
1241
dest[x] = 255 - qGray(src[x]);
1243
if (QNativeImage::systemFormat() == QImage::Format_RGB16)
1244
dest[x] = 255 - qGray(src[x]);
1246
dest[x] = 255 - (qt_pow_gamma[qGray(src[x])] * 255. / 2047.);
1254
if (qt_cleartype_enabled) {
1261
#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1262
#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1264
QImage QFontEngineWin::alphaRGBMapForGlyph(glyph_t glyph, int margin, const QTransform &t)
1269
SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1270
SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
1272
QNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1273
SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
1278
// Gracefully handle the odd case when the display is 16-bit
1279
const QImage source = mask->image.depth() == 32
1281
: mask->image.convertToFormat(QImage::Format_RGB32);
1283
QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1284
for (int y=0; y<mask->height(); ++y) {
1285
uint *dest = (uint *) rgbMask.scanLine(y);
1286
const uint *src = (uint *) source.scanLine(y);
1287
for (int x=0; x<mask->width(); ++x) {
1288
dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1297
// -------------------------------------- Multi font engine
1299
QFontEngineMultiWin::QFontEngineMultiWin(QFontEngineWin *first, const QStringList &fallbacks)
1300
: QFontEngineMulti(fallbacks.size()+1),
1301
fallbacks(fallbacks)
1305
fontDef = engines[0]->fontDef;
1308
void QFontEngineMultiWin::loadEngine(int at)
1310
Q_ASSERT(at < engines.size());
1311
Q_ASSERT(engines.at(at) == 0);
1313
QString fam = fallbacks.at(at-1);
1315
LOGFONT lf = static_cast<QFontEngineWin *>(engines.at(0))->logfont;
1316
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
1317
HFONT hfont = CreateFontIndirect(&lf);
1319
bool stockFont = false;
1321
hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1324
engines[at] = new QFontEngineWin(fam, hfont, stockFont, lf);
1325
engines[at]->ref.ref();
1326
engines[at]->fontDef = fontDef;