~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/text/qfontengine_win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
 
5
** Contact: Nokia Corporation (qt-info@nokia.com)
 
6
**
 
7
** This file is part of the QtGui module of the Qt Toolkit.
 
8
**
 
9
** $QT_BEGIN_LICENSE:LGPL$
 
10
** 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
 
14
** this package.
 
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
** If you have questions regarding the use of this file, please contact
 
29
** Nokia at qt-info@nokia.com.
 
30
**
 
31
**
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
 
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
 
 
89
QT_BEGIN_NAMESPACE
 
90
 
 
91
class QtHDC
 
92
{
 
93
    HDC _hdc;
 
94
public:
 
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
 
113
Q_GLOBAL_STATIC(QThreadStorage<QtHDC *>, local_shared_dc)
 
114
HDC shared_dc()
 
115
{
 
116
    QtHDC *&hdc = local_shared_dc()->localData();
 
117
    if (!hdc)
 
118
        hdc = new QtHDC;
 
119
    return hdc->hdc();
 
120
}
 
121
#else
 
122
HDC shared_dc()
 
123
{
 
124
    return 0;
 
125
}
 
126
#endif
 
127
 
 
128
typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
 
129
static PtrGetCharWidthI ptrGetCharWidthI = 0;
 
130
static bool resolvedGetCharWidthI = false;
 
131
 
 
132
static void resolveGetCharWidthI()
 
133
{
 
134
    if (resolvedGetCharWidthI)
 
135
        return;
 
136
    resolvedGetCharWidthI = true;
 
137
    ptrGetCharWidthI = (PtrGetCharWidthI)QLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
 
138
}
 
139
 
 
140
// defined in qtextengine_win.cpp
 
141
typedef void *SCRIPT_CACHE;
 
142
typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
 
143
extern fScriptFreeCache ScriptFreeCache;
 
144
 
 
145
static inline quint32 getUInt(unsigned char *p)
 
146
{
 
147
    quint32 val;
 
148
    val = *p++ << 24;
 
149
    val |= *p++ << 16;
 
150
    val |= *p++ << 8;
 
151
    val |= *p;
 
152
 
 
153
    return val;
 
154
}
 
155
 
 
156
static inline quint16 getUShort(unsigned char *p)
 
157
{
 
158
    quint16 val;
 
159
    val = *p++ << 8;
 
160
    val |= *p;
 
161
 
 
162
    return val;
 
163
}
 
164
 
 
165
// general font engine
 
166
 
 
167
QFixed QFontEngineWin::lineThickness() const
 
168
{
 
169
    if(lineWidth > 0)
 
170
        return lineWidth;
 
171
 
 
172
    return QFontEngine::lineThickness();
 
173
}
 
174
 
 
175
static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
 
176
{
 
177
    int size;
 
178
    size = GetOutlineTextMetrics(hdc, 0, 0);
 
179
    OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
 
180
    GetOutlineTextMetrics(hdc, size, otm);
 
181
    return otm;
 
182
}
 
183
 
 
184
void QFontEngineWin::getCMap()
 
185
{
 
186
    ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
 
187
    HDC hdc = shared_dc();
 
188
    SelectObject(hdc, hfont);
 
189
    bool symb = false;
 
190
    if (ttf) {
 
191
        cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
 
192
        int size = 0;
 
193
        cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
 
194
                       cmapTable.size(), &symb, &size);
 
195
    }
 
196
    if (!cmap) {
 
197
        ttf = false;
 
198
        symb = false;
 
199
    }
 
200
    symbol = symb;
 
201
    designToDevice = 1;
 
202
    _faceId.index = 0;
 
203
    if(cmap) {
 
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;
 
212
        free(otm);
 
213
    } else {
 
214
        unitsPerEm = tm.tmHeight;
 
215
    }
 
216
}
 
217
 
 
218
 
 
219
inline unsigned int getChar(const QChar *str, int &i, const int len)
 
220
{
 
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;
 
226
            ++i;
 
227
        }
 
228
    }
 
229
    return uc;
 
230
}
 
231
 
 
232
int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
 
233
{
 
234
    int i = 0;
 
235
    int glyph_pos = 0;
 
236
    if (mirrored) {
 
237
#if defined(Q_WS_WINCE)
 
238
        {
 
239
#else
 
240
        if (symbol) {
 
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);
 
246
            }
 
247
        } else if (ttf) {
 
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));
 
251
            }
 
