1 /****************************************************************************
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #if _WIN32_WINNT < 0x0500
44 #define _WIN32_WINNT 0x0500
47 #include "qfontengine_p.h"
48 #include "qtextengine_p.h"
50 #include "qt_windows.h"
51 #include <private/qapplication_p.h>
53 #include <private/qsystemlibrary_p.h>
54 #include <qpaintdevice.h>
60 #include <qthreadstorage.h>
62 #include <private/qunicodetables_p.h>
65 #include <private/qpainter_p.h>
66 #include "qpaintengine.h"
67 #include "qvarlengtharray.h"
68 #include <private/qpaintengine_raster_p.h>
69 #include <private/qnativeimage_p.h>
71 #if defined(Q_WS_WINCE)
72 #include "qguifunctions_wince.h"
75 //### mingw needed define
76 #ifndef TT_PRIM_CSPLINE
77 #define TT_PRIM_CSPLINE 3
83 // GetFontData expects the tags in little endian ;(
84 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
85 (((quint32)(ch4)) << 24) | \
86 (((quint32)(ch3)) << 16) | \
87 (((quint32)(ch2)) << 8) | \
91 // common DC for all fonts
101 HDC displayDC = GetDC(0);
102 _hdc = CreateCompatibleDC(displayDC);
103 ReleaseDC(0, displayDC);
117 Q_GLOBAL_STATIC(QThreadStorage<QtHDC *>, local_shared_dc)
120 QtHDC *&hdc = local_shared_dc()->localData();
133 typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
134 static PtrGetCharWidthI ptrGetCharWidthI = 0;
135 static bool resolvedGetCharWidthI = false;
137 static void resolveGetCharWidthI()
139 if (resolvedGetCharWidthI)
141 resolvedGetCharWidthI = true;
142 ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
144 #endif // !defined(Q_WS_WINCE)
146 // defined in qtextengine_win.cpp
147 typedef void *SCRIPT_CACHE;
148 typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
149 extern fScriptFreeCache ScriptFreeCache;
151 static inline quint32 getUInt(unsigned char *p)
162 static inline quint16 getUShort(unsigned char *p)
171 // general font engine
173 QFixed QFontEngineWin::lineThickness() const
178 return QFontEngine::lineThickness();
181 static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
184 size = GetOutlineTextMetrics(hdc, 0, 0);
185 OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
186 GetOutlineTextMetrics(hdc, size, otm);
190 void QFontEngineWin::getCMap()
192 ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
193 HDC hdc = shared_dc();
194 SelectObject(hdc, hfont);
197 cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
199 cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
200 cmapTable.size(), &symb, &size);
210 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
211 designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
212 unitsPerEm = otm->otmEMSquare;
213 x_height = (int)otm->otmsXHeight;
214 loadKerningPairs(designToDevice);
215 _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
216 lineWidth = otm->otmsUnderscoreSize;
217 fsType = otm->otmfsType;
220 unitsPerEm = tm.tmHeight;
225 inline unsigned int getChar(const QChar *str, int &i, const int len)
227 unsigned int uc = str[i].unicode();
228 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
229 uint low = str[i+1].unicode();
230 if (low >= 0xdc00 && low < 0xe000) {
231 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
238 int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
243 #if defined(Q_WS_WINCE)
247 for (; i < numChars; ++i, ++glyph_pos) {
248 unsigned int uc = getChar(str, i, numChars);
249 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
250 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
251 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
254 for (; i < numChars; ++i, ++glyph_pos) {
255 unsigned int uc = getChar(str, i, numChars);
256 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
260 wchar_t first = tm.tmFirstChar;
261 wchar_t last = tm.tmLastChar;
263 for (; i < numChars; ++i, ++glyph_pos) {
264 uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
267 tm.tmFirstChar > 60000 || // see line 375
269 ucs >= first && ucs <= last)
270 glyphs->glyphs[glyph_pos] = ucs;
272 glyphs->glyphs[glyph_pos] = 0;
276 #if defined(Q_WS_WINCE)
280 for (; i < numChars; ++i, ++glyph_pos) {
281 unsigned int uc = getChar(str, i, numChars);
282 glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
283 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
284 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
287 for (; i < numChars; ++i, ++glyph_pos) {
288 unsigned int uc = getChar(str, i, numChars);
289 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
293 wchar_t first = tm.tmFirstChar;
294 wchar_t last = tm.tmLastChar;
296 for (; i < numChars; ++i, ++glyph_pos) {
297 uint uc = getChar(str, i, numChars);
300 tm.tmFirstChar > 60000 || // see comment in QFontEngineWin
302 uc >= first && uc <= last)
303 glyphs->glyphs[glyph_pos] = uc;
305 glyphs->glyphs[glyph_pos] = 0;
309 glyphs->numGlyphs = glyph_pos;
314 QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf)
316 //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight);
323 HDC hdc = shared_dc();
324 SelectObject(hdc, hfont);
325 this->stockFont = stockFont;
326 fontDef.pixelSize = -lf.lfHeight;
330 synthesized_flags = -1;
334 BOOL res = GetTextMetrics(hdc, &tm);
335 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
337 qErrnoWarning("QFontEngineWin: GetTextMetrics failed");
338 ZeroMemory(&tm, sizeof(TEXTMETRIC));
341 cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
347 designAdvancesSize = 0;
350 if (!resolvedGetCharWidthI)
351 resolveGetCharWidthI();
355 QFontEngineWin::~QFontEngineWin()
358 free(designAdvances);
363 // make sure we aren't by accident still selected
364 SelectObject(shared_dc(), (HFONT)GetStockObject(SYSTEM_FONT));
367 if (!DeleteObject(hfont))
368 qErrnoWarning("QFontEngineWin: failed to delete non-stock font...");
372 HGDIOBJ QFontEngineWin::selectDesignFont() const
375 f.lfHeight = unitsPerEm;
376 HFONT designFont = CreateFontIndirect(&f);
377 return SelectObject(shared_dc(), designFont);
380 bool QFontEngineWin::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
382 if (*nglyphs < len) {
387 *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
389 if (flags & QTextEngine::GlyphIndicesOnly)
392 recalcAdvances(glyphs, flags);
396 inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
398 #if defined(Q_WS_WINCE)
399 GetCharWidth32(hdc, glyph, glyph, &width);
401 if (ptrGetCharWidthI)
402 ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
406 void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
409 HDC hdc = shared_dc();
410 if (ttf && (flags & QTextEngine::DesignMetrics)) {
411 for(int i = 0; i < glyphs->numGlyphs; i++) {
412 unsigned int glyph = glyphs->glyphs[i];
413 if(int(glyph) >= designAdvancesSize) {
414 int newSize = (glyph + 256) >> 8 << 8;
415 designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
416 newSize*sizeof(QFixed)));
417 for(int i = designAdvancesSize; i < newSize; ++i)
418 designAdvances[i] = -1000000;
419 designAdvancesSize = newSize;
421 if (designAdvances[glyph] < -999999) {
423 oldFont = selectDesignFont();
426 calculateTTFGlyphWidth(hdc, glyph, width);
427 designAdvances[glyph] = QFixed(width) / designToDevice;
429 glyphs->advances_x[i] = designAdvances[glyph];
430 glyphs->advances_y[i] = 0;
433 DeleteObject(SelectObject(hdc, oldFont));
435 for(int i = 0; i < glyphs->numGlyphs; i++) {
436 unsigned int glyph = glyphs->glyphs[i];
438 glyphs->advances_y[i] = 0;
440 if (glyph >= widthCacheSize) {
441 int newSize = (glyph + 256) >> 8 << 8;
442 widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
443 newSize*sizeof(QFixed)));
444 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
445 widthCacheSize = newSize;
447 glyphs->advances_x[i] = widthCache[glyph];
448 // font-width cache failed
449 if (glyphs->advances_x[i] == 0) {
452 oldFont = SelectObject(hdc, hfont);
455 QChar ch[2] = { ushort(glyph), 0 };
457 if (glyph > 0xffff) {
458 ch[0] = QChar::highSurrogate(glyph);
459 ch[1] = QChar::lowSurrogate(glyph);
463 GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
466 calculateTTFGlyphWidth(hdc, glyph, width);
468 glyphs->advances_x[i] = width;
469 // if glyph's within cache range, store it for later
470 if (width > 0 && width < 0x100)
471 widthCache[glyph] = width;
476 SelectObject(hdc, oldFont);
480 glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
482 if (glyphs.numGlyphs == 0)
483 return glyph_metrics_t();
486 for (int i = 0; i < glyphs.numGlyphs; ++i)
487 w += glyphs.effectiveAdvance(i);
489 return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
493 bool QFontEngineWin::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
495 Q_ASSERT(metrics != 0);
497 HDC hdc = shared_dc();
502 mat.eM11.value = mat.eM22.value = 1;
503 mat.eM11.fract = mat.eM22.fract = 0;
504 mat.eM21.value = mat.eM12.value = 0;
505 mat.eM21.fract = mat.eM12.fract = 0;
507 if (t.type() > QTransform::TxTranslate) {
508 // We need to set the transform using the HDC's world
509 // matrix rather than using the MAT2 above, because the
510 // results provided when transforming via MAT2 does not
511 // match the glyphs that are drawn using a WorldTransform
513 xform.eM11 = t.m11();
514 xform.eM12 = t.m12();
515 xform.eM21 = t.m21();
516 xform.eM22 = t.m22();
519 SetGraphicsMode(hdc, GM_ADVANCED);
520 SetWorldTransform(hdc, &xform);
523 uint format = GGO_METRICS;
525 format |= GGO_GLYPH_INDEX;
526 res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
528 if (t.type() > QTransform::TxTranslate) {
530 xform.eM11 = xform.eM22 = 1;
531 xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
532 SetWorldTransform(hdc, &xform);
533 SetGraphicsMode(hdc, GM_COMPATIBLE);
536 if (res != GDI_ERROR) {
537 *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
538 (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
546 glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
549 HDC hdc = shared_dc();
550 SelectObject(hdc, hfont);
552 glyph_metrics_t glyphMetrics;
553 bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
555 if (!ttf && !success) {
559 GetCharABCWidthsFloat(hdc, ch, ch, &abc);
560 int width = qRound(abc.abcfB);
562 return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
567 HDC hdc = shared_dc();
568 HGDIOBJ oldFont = SelectObject(hdc, hfont);
573 #ifdef GWES_MGTT // true type fonts
574 if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
575 width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
576 advance = abc.abcA + abc.abcB + abc.abcC;
580 #if defined(GWES_MGRAST) || defined(GWES_MGRAST2) // raster fonts
581 if (GetCharWidth32(hdc, glyph, glyph, &width)) {
587 width = tm.tmMaxCharWidth;
591 SelectObject(hdc, oldFont);
592 return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
596 QFixed QFontEngineWin::ascent() const
601 QFixed QFontEngineWin::descent() const
603 // ### we substract 1 to even out the historical +1 in QFontMetrics's
604 // ### height=asc+desc+1 equation. Fix in Qt5.
605 return tm.tmDescent - 1;
608 QFixed QFontEngineWin::leading() const
610 return tm.tmExternalLeading;
614 QFixed QFontEngineWin::xHeight() const
618 return QFontEngine::xHeight();
621 QFixed QFontEngineWin::averageCharWidth() const
623 return tm.tmAveCharWidth;
626 qreal QFontEngineWin::maxCharWidth() const
628 return tm.tmMaxCharWidth;
631 enum { max_font_count = 256 };
632 static const ushort char_table[] = {
654 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
657 void QFontEngineWin::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
659 HDC hdc = shared_dc();
660 SelectObject(hdc, hfont);
668 GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
670 *leftBearing = abcWidths.abcA;
672 *rightBearing = abcWidths.abcC;
677 QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
683 qreal QFontEngineWin::minLeftBearing() const
685 if (lbearing == SHRT_MIN)
686 minRightBearing(); // calculates both
691 qreal QFontEngineWin::minRightBearing() const
694 if (rbearing == SHRT_MIN) {
697 HDC hdc = shared_dc();
698 SelectObject(hdc, hfont);
701 int n = tm.tmLastChar - tm.tmFirstChar;
702 if (n <= max_font_count) {
704 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
706 abc = new ABC[char_table_entries+1];
707 for(int i = 0; i < char_table_entries; i++)
708 GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
709 n = char_table_entries;
713 for (int i = 1; i < n; i++) {
714 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
715 ml = qMin(ml,abc[i].abcA);
716 mr = qMin(mr,abc[i].abcC);
727 if (rbearing == SHRT_MIN) {
730 HDC hdc = shared_dc();
731 SelectObject(hdc, hfont);
734 int n = tm.tmLastChar - tm.tmFirstChar;
735 if (n <= max_font_count) {
737 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
739 abc = new ABC[char_table_entries+1];
740 for(int i = 0; i < char_table_entries; i++)
741 GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
742 n = char_table_entries;
746 for (int i = 1; i < n; i++) {
747 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
748 ml = qMin(ml,abc[i].abcA);
749 mr = qMin(mr,abc[i].abcC);
755 int n = tm.tmLastChar - tm.tmFirstChar+1;
756 if (n <= max_font_count) {
757 abc = new ABCFLOAT[n];
758 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
760 abc = new ABCFLOAT[char_table_entries];
761 for(int i = 0; i < char_table_entries; i++)
762 GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
763 n = char_table_entries;
765 float fml = abc[0].abcfA;
766 float fmr = abc[0].abcfC;
767 for (int i=1; i<n; i++) {
768 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
769 fml = qMin(fml,abc[i].abcfA);
770 fmr = qMin(fmr,abc[i].abcfC);
773 ml = int(fml - 0.9999);
774 mr = int(fmr - 0.9999);
786 const char *QFontEngineWin::name() const
791 bool QFontEngineWin::canRender(const QChar *string, int len)
794 for (int i = 0; i < len; ++i) {
795 unsigned int uc = getChar(string, i, len);
796 if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
798 if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
806 for (int i = 0; i < len; ++i) {
807 unsigned int uc = getChar(string, i, len);
808 if (getTrueTypeGlyphIndex(cmap, uc) == 0)
813 if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
820 QFontEngine::Type QFontEngineWin::type() const
822 return QFontEngine::Win;
825 static inline double qt_fixed_to_double(const FIXED &p) {
826 return ((p.value << 16) + p.fract) / 65536.0;
829 static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
830 return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
834 #define GGO_UNHINTED 0x0100
837 static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
838 QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
840 #if defined(Q_WS_WINCE)
845 mat.eM11.value = mat.eM22.value = 1;
846 mat.eM11.fract = mat.eM22.fract = 0;
847 mat.eM21.value = mat.eM12.value = 0;
848 mat.eM21.fract = mat.eM12.fract = 0;
849 uint glyphFormat = GGO_NATIVE;
852 glyphFormat |= GGO_GLYPH_INDEX;
854 GLYPHMETRICS gMetric;
855 memset(&gMetric, 0, sizeof(GLYPHMETRICS));
856 int bufferSize = GDI_ERROR;
857 #if !defined(Q_WS_WINCE)
858 bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
860 if ((DWORD)bufferSize == GDI_ERROR) {
864 void *dataBuffer = new char[bufferSize];
865 DWORD ret = GDI_ERROR;
866 #if !defined(Q_WS_WINCE)
867 ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
869 if (ret == GDI_ERROR) {
870 delete [](char *)dataBuffer;
876 *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
877 (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
878 gMetric.gmCellIncX, gMetric.gmCellIncY);
882 int headerOffset = 0;
883 TTPOLYGONHEADER *ttph = 0;
885 QPointF oset = position.toPointF();
886 while (headerOffset < bufferSize) {
887 ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
889 QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
890 path->moveTo(lastPoint + oset);
891 offset += sizeof(TTPOLYGONHEADER);
893 while (offset<int(headerOffset + ttph->cb)) {
894 curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
895 switch (curve->wType) {
897 for (int i=0; i<curve->cpfx; ++i) {
898 QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
903 case TT_PRIM_QSPLINE: {
904 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
905 QPointF prev(elm.x, elm.y);
907 for (int i=0; i<curve->cpfx - 1; ++i) {
908 QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
909 QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
910 if (i < curve->cpfx - 2) {
911 endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
916 path->quadTo(p1, endPoint);
922 case TT_PRIM_CSPLINE: {
923 for (int i=0; i<curve->cpfx; ) {
924 QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
925 QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
926 QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
927 path->cubicTo(p2, p3, p4);
932 qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
934 offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
936 path->closeSubpath();
937 headerOffset += ttph->cb;
939 delete [] (char*)dataBuffer;
944 void QFontEngineWin::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
945 QPainterPath *path, QTextItem::RenderFlags)
947 LOGFONT lf = logfont;
948 // The sign must be negative here to make sure we match against character height instead of
949 // hinted cell height. This ensures that we get linear matching, and we need this for
950 // paths since we later on apply a scaling transform to the glyph outline to get the
951 // font at the correct pixel size.
952 lf.lfHeight = -unitsPerEm;
954 HFONT hf = CreateFontIndirect(&lf);
955 HDC hdc = shared_dc();
956 HGDIOBJ oldfont = SelectObject(hdc, hf);
958 for(int i = 0; i < nglyphs; ++i) {
959 if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
960 qreal(fontDef.pixelSize) / unitsPerEm)) {
961 // Some windows fonts, like "Modern", are vector stroke
962 // fonts, which are reported as TMPF_VECTOR but do not
963 // support GetGlyphOutline, and thus we set this bit so
964 // that addOutLineToPath can check it and return safely...
969 DeleteObject(SelectObject(hdc, oldfont));
972 void QFontEngineWin::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
973 QPainterPath *path, QTextItem::RenderFlags flags)
975 #if !defined(Q_WS_WINCE)
976 if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
978 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
980 // has_outline is set to false if addGlyphToPath gets
981 // false from GetGlyphOutline, meaning its not an outline
987 QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
990 QFontEngine::FaceId QFontEngineWin::faceId() const
995 QT_BEGIN_INCLUDE_NAMESPACE
997 QT_END_INCLUDE_NAMESPACE
999 int QFontEngineWin::synthesized() const
1001 if(synthesized_flags == -1) {
1002 synthesized_flags = 0;
1004 const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
1005 HDC hdc = shared_dc();
1006 SelectObject(hdc, hfont);
1008 GetFontData(hdc, HEAD, 44, &data, 4);
1009 USHORT macStyle = getUShort(data);
1010 if (tm.tmItalic && !(macStyle & 2))
1011 synthesized_flags = SynthesizedItalic;
1012 if (fontDef.stretch != 100 && ttf)
1013 synthesized_flags |= SynthesizedStretch;
1014 if (tm.tmWeight >= 500 && !(macStyle & 1))
1015 synthesized_flags |= SynthesizedBold;
1016 //qDebug() << "font is" << _name <<
1017 // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
1020 return synthesized_flags;
1023 QFixed QFontEngineWin::emSquareSize() const
1028 QFontEngine::Properties QFontEngineWin::properties() const
1030 LOGFONT lf = logfont;
1031 lf.lfHeight = unitsPerEm;
1032 HFONT hf = CreateFontIndirect(&lf);
1033 HDC hdc = shared_dc();
1034 HGDIOBJ oldfont = SelectObject(hdc, hf);
1035 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
1037 p.emSquare = unitsPerEm;
1038 p.italicAngle = otm->otmItalicAngle;
1039 p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
1040 p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
1041 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
1042 p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
1043 otm->otmrcFontBox.right - otm->otmrcFontBox.left,
1044 otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
1045 p.ascent = otm->otmAscent;
1046 p.descent = -otm->otmDescent;
1047 p.leading = (int)otm->otmLineGap;
1049 p.lineWidth = otm->otmsUnderscoreSize;
1051 DeleteObject(SelectObject(hdc, oldfont));
1055 void QFontEngineWin::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1057 LOGFONT lf = logfont;
1058 lf.lfHeight = unitsPerEm;
1059 int flags = synthesized();
1060 if(flags & SynthesizedItalic)
1061 lf.lfItalic = false;
1063 HFONT hf = CreateFontIndirect(&lf);
1064 HDC hdc = shared_dc();
1065 HGDIOBJ oldfont = SelectObject(hdc, hf);
1069 addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
1070 DeleteObject(SelectObject(hdc, oldfont));
1073 bool QFontEngineWin::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1077 HDC hdc = shared_dc();
1078 SelectObject(hdc, hfont);
1079 DWORD t = qbswap<quint32>(tag);
1080 *length = GetFontData(hdc, t, 0, buffer, *length);
1081 return *length != GDI_ERROR;
1084 #if !defined(CLEARTYPE_QUALITY)
1085 # define CLEARTYPE_QUALITY 5
1088 extern bool qt_cleartype_enabled;
1090 QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
1091 const QTransform &t, QImage::Format mask_format)
1093 Q_UNUSED(mask_format)
1094 glyph_metrics_t gm = boundingBox(glyph);
1096 // printf(" -> for glyph %4x\n", glyph);
1098 int gx = gm.x.toInt();
1099 int gy = gm.y.toInt();
1100 int iw = gm.width.toInt();
1101 int ih = gm.height.toInt();
1103 if (iw <= 0 || iw <= 0)
1106 bool has_transformation = t.type() > QTransform::TxTranslate;
1109 unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
1112 if (has_transformation) {
1113 xform.eM11 = t.m11();
1114 xform.eM12 = t.m12();
1115 xform.eM21 = t.m21();
1116 xform.eM22 = t.m22();
1121 HDC hdc = qthdc.hdc();
1123 SetGraphicsMode(hdc, GM_ADVANCED);
1124 SetWorldTransform(hdc, &xform);
1125 HGDIOBJ old_font = SelectObject(hdc, font);
1127 int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
1130 memset(&mat, 0, sizeof(mat));
1131 mat.eM11.value = mat.eM22.value = 1;
1133 if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
1134 qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
1138 iw = tgm.gmBlackBoxX;
1139 ih = tgm.gmBlackBoxY;
1141 xform.eDx -= tgm.gmptGlyphOrigin.x;
1142 xform.eDy += tgm.gmptGlyphOrigin.y;
1144 SetGraphicsMode(hdc, GM_COMPATIBLE);
1145 SelectObject(hdc, old_font);
1148 unsigned int options = 0;
1150 Q_ASSERT(!has_transformation);
1152 Q_UNUSED(has_transformation);
1156 QNativeImage *ni = new QNativeImage(iw + 2 * margin + 4,
1157 ih + 2 * margin + 4,
1158 QNativeImage::systemFormat(), !qt_cleartype_enabled);
1160 /*If cleartype is enabled we use the standard system format even on Windows CE
1161 and not the special textbuffer format we have to use if cleartype is disabled*/
1163 ni->image.fill(0xffffffff);
1167 SelectObject(hdc, GetStockObject(NULL_BRUSH));
1168 SelectObject(hdc, GetStockObject(BLACK_PEN));
1169 SetTextColor(hdc, RGB(0,0,0));
1170 SetBkMode(hdc, TRANSPARENT);
1171 SetTextAlign(hdc, TA_BASELINE);
1173 HGDIOBJ old_font = SelectObject(hdc, font);
1176 if (has_transformation) {
1177 SetGraphicsMode(hdc, GM_ADVANCED);
1178 SetWorldTransform(hdc, &xform);
1179 ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
1183 ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
1186 SelectObject(hdc, old_font);
1191 extern uint qt_pow_gamma[256];
1193 QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
1196 if (qt_cleartype_enabled) {
1197 LOGFONT lf = logfont;
1198 lf.lfQuality = ANTIALIASED_QUALITY;
1199 font = CreateFontIndirect(&lf);
1201 QImage::Format mask_format = QNativeImage::systemFormat();
1203 mask_format = QImage::Format_RGB32;
1206 QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1210 QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
1212 // ### This part is kinda pointless, but we'll crash later if we don't because some
1213 // code paths expects there to be colortables for index8-bit...
1214 QVector<QRgb> colors(256);
1215 for (int i=0; i<256; ++i)
1216 colors[i] = qRgba(0, 0, 0, i);
1217 indexed.setColorTable(colors);
1219 // Copy data... Cannot use QPainter here as GDI has messed up the
1220 // Alpha channel of the ni.image pixels...
1221 for (int y=0; y<mask->height(); ++y) {
1222 uchar *dest = indexed.scanLine(y);
1223 if (mask->image.format() == QImage::Format_RGB16) {
1224 const qint16 *src = (qint16 *) ((const QImage &) mask->image).scanLine(y);
1225 for (int x=0; x<mask->width(); ++x)
1226 dest[x] = 255 - qGray(src[x]);
1228 const uint *src = (uint *) ((const QImage &) mask->image).scanLine(y);
1229 for (int x=0; x<mask->width(); ++x) {
1231 dest[x] = 255 - qGray(src[x]);
1233 if (QNativeImage::systemFormat() == QImage::Format_RGB16)
1234 dest[x] = 255 - qGray(src[x]);
1236 dest[x] = 255 - (qt_pow_gamma[qGray(src[x])] * 255. / 2047.);
1244 if (qt_cleartype_enabled) {
1251 #define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1252 #define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1254 QImage QFontEngineWin::alphaRGBMapForGlyph(glyph_t glyph, QFixed, int margin, const QTransform &t)
1259 SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1260 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
1262 QNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1263 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
1268 // Gracefully handle the odd case when the display is 16-bit
1269 const QImage source = mask->image.depth() == 32
1271 : mask->image.convertToFormat(QImage::Format_RGB32);
1273 QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1274 for (int y=0; y<mask->height(); ++y) {
1275 uint *dest = (uint *) rgbMask.scanLine(y);
1276 const uint *src = (uint *) source.scanLine(y);
1277 for (int x=0; x<mask->width(); ++x) {
1278 dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1287 // From qfontdatabase_win.cpp
1288 extern QFontEngine *qt_load_font_engine_win(const QFontDef &request);
1289 QFontEngine *QFontEngineWin::cloneWithSize(qreal pixelSize) const
1291 QFontDef request = fontDef;
1292 QString actualFontName = request.family;
1293 if (!uniqueFamilyName.isEmpty())
1294 request.family = uniqueFamilyName;
1295 request.pixelSize = pixelSize;
1297 QFontEngine *fontEngine = qt_load_font_engine_win(request);
1298 if (fontEngine != NULL)
1299 fontEngine->fontDef.family = actualFontName;
1304 // -------------------------------------- Multi font engine
1306 QFontEngineMultiWin::QFontEngineMultiWin(QFontEngine *first, const QStringList &fallbacks)
1307 : QFontEngineMulti(fallbacks.size()+1),
1308 fallbacks(fallbacks)
1312 fontDef = engines[0]->fontDef;
1313 cache_cost = first->cache_cost;
1316 void QFontEngineMultiWin::loadEngine(int at)
1318 Q_ASSERT(at < engines.size());
1319 Q_ASSERT(engines.at(at) == 0);
1321 QString fam = fallbacks.at(at-1);
1323 LOGFONT lf = static_cast<QFontEngineWin *>(engines.at(0))->logfont;
1324 memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
1325 HFONT hfont = CreateFontIndirect(&lf);
1327 bool stockFont = false;
1329 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1332 engines[at] = new QFontEngineWin(fam, hfont, stockFont, lf);
1333 engines[at]->ref.ref();
1334 engines[at]->fontDef = fontDef;
1336 // TODO: increase cost in QFontCache for the font engine loaded here