1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #if _WIN32_WINNT < 0x0500
44 #define _WIN32_WINNT 0x0500
47 #include "qwindowsintegration.h"
48 #include "qwindowsfontengine.h"
49 #include "qwindowsnativeimage.h"
50 #include "qwindowscontext.h"
51 #include "qwindowsfontdatabase.h"
52 #include "qtwindows_additional.h"
54 #include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
55 #include <QtGui/private/qguiapplication_p.h>
56 #include <QtGui/QPaintDevice>
57 #include <QtGui/QBitmap>
58 #include <QtGui/QPainter>
59 #include <QtGui/private/qpainter_p.h>
60 #include <QtGui/QPaintEngine>
61 #include <QtGui/private/qpaintengine_raster_p.h>
63 #include <QtCore/QtEndian>
64 #include <QtCore/qmath.h>
65 #include <QtCore/QThreadStorage>
66 #include <QtCore/private/qsystemlibrary_p.h>
68 #include <QtCore/private/qunicodetables_p.h>
69 #include <QtCore/QDebug>
74 # include "qplatformfunctions_wince.h"
79 //### mingw needed define
80 #ifndef TT_PRIM_CSPLINE
81 #define TT_PRIM_CSPLINE 3
87 // GetFontData expects the tags in little endian ;(
88 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
89 (((quint32)(ch4)) << 24) | \
90 (((quint32)(ch3)) << 16) | \
91 (((quint32)(ch2)) << 8) | \
95 // common DC for all fonts
97 typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
98 static PtrGetCharWidthI ptrGetCharWidthI = 0;
99 static bool resolvedGetCharWidthI = false;
101 static void resolveGetCharWidthI()
103 if (resolvedGetCharWidthI)
105 resolvedGetCharWidthI = true;
106 ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI");
109 // defined in qtextengine_win.cpp
110 typedef void *SCRIPT_CACHE;
111 typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
112 extern fScriptFreeCache ScriptFreeCache;
114 static inline quint32 getUInt(unsigned char *p)
125 static inline quint16 getUShort(unsigned char *p)
134 // general font engine
136 QFixed QWindowsFontEngine::lineThickness() const
141 return QFontEngine::lineThickness();
144 static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
147 size = GetOutlineTextMetrics(hdc, 0, 0);
148 OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
149 GetOutlineTextMetrics(hdc, size, otm);
153 void QWindowsFontEngine::getCMap()
155 ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
156 HDC hdc = m_fontEngineData->hdc;
157 SelectObject(hdc, hfont);
160 cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
162 cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
163 cmapTable.size(), &symb, &size);
173 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
174 designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
175 unitsPerEm = otm->otmEMSquare;
176 x_height = (int)otm->otmsXHeight;
177 loadKerningPairs(designToDevice);
178 _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
179 lineWidth = otm->otmsUnderscoreSize;
180 fsType = otm->otmfsType;
183 unitsPerEm = tm.tmHeight;
187 // ### Qt 5.1: replace with QStringIterator
188 inline unsigned int getChar(const QChar *str, int &i, const int len)
190 uint uc = str[i].unicode();
191 if (QChar::isHighSurrogate(uc) && i < len-1) {
192 uint low = str[i+1].unicode();
193 if (QChar::isLowSurrogate(low)) {
194 uc = QChar::surrogateToUcs4(uc, low);
201 int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
206 #if defined(Q_OS_WINCE)
210 for (; i < numChars; ++i, ++glyph_pos) {
211 unsigned int uc = getChar(str, i, numChars);
212 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
213 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
214 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
217 for (; i < numChars; ++i, ++glyph_pos) {
218 unsigned int uc = getChar(str, i, numChars);
219 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
223 wchar_t first = tm.tmFirstChar;
224 wchar_t last = tm.tmLastChar;
226 for (; i < numChars; ++i, ++glyph_pos) {
227 uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
230 tm.tmFirstChar > 60000 ||
232 ucs >= first && ucs <= last)
233 glyphs->glyphs[glyph_pos] = ucs;
235 glyphs->glyphs[glyph_pos] = 0;
239 #if defined(Q_OS_WINCE)
243 for (; i < numChars; ++i, ++glyph_pos) {
244 unsigned int uc = getChar(str, i, numChars);
245 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
246 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
247 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
250 for (; i < numChars; ++i, ++glyph_pos) {
251 unsigned int uc = getChar(str, i, numChars);
252 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
256 wchar_t first = tm.tmFirstChar;
257 wchar_t last = tm.tmLastChar;
259 for (; i < numChars; ++i, ++glyph_pos) {
260 uint uc = getChar(str, i, numChars);
263 tm.tmFirstChar > 60000 ||
265 uc >= first && uc <= last)
266 glyphs->glyphs[glyph_pos] = uc;
268 glyphs->glyphs[glyph_pos] = 0;
272 glyphs->numGlyphs = glyph_pos;
277 \class QWindowsFontEngine
278 \brief Standard Windows font engine.
279 \ingroup qt-lighthouse-win
281 Will probably be superseded by a common Free Type font engine in Qt 5.X.
284 QWindowsFontEngine::QWindowsFontEngine(const QString &name,
285 HFONT _hfont, bool stockFontIn, LOGFONT lf,
286 const QSharedPointer<QWindowsFontEngineData> &fontEngineData) :
287 m_fontEngineData(fontEngineData),
291 stockFont(stockFontIn),
299 synthesized_flags(-1),
304 designAdvancesSize(0)
306 if (QWindowsContext::verboseFonts)
307 qDebug("%s: font='%s', size=%ld", __FUNCTION__, qPrintable(name), lf.lfHeight);
308 HDC hdc = m_fontEngineData->hdc;
309 SelectObject(hdc, hfont);
310 fontDef.pixelSize = -lf.lfHeight;
311 const BOOL res = GetTextMetrics(hdc, &tm);
312 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
314 qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
315 ZeroMemory(&tm, sizeof(TEXTMETRIC));
318 cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
321 if (!resolvedGetCharWidthI)
322 resolveGetCharWidthI();
325 QWindowsFontEngine::~QWindowsFontEngine()
328 free(designAdvances);
333 // make sure we aren't by accident still selected
334 SelectObject(m_fontEngineData->hdc, (HFONT)GetStockObject(SYSTEM_FONT));
337 if (!DeleteObject(hfont))
338 qErrnoWarning("%s: QFontEngineWin: failed to delete non-stock font... failed", __FUNCTION__);
340 if (QWindowsContext::verboseFonts)
341 if (QWindowsContext::verboseFonts)
342 qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name));
344 if (!uniqueFamilyName.isEmpty()) {
345 QPlatformFontDatabase *pfdb = QWindowsIntegration::instance()->fontDatabase();
346 static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
350 HGDIOBJ QWindowsFontEngine::selectDesignFont() const
352 LOGFONT f = m_logfont;
353 f.lfHeight = unitsPerEm;
354 HFONT designFont = CreateFontIndirect(&f);
355 return SelectObject(m_fontEngineData->hdc, designFont);
358 bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
360 if (*nglyphs < len) {
365 *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
367 if (flags & QTextEngine::GlyphIndicesOnly)
370 recalcAdvances(glyphs, flags);
374 inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
376 #if defined(Q_OS_WINCE)
377 GetCharWidth32(hdc, glyph, glyph, &width);
379 if (ptrGetCharWidthI)
380 ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
384 void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
387 HDC hdc = m_fontEngineData->hdc;
388 if (ttf && (flags & QTextEngine::DesignMetrics)) {
389 for(int i = 0; i < glyphs->numGlyphs; i++) {
390 unsigned int glyph = glyphs->glyphs[i];
391 if(int(glyph) >= designAdvancesSize) {
392 int newSize = (glyph + 256) >> 8 << 8;
393 designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
394 newSize*sizeof(QFixed)));
395 for(int i = designAdvancesSize; i < newSize; ++i)
396 designAdvances[i] = -1000000;
397 designAdvancesSize = newSize;
399 if (designAdvances[glyph] < -999999) {
401 oldFont = selectDesignFont();
404 calculateTTFGlyphWidth(hdc, glyph, width);
405 designAdvances[glyph] = QFixed(width) / designToDevice;
407 glyphs->advances_x[i] = designAdvances[glyph];
408 glyphs->advances_y[i] = 0;
411 DeleteObject(SelectObject(hdc, oldFont));
413 for(int i = 0; i < glyphs->numGlyphs; i++) {
414 unsigned int glyph = glyphs->glyphs[i];
416 glyphs->advances_y[i] = 0;
418 if (glyph >= widthCacheSize) {
419 int newSize = (glyph + 256) >> 8 << 8;
420 widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
421 newSize*sizeof(QFixed)));
422 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
423 widthCacheSize = newSize;
425 glyphs->advances_x[i] = widthCache[glyph];
426 // font-width cache failed
427 if (glyphs->advances_x[i] == 0) {
430 oldFont = SelectObject(hdc, hfont);
433 QChar ch[2] = { ushort(glyph), 0 };
435 if (QChar::requiresSurrogates(glyph)) {
436 ch[0] = QChar::highSurrogate(glyph);
437 ch[1] = QChar::lowSurrogate(glyph);
441 GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
444 calculateTTFGlyphWidth(hdc, glyph, width);
446 glyphs->advances_x[i] = width;
447 // if glyph's within cache range, store it for later
448 if (width > 0 && width < 0x100)
449 widthCache[glyph] = width;
454 SelectObject(hdc, oldFont);
458 glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs)
460 if (glyphs.numGlyphs == 0)
461 return glyph_metrics_t();
464 for (int i = 0; i < glyphs.numGlyphs; ++i)
465 w += glyphs.effectiveAdvance(i);
467 return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
470 bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
472 Q_ASSERT(metrics != 0);
474 HDC hdc = m_fontEngineData->hdc;
479 mat.eM11.value = mat.eM22.value = 1;
480 mat.eM11.fract = mat.eM22.fract = 0;
481 mat.eM21.value = mat.eM12.value = 0;
482 mat.eM21.fract = mat.eM12.fract = 0;
484 if (t.type() > QTransform::TxTranslate) {
485 // We need to set the transform using the HDC's world
486 // matrix rather than using the MAT2 above, because the
487 // results provided when transforming via MAT2 does not
488 // match the glyphs that are drawn using a WorldTransform
490 xform.eM11 = t.m11();
491 xform.eM12 = t.m12();
492 xform.eM21 = t.m21();
493 xform.eM22 = t.m22();
496 SetGraphicsMode(hdc, GM_ADVANCED);
497 SetWorldTransform(hdc, &xform);
500 uint format = GGO_METRICS;
502 format |= GGO_GLYPH_INDEX;
503 res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
505 if (t.type() > QTransform::TxTranslate) {
507 xform.eM11 = xform.eM22 = 1;
508 xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
509 SetWorldTransform(hdc, &xform);
510 SetGraphicsMode(hdc, GM_COMPATIBLE);
513 if (res != GDI_ERROR) {
514 *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
515 (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
523 glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t)
526 HDC hdc = m_fontEngineData->hdc;
527 SelectObject(hdc, hfont);
529 glyph_metrics_t glyphMetrics;
530 bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
532 if (!ttf && !success) {
536 GetCharABCWidthsFloat(hdc, ch, ch, &abc);
537 int width = qRound(abc.abcfB);
539 return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
544 HDC hdc = m_fontEngineData->hdc;
545 HGDIOBJ oldFont = SelectObject(hdc, hfont);
550 #ifdef GWES_MGTT // true type fonts
551 if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
552 width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
553 advance = abc.abcA + abc.abcB + abc.abcC;
557 #if defined(GWES_MGRAST) || defined(GWES_MGRAST2) // raster fonts
558 if (GetCharWidth32(hdc, glyph, glyph, &width)) {
564 width = tm.tmMaxCharWidth;
568 SelectObject(hdc, oldFont);
569 return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
573 QFixed QWindowsFontEngine::ascent() const
578 QFixed QWindowsFontEngine::descent() const
583 QFixed QWindowsFontEngine::leading() const
585 return tm.tmExternalLeading;
589 QFixed QWindowsFontEngine::xHeight() const
593 return QFontEngine::xHeight();
596 QFixed QWindowsFontEngine::averageCharWidth() const
598 return tm.tmAveCharWidth;
601 qreal QWindowsFontEngine::maxCharWidth() const
603 return tm.tmMaxCharWidth;
606 enum { max_font_count = 256 };
607 static const ushort char_table[] = {
629 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
632 void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
634 HDC hdc = m_fontEngineData->hdc;
635 SelectObject(hdc, hfont);
642 GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
644 *leftBearing = abcWidths.abcA;
646 *rightBearing = abcWidths.abcC;
650 QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
656 qreal QWindowsFontEngine::minLeftBearing() const
658 if (lbearing == SHRT_MIN)
659 minRightBearing(); // calculates both
664 qreal QWindowsFontEngine::minRightBearing() const
667 if (rbearing == SHRT_MIN) {
670 HDC hdc = m_fontEngineData->hdc;
671 SelectObject(hdc, hfont);
674 int n = tm.tmLastChar - tm.tmFirstChar;
675 if (n <= max_font_count) {
677 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
679 abc = new ABC[char_table_entries+1];
680 for(int i = 0; i < char_table_entries; i++)
681 GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
682 n = char_table_entries;
686 for (int i = 1; i < n; i++) {
687 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
688 ml = qMin(ml,abc[i].abcA);
689 mr = qMin(mr,abc[i].abcC);
695 int n = tm.tmLastChar - tm.tmFirstChar+1;
696 if (n <= max_font_count) {
697 abc = new ABCFLOAT[n];
698 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
700 abc = new ABCFLOAT[char_table_entries];
701 for(int i = 0; i < char_table_entries; i++)
702 GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
703 n = char_table_entries;
705 float fml = abc[0].abcfA;
706 float fmr = abc[0].abcfC;
707 for (int i=1; i<n; i++) {
708 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
709 fml = qMin(fml,abc[i].abcfA);
710 fmr = qMin(fmr,abc[i].abcfC);
713 ml = int(fml - 0.9999);
714 mr = int(fmr - 0.9999);
723 if (rbearing == SHRT_MIN) {
726 HDC hdc = m_fontEngineData->hdc;
727 SelectObject(hdc, hfont);
730 int n = tm.tmLastChar - tm.tmFirstChar;
731 if (n <= max_font_count) {
733 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
735 abc = new ABC[char_table_entries+1];
736 for (int i = 0; i < char_table_entries; i++)
737 GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
738 n = char_table_entries;
742 for (int i = 1; i < n; i++) {
743 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
744 ml = qMin(ml,abc[i].abcA);
745 mr = qMin(mr,abc[i].abcC);
759 const char *QWindowsFontEngine::name() const
764 bool QWindowsFontEngine::canRender(const QChar *string, int len)
767 for (int i = 0; i < len; ++i) {
768 unsigned int uc = getChar(string, i, len);
769 if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
771 if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
779 for (int i = 0; i < len; ++i) {
780 unsigned int uc = getChar(string, i, len);
781 if (getTrueTypeGlyphIndex(cmap, uc) == 0)
786 if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
793 QFontEngine::Type QWindowsFontEngine::type() const
795 return QFontEngine::Win;
798 static inline double qt_fixed_to_double(const FIXED &p) {
799 return ((p.value << 16) + p.fract) / 65536.0;
802 static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
803 return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
807 #define GGO_UNHINTED 0x0100
810 static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
811 QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
814 mat.eM11.value = mat.eM22.value = 1;
815 mat.eM11.fract = mat.eM22.fract = 0;
816 mat.eM21.value = mat.eM12.value = 0;
817 mat.eM21.fract = mat.eM12.fract = 0;
818 uint glyphFormat = GGO_NATIVE;
821 glyphFormat |= GGO_GLYPH_INDEX;
823 GLYPHMETRICS gMetric;
824 memset(&gMetric, 0, sizeof(GLYPHMETRICS));
825 int bufferSize = GDI_ERROR;
826 bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
827 if ((DWORD)bufferSize == GDI_ERROR) {
831 void *dataBuffer = new char[bufferSize];
832 DWORD ret = GDI_ERROR;
833 ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
834 if (ret == GDI_ERROR) {
835 delete [](char *)dataBuffer;
841 *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
842 (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
843 gMetric.gmCellIncX, gMetric.gmCellIncY);
847 int headerOffset = 0;
848 TTPOLYGONHEADER *ttph = 0;
850 QPointF oset = position.toPointF();
851 while (headerOffset < bufferSize) {
852 ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
854 QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
855 path->moveTo(lastPoint + oset);
856 offset += sizeof(TTPOLYGONHEADER);
858 while (offset<int(headerOffset + ttph->cb)) {
859 curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
860 switch (curve->wType) {
862 for (int i=0; i<curve->cpfx; ++i) {
863 QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
868 case TT_PRIM_QSPLINE: {
869 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
870 QPointF prev(elm.x, elm.y);
872 for (int i=0; i<curve->cpfx - 1; ++i) {
873 QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
874 QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
875 if (i < curve->cpfx - 2) {
876 endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
881 path->quadTo(p1, endPoint);
887 case TT_PRIM_CSPLINE: {
888 for (int i=0; i<curve->cpfx; ) {
889 QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
890 QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
891 QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
892 path->cubicTo(p2, p3, p4);
897 qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
899 offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
901 path->closeSubpath();
902 headerOffset += ttph->cb;
904 delete [] (char*)dataBuffer;
909 void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
910 QPainterPath *path, QTextItem::RenderFlags)
912 LOGFONT lf = m_logfont;
913 // The sign must be negative here to make sure we match against character height instead of
914 // hinted cell height. This ensures that we get linear matching, and we need this for
915 // paths since we later on apply a scaling transform to the glyph outline to get the
916 // font at the correct pixel size.
917 lf.lfHeight = -unitsPerEm;
919 HFONT hf = CreateFontIndirect(&lf);
920 HDC hdc = m_fontEngineData->hdc;
921 HGDIOBJ oldfont = SelectObject(hdc, hf);
923 for(int i = 0; i < nglyphs; ++i) {
924 if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
925 qreal(fontDef.pixelSize) / unitsPerEm)) {
926 // Some windows fonts, like "Modern", are vector stroke
927 // fonts, which are reported as TMPF_VECTOR but do not
928 // support GetGlyphOutline, and thus we set this bit so
929 // that addOutLineToPath can check it and return safely...
934 DeleteObject(SelectObject(hdc, oldfont));
937 void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
938 QPainterPath *path, QTextItem::RenderFlags flags)
940 if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
942 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
944 // has_outline is set to false if addGlyphToPath gets
945 // false from GetGlyphOutline, meaning its not an outline
950 QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
953 QFontEngine::FaceId QWindowsFontEngine::faceId() const
958 QT_BEGIN_INCLUDE_NAMESPACE
960 QT_END_INCLUDE_NAMESPACE
962 int QWindowsFontEngine::synthesized() const
964 if(synthesized_flags == -1) {
965 synthesized_flags = 0;
967 const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
968 HDC hdc = m_fontEngineData->hdc;
969 SelectObject(hdc, hfont);
971 GetFontData(hdc, HEAD, 44, &data, 4);
972 USHORT macStyle = getUShort(data);
973 if (tm.tmItalic && !(macStyle & 2))
974 synthesized_flags = SynthesizedItalic;
975 if (fontDef.stretch != 100 && ttf)
976 synthesized_flags |= SynthesizedStretch;
977 if (tm.tmWeight >= 500 && !(macStyle & 1))
978 synthesized_flags |= SynthesizedBold;
979 //qDebug() << "font is" << _name <<
980 // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
983 return synthesized_flags;
986 QFixed QWindowsFontEngine::emSquareSize() const
991 QFontEngine::Properties QWindowsFontEngine::properties() const
993 LOGFONT lf = m_logfont;
994 lf.lfHeight = unitsPerEm;
995 HFONT hf = CreateFontIndirect(&lf);
996 HDC hdc = m_fontEngineData->hdc;
997 HGDIOBJ oldfont = SelectObject(hdc, hf);
998 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
1000 p.emSquare = unitsPerEm;
1001 p.italicAngle = otm->otmItalicAngle;
1002 p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
1003 p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
1004 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
1005 p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
1006 otm->otmrcFontBox.right - otm->otmrcFontBox.left,
1007 otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
1008 p.ascent = otm->otmAscent;
1009 p.descent = -otm->otmDescent;
1010 p.leading = (int)otm->otmLineGap;
1012 p.lineWidth = otm->otmsUnderscoreSize;
1014 DeleteObject(SelectObject(hdc, oldfont));
1018 void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1020 LOGFONT lf = m_logfont;
1021 lf.lfHeight = unitsPerEm;
1022 int flags = synthesized();
1023 if(flags & SynthesizedItalic)
1024 lf.lfItalic = false;
1026 HFONT hf = CreateFontIndirect(&lf);
1027 HDC hdc = m_fontEngineData->hdc;
1028 HGDIOBJ oldfont = SelectObject(hdc, hf);
1032 addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
1033 DeleteObject(SelectObject(hdc, oldfont));
1036 bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1040 HDC hdc = m_fontEngineData->hdc;
1041 SelectObject(hdc, hfont);
1042 DWORD t = qbswap<quint32>(tag);
1043 *length = GetFontData(hdc, t, 0, buffer, *length);
1044 return *length != GDI_ERROR;
1047 #if !defined(CLEARTYPE_QUALITY)
1048 # define CLEARTYPE_QUALITY 5
1051 QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
1052 const QTransform &t,
1053 QImage::Format mask_format)
1055 Q_UNUSED(mask_format)
1056 glyph_metrics_t gm = boundingBox(glyph);
1058 // printf(" -> for glyph %4x\n", glyph);
1060 int gx = gm.x.toInt();
1061 int gy = gm.y.toInt();
1062 int iw = gm.width.toInt();
1063 int ih = gm.height.toInt();
1065 if (iw <= 0 || iw <= 0)
1068 bool has_transformation = t.type() > QTransform::TxTranslate;
1071 unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
1074 if (has_transformation) {
1075 xform.eM11 = t.m11();
1076 xform.eM12 = t.m12();
1077 xform.eM21 = t.m21();
1078 xform.eM22 = t.m22();
1082 HDC hdc = CreateCompatibleDC(QWindowsContext::instance()->displayContext());
1084 SetGraphicsMode(hdc, GM_ADVANCED);
1085 SetWorldTransform(hdc, &xform);
1086 HGDIOBJ old_font = SelectObject(hdc, font);
1088 int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
1091 memset(&mat, 0, sizeof(mat));
1092 mat.eM11.value = mat.eM22.value = 1;
1094 if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
1095 qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
1099 iw = tgm.gmBlackBoxX;
1100 ih = tgm.gmBlackBoxY;
1102 xform.eDx -= tgm.gmptGlyphOrigin.x;
1103 xform.eDy += tgm.gmptGlyphOrigin.y;
1105 SetGraphicsMode(hdc, GM_COMPATIBLE);
1106 SelectObject(hdc, old_font);
1110 unsigned int options = 0;
1112 Q_ASSERT(!has_transformation);
1114 Q_UNUSED(has_transformation);
1117 QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4,
1118 ih + 2 * margin + 4,
1119 QWindowsNativeImage::systemFormat());
1121 /*If cleartype is enabled we use the standard system format even on Windows CE
1122 and not the special textbuffer format we have to use if cleartype is disabled*/
1124 ni->image().fill(0xffffffff);
1126 HDC hdc = ni->hdc();
1128 SelectObject(hdc, GetStockObject(NULL_BRUSH));
1129 SelectObject(hdc, GetStockObject(BLACK_PEN));
1130 SetTextColor(hdc, RGB(0,0,0));
1131 SetBkMode(hdc, TRANSPARENT);
1132 SetTextAlign(hdc, TA_BASELINE);
1134 HGDIOBJ old_font = SelectObject(hdc, font);
1137 if (has_transformation) {
1138 SetGraphicsMode(hdc, GM_ADVANCED);
1139 SetWorldTransform(hdc, &xform);
1140 ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
1142 #endif // !Q_OS_WINCE
1144 ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
1147 SelectObject(hdc, old_font);
1151 QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
1154 if (m_fontEngineData->clearTypeEnabled) {
1155 LOGFONT lf = m_logfont;
1156 lf.lfQuality = ANTIALIASED_QUALITY;
1157 font = CreateFontIndirect(&lf);
1159 QImage::Format mask_format = QWindowsNativeImage::systemFormat();
1160 mask_format = QImage::Format_RGB32;
1162 QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1166 QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
1168 // ### This part is kinda pointless, but we'll crash later if we don't because some
1169 // code paths expects there to be colortables for index8-bit...
1170 QVector<QRgb> colors(256);
1171 for (int i=0; i<256; ++i)
1172 colors[i] = qRgba(0, 0, 0, i);
1173 indexed.setColorTable(colors);
1175 // Copy data... Cannot use QPainter here as GDI has messed up the
1176 // Alpha channel of the ni.image pixels...
1177 for (int y=0; y<mask->height(); ++y) {
1178 uchar *dest = indexed.scanLine(y);
1179 if (mask->image().format() == QImage::Format_RGB16) {
1180 const qint16 *src = (qint16 *) ((const QImage &) mask->image()).scanLine(y);
1181 for (int x=0; x<mask->width(); ++x)
1182 dest[x] = 255 - qGray(src[x]);
1184 const uint *src = (uint *) ((const QImage &) mask->image()).scanLine(y);
1185 for (int x=0; x<mask->width(); ++x) {
1186 if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
1187 dest[x] = 255 - qGray(src[x]);
1189 dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1196 if (m_fontEngineData->clearTypeEnabled) {
1203 #define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1204 #define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1206 QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t)
1211 SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1212 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
1214 int margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask);
1215 QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1216 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
1221 // Gracefully handle the odd case when the display is 16-bit
1222 const QImage source = mask->image().depth() == 32
1224 : mask->image().convertToFormat(QImage::Format_RGB32);
1226 QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1227 for (int y=0; y<mask->height(); ++y) {
1228 uint *dest = (uint *) rgbMask.scanLine(y);
1229 const uint *src = (uint *) source.scanLine(y);
1230 for (int x=0; x<mask->width(); ++x) {
1231 dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1240 QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
1242 QFontDef request = fontDef;
1243 QString actualFontName = request.family;
1244 if (!uniqueFamilyName.isEmpty())
1245 request.family = uniqueFamilyName;
1246 request.pixelSize = pixelSize;
1247 // Disable font merging, as otherwise createEngine will return a multi-engine
1248 // instance instead of the specific engine we wish to clone.
1249 request.styleStrategy |= QFont::NoFontMerging;
1251 QFontEngine *fontEngine =
1252 QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
1253 QWindowsContext::instance()->defaultDPI(),
1255 QStringList(), m_fontEngineData);
1257 fontEngine->fontDef.family = actualFontName;
1258 if (!uniqueFamilyName.isEmpty()) {
1259 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1260 QPlatformFontDatabase *pfdb = QWindowsIntegration::instance()->fontDatabase();
1261 static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1267 void QWindowsFontEngine::initFontInfo(const QFontDef &request,
1271 fontDef = request; // most settings are equal
1272 HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : m_fontEngineData->hdc;
1273 SelectObject(dc, hfont);
1275 GetTextFace(dc, 64, n);
1276 fontDef.family = QString::fromWCharArray(n);
1277 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1278 if (fontDef.pointSize < 0) {
1279 fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1280 } else if (fontDef.pixelSize == -1) {
1281 fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1286 \class QWindowsMultiFontEngine
1287 \brief Standard Windows Multi font engine.
1288 \ingroup qt-lighthouse-win
1290 "Merges" several font engines that have gaps in the
1291 supported writing systems.
1293 Will probably be superseded by a common Free Type font engine in Qt 5.X.
1296 QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks)
1297 : QFontEngineMulti(fallbacks.size()+1),
1298 fallbacks(fallbacks)
1300 if (QWindowsContext::verboseFonts)
1301 qDebug() << __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks;
1304 fontDef = engines[0]->fontDef;
1305 cache_cost = first->cache_cost;
1308 QWindowsMultiFontEngine::~QWindowsMultiFontEngine()
1310 if (QWindowsContext::verboseFonts)
1311 qDebug("%s", __FUNCTION__);
1314 void QWindowsMultiFontEngine::loadEngine(int at)
1316 Q_ASSERT(at < engines.size());
1317 Q_ASSERT(engines.at(at) == 0);
1319 const QString fam = fallbacks.at(at-1);
1320 QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(engines.at(0));
1321 LOGFONT lf = fe->logFont();
1322 memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
1323 HFONT hfont = CreateFontIndirect(&lf);
1325 bool stockFont = false;
1327 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1330 engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, fe->fontEngineData());
1331 engines[at]->ref.ref();
1332 engines[at]->fontDef = fontDef;
1333 if (QWindowsContext::verboseFonts)
1334 qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam));
1337 // TODO: increase cost in QFontCache for the font engine loaded here