252
        } else {
 
253
#endif
 
254
            wchar_t first = tm.tmFirstChar;
 
255
            wchar_t last = tm.tmLastChar;
 
256
 
 
257
            for (; i < numChars; ++i, ++glyph_pos) {
 
258
                uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
 
259
                if (
 
260
#ifdef Q_WS_WINCE
 
261
                    tm.tmFirstChar > 60000 || // see line 375
 
262
#endif
 
263
                        ucs >= first && ucs <= last)
 
264
                    glyphs->glyphs[glyph_pos] = ucs;
 
265
                else
 
266
                    glyphs->glyphs[glyph_pos] = 0;
 
267
            }
 
268
        }
 
269
    } else {
 
270
#if defined(Q_WS_WINCE)
 
271
        {
 
272
#else
 
273
        if (symbol) {
 
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);
 
279
            }
 
280
        } else if (ttf) {
 
281
            for (; i < numChars; ++i, ++glyph_pos) {
 
282
                unsigned int uc = getChar(str, i, numChars);
 
283
                glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
 
284
            }
 
285
        } else {
 
286
#endif
 
287
            wchar_t first = tm.tmFirstChar;
 
288
            wchar_t last = tm.tmLastChar;
 
289
 
 
290
            for (; i < numChars; ++i, ++glyph_pos) {
 
291
                uint uc = getChar(str, i, numChars);
 
292
                if (
 
293
#ifdef Q_WS_WINCE
 
294
                    tm.tmFirstChar > 60000 || // see comment in QFontEngineWin
 
295
#endif
 
296
                        uc >= first && uc <= last)
 
297
                    glyphs->glyphs[glyph_pos] = uc;
 
298
                else
 
299
                    glyphs->glyphs[glyph_pos] = 0;
 
300
            }
 
301
        }
 
302
    }
 
303
    glyphs->numGlyphs = glyph_pos;
 
304
    return glyph_pos;
 
305
}
 
306
 
 
307
 
 
308
QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf)
 
309
{
 
310
    //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight);
 
311
 
 
312
    _name = name;
 
313
 
 
314
    cmap = 0;
 
315
    hfont = _hfont;
 
316
    logfont = lf;
 
317
    HDC hdc = shared_dc();
 
318
    SelectObject(hdc, hfont);
 
319
    this->stockFont = stockFont;
 
320
    fontDef.pixelSize = -lf.lfHeight;
 
321
 
 
322
    lbearing = SHRT_MIN;
 
323
    rbearing = SHRT_MIN;
 
324
    synthesized_flags = -1;
 
325
    lineWidth = -1;
 
326
    x_height = -1;
 
327
 
 
328
    BOOL res = GetTextMetrics(hdc, &tm);
 
329
    fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
 
330
    if (!res) {
 
331
        qErrnoWarning("QFontEngineWin: GetTextMetrics failed");
 
332
        ZeroMemory(&tm, sizeof(TEXTMETRIC));
 
333
    }
 
334
 
 
335
    cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
 
336
    getCMap();
 
337
 
 
338
    widthCache = 0;
 
339
    widthCacheSize = 0;
 
340
    designAdvances = 0;
 
341
    designAdvancesSize = 0;
 
342
 
 
343
    if (!resolvedGetCharWidthI)
 
344
        resolveGetCharWidthI();
 
345
}
 
346
 
 
347
QFontEngineWin::~QFontEngineWin()
 
348
{
 
349
    if (designAdvances)
 
350
        free(designAdvances);
 
351
 
 
352
    if (widthCache)
 
353
        free(widthCache);
 
354
 
 
355
    // make sure we aren't by accident still selected
 
356
    SelectObject(shared_dc(), (HFONT)GetStockObject(SYSTEM_FONT));
 
357
 
 
358
    if (!stockFont) {
 
359
        if (!DeleteObject(hfont))
 
360
            qErrnoWarning("QFontEngineWin: failed to delete non-stock font...");
 
361
    }
 
362
}
 
363
 
 
364
HGDIOBJ QFontEngineWin::selectDesignFont() const
 
365
{
 
366
    LOGFONT f = logfont;
 
367
    f.lfHeight = unitsPerEm;
 
368
    HFONT designFont = CreateFontIndirect(&f);
 
369
    return SelectObject(shared_dc(), designFont);
 
370
}
 
371
 
 
372
bool QFontEngineWin::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
 
373
{
 
374
    if (*nglyphs < len) {
 
375
        *nglyphs = len;
 
376
        return false;
 
377
    }
 
378
 
 
379
    *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
 
380
 
 
381
    if (flags & QTextEngine::GlyphIndicesOnly)
 
382
        return true;
 
383
 
 
384
#if defined(Q_WS_WINCE)
 
385
    HDC hdc = shared_dc();
 
386
    if (flags & QTextEngine::DesignMetrics) {
 
387
        HGDIOBJ oldFont = 0;
 
388
        int glyph_pos = 0;
 
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;
 
399
            }
 
400
            if(designAdvances[glyph] < -999999) {
 
401
                if(!oldFont)
 
402
                    oldFont = selectDesignFont();
 
403
                SIZE size = {0, 0};
 
404
                GetTextExtentPoint32(hdc, (wchar_t *)(str+i), surrogate ? 2 : 1, &size);
 
405
                designAdvances[glyph] = QFixed((int)size.cx)/designToDevice;
 
406
            }
 
407
            glyphs->advances_x[glyph_pos] = designAdvances[glyph];
 
408
            glyphs->advances_y[glyph_pos] = 0;
 
409
            if (surrogate)
 
410
                ++i;
 
411
            ++glyph_pos;
 
412
        }
 
413
        if(oldFont)
 
414
            DeleteObject(SelectObject(hdc, oldFont));
 
415
    } else {
 
416
        int glyph_pos = 0;
 
417
        HGDIOBJ oldFont = 0;
 
418
 
 
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];
 
423
 
 
424
            glyphs->advances_y[glyph_pos] = 0;
 
425
 
 
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;
 
432
            }
 
433
            glyphs->advances_x[glyph_pos] = widthCache[glyph];
 
434
            // font-width cache failed
 
435
            if (glyphs->advances_x[glyph_pos] == 0) {
 
436
                SIZE size = {0, 0};
 
437
                if (!oldFont)
 
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;
 
444
            }
 
445
 
 
446
            if (surrogate)
 
447
                ++i;
 
448
            ++glyph_pos;
 
449
        }
 
450
 
 
451
        if (oldFont)
 
452
            SelectObject(hdc, oldFont);
 
453
    }
 
454
#else
 
455
    recalcAdvances(glyphs, flags);
 
456
#endif
 
457
    return true;
 
458
}
 
459
 
 
460
void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
 
461
{
 
462
    HGDIOBJ oldFont = 0;
 
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;
 
474
            }
 
475
            if (designAdvances[glyph] < -999999) {
 
476
                if (!oldFont)
 
477
                    oldFont = selectDesignFont();
 
478
 
 
479
                int width = 0;
 
480
                if (ptrGetCharWidthI)
 
481
                    ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
 
482
                designAdvances[glyph] = QFixed(width) / designToDevice;
 
483
            }
 
484
            glyphs->advances_x[i] = designAdvances[glyph];
 
485
            glyphs->advances_y[i] = 0;
 
486
        }
 
487
        if(oldFont)
 
488
            DeleteObject(SelectObject(hdc, oldFont));
 
489
    } else {
 
490
        for(int i = 0; i < glyphs->numGlyphs; i++) {
 
491
            unsigned int glyph = glyphs->glyphs[i];
 
492
 
 
493
            glyphs->advances_y[i] = 0;
 
494
 
 
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;
 
501
            }
 
502
            glyphs->advances_x[i] = widthCache[glyph];
 
503
            // font-width cache failed
 
504
            if (glyphs->advances_x[i] == 0) {
 
505
                int width = 0;
 
506
                if (!oldFont)
 
507
                    oldFont = SelectObject(hdc, hfont);
 
508
 
 
509
                if (!ttf) {
 
510
                    QChar ch[2] = { ushort(glyph), 0 };
 
511
                    int chrLen = 1;
 
512
                    if (glyph > 0xffff) {
 
513
                        ch[0] = QChar::highSurrogate(glyph);
 
514
                        ch[1] = QChar::lowSurrogate(glyph);
 
515
                        ++chrLen;
 
516
                    }
 
517
                    SIZE size = {0, 0};
 
518
                    GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
 
519
                    width = size.cx;
 
520
                } else if (ptrGetCharWidthI) {
 
521
                    ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
 
522
                }
 
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;
 
527
            }
 
528
        }
 
529
 
 
530
        if (oldFont)
 
531
            SelectObject(hdc, oldFont);
 
532
    }
 
533
}
 
534
 
 
535
glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
 
536
{
 
537
    if (glyphs.numGlyphs == 0)
 
538
        return glyph_metrics_t();
 
539
 
 
540
    QFixed w = 0;
 
541
    for (int i = 0; i < glyphs.numGlyphs; ++i)
 
542
        w += glyphs.effectiveAdvance(i);
 
543
 
 
544
    return glyph_metrics_t(0, -tm.tmAscent, w, tm.tmHeight, w, 0);
 
545
}
 
546
 
 
547
 
 
548
glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
 
549
{
 
550
#ifndef Q_WS_WINCE
 
551
    GLYPHMETRICS gm;
 
552
 
 
553
    HDC hdc = shared_dc();
 
554
    SelectObject(hdc, hfont);
 
555
    if (!ttf) {
 
556
        wchar_t ch = glyph;
 
557
        ABCFLOAT abc;
 
558
        GetCharABCWidthsFloat(hdc, ch, ch, &abc);
 
559
        int width = qRound(abc.abcfB);
 
560
 
 
561
        return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
 
562
    } else {
 
563
        DWORD res = 0;
 
564
        MAT2 mat;
 
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;
 
569
 
 
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
 
575
            XFORM xform;
 
576
            xform.eM11 = t.m11();
 
577
            xform.eM12 = t.m12();
 
578
            xform.eM21 = t.m21();
 
579
            xform.eM22 = t.m22();
 
580
            xform.eDx = 0;
 
581
            xform.eDy = 0;
 
582
            SetGraphicsMode(hdc, GM_ADVANCED);
 
583
            SetWorldTransform(hdc, &xform);
 
584
        }
 
585
 
 
586
        res = GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 0, &mat);
 
587
 
 
588
        if (t.type() > QTransform::TxTranslate) {
 
589
            XFORM xform;
 
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);
 
594
        }
 
595
 
 
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);
 
599
        }
 
600
    }
 
601
    return glyph_metrics_t();
 
602
#else
 
603
    HDC hdc = shared_dc();
 
604
    HGDIOBJ oldFont = SelectObject(hdc, hfont);
 
605
 
 
606
    ABC abc;
 
607
    int width;
 
608
    int advance;
 
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;
 
613
    }
 
614
    else
 
615
#endif
 
616
#if defined(GWES_MGRAST) || defined(GWES_MGRAST2)   // raster fonts
 
617
    if (GetCharWidth32(hdc, glyph, glyph, &width)) {
 
618
        advance = width;
 
619
    }
 
620
    else
 
621
#endif
 
622
    {   // fallback
 
623
        width = tm.tmMaxCharWidth;
 
624
        advance = width;
 
625
    }
 
626
 
 
627
    SelectObject(hdc, oldFont);
 
628
    return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
 
629
#endif
 
630
}
 
631
 
 
632
QFixed QFontEngineWin::ascent() const
 
633
{
 
634
    return tm.tmAscent;
 
635
}
 
636
 
 
637
QFixed QFontEngineWin::descent() const
 
638
{
 
639
    return tm.tmDescent;
 
640
}
 
641
 
 
642
QFixed QFontEngineWin::leading() const
 
643
{
 
644
    return tm.tmExternalLeading;
 
645
}
 
646
 
 
647
 
 
648
QFixed QFontEngineWin::xHeight() const
 
649
{
 
650
    if(x_height >= 0)
 
651
        return x_height;
 
652
    return QFontEngine::xHeight();
 
653
}
 
654
 
 
655
QFixed QFontEngineWin::averageCharWidth() const
 
656
{
 
657
    return tm.tmAveCharWidth;
 
658
}
 
659
 
 
660
qreal QFontEngineWin::maxCharWidth() const
 
661
{
 
662
    return tm.tmMaxCharWidth;
 
663
}
 
664
 
 
665
enum { max_font_count = 256 };
 
666
static const ushort char_table[] = {
 
667
        40,
 
668
        67,
 
669
        70,
 
670
        75,
 
671
        86,
 
672
        88,
 
673
        89,
 
674
        91,
 
675
        102,
 
676
        114,
 
677
        124,
 
678
        127,
 
679
        205,
 
680
        645,
 
681
        884,
 
682
        922,
 
683
        1070,
 
684
        12386,
 
685
        0
 
686
};
 
687
 
 
688
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
 
689
 
 
690
 
 
691
qreal QFontEngineWin::minLeftBearing() const
 
692
{
 
693
    if (lbearing == SHRT_MIN)
 
694
        minRightBearing(); // calculates both
 
695
 
 
696
    return lbearing;
 
697
}
 
698
 
 
699
qreal QFontEngineWin::minRightBearing() const
 
700
{
 
701
#ifdef Q_WS_WINCE
 
702
    if (rbearing == SHRT_MIN) {
 
703
        int ml = 0;
 
704
        int mr = 0;
 
705
        HDC hdc = shared_dc();
 
706
        SelectObject(hdc, hfont);
 
707
        if (ttf) {
 
708
            ABC *abc = 0;
 
709
            int n = tm.tmLastChar - tm.tmFirstChar;
 
710
            if (n <= max_font_count) {
 
711
                abc = new ABC[n+1];
 
712
                GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
 
713
            } else {
 
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;
 
718
            }
 
719
            ml = abc[0].abcA;
 
720
            mr = abc[0].abcC;
 
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);
 
725
                }
 
726
            }
 
727
            delete [] abc;
 
728
        }
 
729
        lbearing = ml;
 
730
        rbearing = mr;
 
731
    }
 
732
 
 
733
    return rbearing;
 
734
#else
 
735
    if (rbearing == SHRT_MIN) {
 
736
        int ml = 0;
 
737
        int mr = 0;
 
738
        HDC hdc = shared_dc();
 
739
        SelectObject(hdc, hfont);
 
740
        if (ttf) {
 
741
            ABC *abc = 0;
 
742
            int n = tm.tmLastChar - tm.tmFirstChar;
 
743
            if (n <= max_font_count) {
 
744
                abc = new ABC[n+1];
 
745
                GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
 
746
            } else {
 
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;
 
751
            }
 
752
            ml = abc[0].abcA;
 
753
            mr = abc[0].abcC;
 
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);
 
758
                }
 
759
            }
 
760
            delete [] abc;
 
761
        } else {
 
762
            ABCFLOAT *abc = 0;
 
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);
 
767
            } else {
 
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;
 
772
            }
 
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);
 
779
                }
 
780
            }
 
781
            ml = int(fml - 0.9999);
 
782
            mr = int(fmr - 0.9999);
 
783
            delete [] abc;
 
784
        }
 
785
        lbearing = ml;
 
786
        rbearing = mr;
 
787
    }
 
788
 
 
789
    return rbearing;
 
790
#endif
 
791
}
 
792
 
 
793
 
 
794
const char *QFontEngineWin::name() const
 
795
{
 
796
    return 0;
 
797
}
 
798
 
 
799
bool QFontEngineWin::canRender(const QChar *string,  int len)
 
800
{
 
801
    if (symbol) {
 
802
        for (int i = 0; i < len; ++i) {
 
803
            unsigned int uc = getChar(string, i, len);
 
804
            if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
 
805
                if (uc < 0x100) {
 
806
                    if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
 
807
                        return false;
 
808
                } else {
 
809
                    return false;
 
810
                }
 
811
            }
 
812
        }
 
813
    } else if (ttf) {
 
814
        for (int i = 0; i < len; ++i) {
 
815
            unsigned int uc = getChar(string, i, len);
 
816
            if (getTrueTypeGlyphIndex(cmap, uc) == 0)
 
817
                return false;
 
818
        }
 
819
    } else {
 
820
        while(len--) {
 
821
            if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
 
822
                return false;
 
823
        }
 
824
    }
 
825
    return true;
 
826
}
 
827
 
 
828
QFontEngine::Type QFontEngineWin::type() const
 
829
{
 
830
    return QFontEngine::Win;
 
831
}
 
832
 
 
833
static inline double qt_fixed_to_double(const FIXED &p) {
 
834
    return ((p.value << 16) + p.fract) / 65536.0;
 
835
}
 
836
 
 
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);
 
839
}
 
840
 
 
841
#ifndef GGO_UNHINTED
 
842
#define GGO_UNHINTED 0x0100
 
843
#endif
 
844
 
 
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)
 
847
{
 
848
#if defined(Q_WS_WINCE)
 
849
    Q_UNUSED(glyph);
 
850
    Q_UNUSED(hdc);
 
851
#endif
 
852
    MAT2 mat;
 
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;
 
858
 
 
859
    if (ttf)
 
860
        glyphFormat |= GGO_GLYPH_INDEX;
 
861
 
 
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);
 
867
#endif
 
868
    if ((DWORD)bufferSize == GDI_ERROR) {
 
869
        return false;
 
870
    }
 
871
 
 
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);
 
876
#endif
 
877
    if (ret == GDI_ERROR) {
 
878
        delete [](char *)dataBuffer;
 
879
        return false;
 
880
    }
 
881
 
 
882
    if(metric) {
 
883
        // #### obey scale
 
884
        *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
 
885
                                  (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
 
886
                                  gMetric.gmCellIncX, gMetric.gmCellIncY);
 
887
    }
 
888
 
 
889
    int offset = 0;
 
890
    int headerOffset = 0;
 
891
    TTPOLYGONHEADER *ttph = 0;
 
892
 
 
893
    QPointF oset = position.toPointF();
 
894
    while (headerOffset < bufferSize) {
 
895
        ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
 
896
 
 
897
        QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
 
898
        path->moveTo(lastPoint + oset);
 
899
        offset += sizeof(TTPOLYGONHEADER);
 
900
        TTPOLYCURVE *curve;
 
901
        while (offset<int(headerOffset + ttph->cb)) {
 
902
            curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
 
903
            switch (curve->wType) {
 
904
            case TT_PRIM_LINE: {
 
905
                for (int i=0; i<curve->cpfx; ++i) {
 
906
                    QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
 
907
                    path->lineTo(p);
 
908
                }
 
909
                break;
 
910
            }
 
911
            case TT_PRIM_QSPLINE: {
 
912
                const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
 
913
                QPointF prev(elm.x, elm.y);
 
914
                QPointF endPoint;
 
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);
 
920
                    } else {
 
921
                        endPoint = p2;
 
922
                    }
 
923
 
 
924
                    path->quadTo(p1, endPoint);
 
925
                    prev = endPoint;
 
926
                }
 
927
 
 
928
                break;
 
929
            }
 
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);
 
936
                }
 
937
                break;
 
938
            }
 
939
            default:
 
940
                qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
 
941
            }
 
942
            offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
 
943
        }
 
944
        path->closeSubpath();
 
945
        headerOffset += ttph->cb;
 
946
    }
 
947
    delete [] (char*)dataBuffer;
 
948
 
 
949
    return true;
 
950
}
 
951
 
 
952
void QFontEngineWin::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
 
953
                                     QPainterPath *path, QTextItem::RenderFlags)
 
954
{
 
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;
 
961
    lf.lfWidth = 0;
 
962
    HFONT hf = CreateFontIndirect(&lf);
 
963
    HDC hdc = shared_dc();
 
964
    HGDIOBJ oldfont = SelectObject(hdc, hf);
 
965
 
 
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...
 
973
            hasOutline = false;
 
974
            break;
 
975
        }
 
976
    }
 
977
    DeleteObject(SelectObject(hdc, oldfont));
 
978
}
 
979
 
 
980
void QFontEngineWin::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
 
981
                                      QPainterPath *path, QTextItem::RenderFlags flags)
 
982
{
 
983
#if !defined(Q_WS_WINCE)
 
984
    if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
 
985
        hasOutline = true;
 
986
        QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
 
987
        if (hasOutline)  {
 
988
            // has_outline is set to false if addGlyphToPath gets
 
989
            // false from GetGlyphOutline, meaning its not an outline
 
990
            // font.
 
991
            return;
 
992
        }
 
993
    }
 
994
#endif
 
995
    QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
 
996
}
 
997
 
 
998
QFontEngine::FaceId QFontEngineWin::faceId() const
 
999
{
 
1000
    return _faceId;
 
1001
}
 
1002
 
 
1003
QT_BEGIN_INCLUDE_NAMESPACE
 
1004
#include <qdebug.h>
 
1005
QT_END_INCLUDE_NAMESPACE
 
1006
 
 
1007
int QFontEngineWin::synthesized() const
 
1008
{
 
1009
    if(synthesized_flags == -1) {
 
1010
        synthesized_flags = 0;
 
1011
        if(ttf) {
 
1012
            const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
 
1013
            HDC hdc = shared_dc();
 
1014
            SelectObject(hdc, hfont);
 
1015
            uchar data[4];
 
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;
 
1026
        }
 
1027
    }
 
1028
    return synthesized_flags;
 
1029
}
 
1030
 
 
1031
QFixed QFontEngineWin::emSquareSize() const
 
1032
{
 
1033
    return unitsPerEm;
 
1034
}
 
1035
 
 
1036
QFontEngine::Properties QFontEngineWin::properties() const
 
1037
{
 
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);
 
1044
    Properties p;
 
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);
 
1051
#endif
 
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;
 
1058
    p.capHeight = 0;
 
1059
    p.lineWidth = otm->otmsUnderscoreSize;
 
1060
    free(otm);
 
1061
    DeleteObject(SelectObject(hdc, oldfont));
 
1062
    return p;
 
1063
}
 
1064
 
 
1065
void QFontEngineWin::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
 
1066
{
 
1067
    LOGFONT lf = logfont;
 
1068
    lf.lfHeight = unitsPerEm;
 
1069
    int flags = synthesized();
 
1070
    if(flags & SynthesizedItalic)
 
1071
        lf.lfItalic = false;
 
1072
    lf.lfWidth = 0;
 
1073
    HFONT hf = CreateFontIndirect(&lf);
 
1074
    HDC hdc = shared_dc();
 
1075
    HGDIOBJ oldfont = SelectObject(hdc, hf);
 
1076
    QFixedPoint p;
 
1077
    p.x = 0;
 
1078
    p.y = 0;
 
1079
    addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
 
1080
    DeleteObject(SelectObject(hdc, oldfont));
 
1081
}
 
1082
 
 
1083
bool QFontEngineWin::getSfntTableData(uint tag, uchar *buffer, uint *length) const
 
1084
{
 
1085
    if (!ttf)
 
1086
        return false;
 
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;
 
1092
}
 
1093
 
 
1094
#if !defined(CLEARTYPE_QUALITY)
 
1095
#    define CLEARTYPE_QUALITY       5
 
1096
#endif
 
1097
 
 
1098
extern bool qt_cleartype_enabled;
 
1099
 
 
1100
QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
 
1101
                                           const QTransform &t, QImage::Format mask_format)
 
1102
{
 
1103
    Q_UNUSED(mask_format)
 
1104
    glyph_metrics_t gm = boundingBox(glyph);
 
1105
 
 
1106
//     printf(" -> for glyph %4x\n", glyph);
 
1107
 
 
1108
    int gx = gm.x.toInt();
 
1109
    int gy = gm.y.toInt();
 
1110
    int iw = gm.width.toInt();
 
1111
    int ih = gm.height.toInt();
 
1112
 
 
1113
    if (iw <= 0 || iw <= 0)
 
1114
        return 0;
 
1115
 
 
1116
    bool has_transformation = t.type() > QTransform::TxTranslate;
 
1117
 
 
1118
#ifndef Q_WS_WINCE
 
1119
    unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
 
1120
    XFORM xform;
 
1121
 
 
1122
    if (has_transformation) {
 
1123
        xform.eM11 = t.m11();
 
1124
        xform.eM12 = t.m12();
 
1125
        xform.eM21 = t.m21();
 
1126
        xform.eM22 = t.m22();
 
1127
        xform.eDx = margin;
 
1128
        xform.eDy = margin;
 
1129
 
 
1130
        QtHDC qthdc;
 
1131
        HDC hdc = qthdc.hdc();
 
1132
 
 
1133
        SetGraphicsMode(hdc, GM_ADVANCED);
 
1134
        SetWorldTransform(hdc, &xform);
 
1135
        HGDIOBJ old_font = SelectObject(hdc, font);
 
1136
 
 
1137
        int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
 
1138
        GLYPHMETRICS tgm;
 
1139
        MAT2 mat;
 
1140
        memset(&mat, 0, sizeof(mat));
 
1141
        mat.eM11.value = mat.eM22.value = 1;
 
1142
 
 
1143
        if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
 
1144
            qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
 
1145
            return 0;
 
1146
        }
 
1147
 
 
1148
        iw = tgm.gmBlackBoxX;
 
1149
        ih = tgm.gmBlackBoxY;
 
1150
 
 
1151
        xform.eDx -= tgm.gmptGlyphOrigin.x;
 
1152
        xform.eDy += tgm.gmptGlyphOrigin.y;
 
1153
 
 
1154
        SetGraphicsMode(hdc, GM_COMPATIBLE);
 
1155
        SelectObject(hdc, old_font);
 
1156
    }
 
1157
#else // else winc
 
1158
    unsigned int options = 0;
 
1159
#ifdef DEBUG
 
1160
    Q_ASSERT(!has_transformation);
 
1161
#else
 
1162
    Q_UNUSED(has_transformation);
 
1163
#endif
 
1164
#endif
 
1165
 
 
1166
    QNativeImage *ni = new QNativeImage(iw + 2 * margin + 4,
 
1167
                                        ih + 2 * margin + 4,
 
1168
                                        QNativeImage::systemFormat(), !qt_cleartype_enabled);
 
1169
 
 
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*/
 
1172
 
 
1173
    ni->image.fill(0xffffffff);
 
1174
 
 
1175
    HDC hdc = ni->hdc;
 
1176
 
 
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);
 
1182
 
 
1183
    HGDIOBJ old_font = SelectObject(hdc, font);
 
1184
 
 
1185
#ifndef Q_OS_WINCE
 
1186
    if (has_transformation) {
 
1187
        SetGraphicsMode(hdc, GM_ADVANCED);
 
1188
        SetWorldTransform(hdc, &xform);
 
1189
        ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
 
1190
    } else
 
1191
#endif
 
1192
    {
 
1193
        ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
 
1194
    }
 
1195
 
 
1196
    SelectObject(hdc, old_font);
 
1197
    return ni;
 
1198
}
 
1199
 
 
1200
 
 
1201
extern uint qt_pow_gamma[256];
 
1202
 
 
1203
QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
 
1204
{
 
1205
    HFONT font = hfont;
 
1206
    if (qt_cleartype_enabled) {
 
1207
        LOGFONT lf = logfont;
 
1208
        lf.lfQuality = ANTIALIASED_QUALITY;
 
1209
        font = CreateFontIndirect(&lf);
 
1210
    }
 
1211
    QImage::Format mask_format = QNativeImage::systemFormat();
 
1212
#ifndef Q_OS_WINCE
 
1213
    mask_format = QImage::Format_RGB32;
 
1214
#endif
 
1215
 
 
1216
    QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
 
1217
    if (mask == 0)
 
1218
        return QImage();
 
1219
 
 
1220
    QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
 
1221
 
 
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);
 
1228
 
 
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]);
 
1237
        } else {
 
1238
            const uint *src = (uint *) ((const QImage &) mask->image).scanLine(y);
 
1239
            for (int x=0; x<mask->width(); ++x) {
 
1240
#ifdef Q_OS_WINCE
 
1241
                dest[x] = 255 - qGray(src[x]);
 
1242
#else
 
1243
                if (QNativeImage::systemFormat() == QImage::Format_RGB16)
 
1244
                    dest[x] = 255 - qGray(src[x]);
 
1245
                else
 
1246
                    dest[x] = 255 - (qt_pow_gamma[qGray(src[x])] * 255. / 2047.);
 
1247
#endif
 
1248
            }
 
1249
        }
 
1250
    }
 
1251
 
 
1252
    // Cleanup...
 
1253
    delete mask;
 
1254
    if (qt_cleartype_enabled) {
 
1255
        DeleteObject(font);
 
1256
    }
 
1257
 
 
1258
    return indexed;
 
1259
}
 
1260
 
 
1261
#define SPI_GETFONTSMOOTHINGCONTRAST           0x200C
 
1262
#define SPI_SETFONTSMOOTHINGCONTRAST           0x200D
 
1263
 
 
1264
QImage QFontEngineWin::alphaRGBMapForGlyph(glyph_t glyph, int margin, const QTransform &t)
 
1265
{
 
1266
    HFONT font = hfont;
 
1267
 
 
1268
    int contrast;
 
1269
    SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
 
1270
    SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
 
1271
 
 
1272
    QNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
 
1273
    SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
 
1274
 
 
1275
    if (mask == 0)
 
1276
        return QImage();
 
1277
 
 
1278
    // Gracefully handle the odd case when the display is 16-bit
 
1279
    const QImage source = mask->image.depth() == 32
 
1280
                          ? mask->image
 
1281
                          : mask->image.convertToFormat(QImage::Format_RGB32);
 
1282
 
 
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]);
 
1289
        }
 
1290
    }
 
1291
 
 
1292
    delete mask;
 
1293
 
 
1294
    return rgbMask;
 
1295
}
 
1296
 
 
1297
// -------------------------------------- Multi font engine
 
1298
 
 
1299
QFontEngineMultiWin::QFontEngineMultiWin(QFontEngineWin *first, const QStringList &fallbacks)
 
1300
        : QFontEngineMulti(fallbacks.size()+1),
 
1301
          fallbacks(fallbacks)
 
1302
{
 
1303
    engines[0] = first;
 
1304
    first->ref.ref();
 
1305
    fontDef = engines[0]->fontDef;
 
1306
}
 
1307
 
 
1308
void QFontEngineMultiWin::loadEngine(int at)
 
1309
{
 
1310
    Q_ASSERT(at < engines.size());
 
1311
    Q_ASSERT(engines.at(at) == 0);
 
1312
 
 
1313
    QString fam = fallbacks.at(at-1);
 
1314
 
 
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);
 
1318
 
 
1319
    bool stockFont = false;
 
1320
    if (hfont == 0) {
 
1321
        hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
 
1322
        stockFont = true;
 
1323
    }
 
1324
    engines[at] = new QFontEngineWin(fam, hfont, stockFont, lf);
 
1325
    engines[at]->ref.ref();
 
1326
    engines[at]->fontDef = fontDef;
 
1327
}
 
1328
 
 
1329
QT_END_NAMESPACE