8#include <QtCore/qt_windows.h>
9#if QT_CONFIG(directwrite)
10# include "qwindowsfontenginedirectwrite_p.h"
12#include <QtGui/qpa/qplatformintegration.h>
13#include <QtGui/private/qtextengine_p.h>
14#include <QtGui/private/qguiapplication_p.h>
15#include <QtGui/QPaintDevice>
16#include <QtGui/QBitmap>
17#include <QtGui/QPainter>
18#include <QtGui/private/qpainter_p.h>
19#include <QtGui/QPaintEngine>
20#include <QtGui/private/qpaintengine_raster_p.h>
21#include <QtGui/private/qtgui-config_p.h>
23#include <QtCore/QtEndian>
24#include <QtCore/QFile>
25#include <QtCore/qmath.h>
26#include <QtCore/QTextStream>
27#include <QtCore/QThreadStorage>
28#include <QtCore/private/qsystemlibrary_p.h>
29#include <QtCore/private/qstringiterator_p.h>
31#include <QtCore/QDebug>
35#if QT_CONFIG(directwrite)
42QT_IMPL_METATYPE_EXTERN(HFONT)
43QT_IMPL_METATYPE_EXTERN(LOGFONT)
46#ifndef TT_PRIM_CSPLINE
47#define TT_PRIM_CSPLINE 3
51#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (
52 (((quint32)(ch4)) << 24
) |
53 (((quint32)(ch3)) << 16
) |
54 (((quint32)(ch2)) << 8
) |
62QFixed QWindowsFontEngine::lineThickness()
const
67 return QFontEngine::lineThickness();
70static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
72 const auto size = GetOutlineTextMetrics(hdc, 0,
nullptr);
75 auto otm =
reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size));
78 if (GetOutlineTextMetrics(hdc, size, otm) == 0) {
85bool QWindowsFontEngine::hasCFFTable()
const
87 HDC hdc = m_fontEngineData->hdc;
88 SelectObject(hdc, hfont);
92bool QWindowsFontEngine::hasCMapTable()
const
94 HDC hdc = m_fontEngineData->hdc;
95 SelectObject(hdc, hfont);
99static inline QString stringFromOutLineTextMetric(
const OUTLINETEXTMETRIC *otm, PSTR offset)
101 const uchar *p =
reinterpret_cast<
const uchar *>(otm) + quintptr(offset);
102 return QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(p));
105void QWindowsFontEngine::getCMap()
107 ttf = (
bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable();
109 cffTable = hasCFFTable();
111 HDC hdc = m_fontEngineData->hdc;
112 SelectObject(hdc, hfont);
115 cmapTable = getSfntTable(QFont::Tag(
"cmap").value());
116 cmap = QFontEngine::getCMap(
reinterpret_cast<
const uchar *>(cmapTable.constData()),
117 cmapTable.size(), &symb, &cmapSize);
126 OUTLINETEXTMETRIC *otm = cmap !=
nullptr ? getOutlineTextMetric(hdc) :
nullptr;
127 if (otm !=
nullptr) {
128 unitsPerEm =
int(otm->otmEMSquare);
129 const QFixed unitsPerEmF(unitsPerEm);
130 designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize);
131 x_height =
int(otm->otmsXHeight);
132 loadKerningPairs(designToDevice);
133 _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName));
134 lineWidth = otm->otmsUnderscoreSize;
135 fsType = otm->otmfsType;
139 unitsPerEm = tm.tmHeight;
143int QWindowsFontEngine::getGlyphIndexes(
const QChar *str,
int numChars, QGlyphLayout *glyphs,
int *mappedGlyphs)
const
149 QStringIterator it(str, str + numChars);
150 while (it.hasNext()) {
151 const uint uc = it.next();
152 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
153 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
154 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
155 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
160 QStringIterator it(str, str + numChars);
161 while (it.hasNext()) {
162 const uint uc = it.next();
163 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
164 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
169 QStringIterator it(str, str + numChars);
170 while (it.hasNext()) {
171 const uint uc = it.next();
172 if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar)
173 glyphs->glyphs[glyph_pos] = uc;
175 glyphs->glyphs[glyph_pos] = 0;
176 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
182 glyphs->numGlyphs = glyph_pos;
187
188
189
190
191
192
194QWindowsFontEngine::QWindowsFontEngine(
const QString &name,
196 const QSharedPointer<QWindowsFontEngineData> &fontEngineData)
198 m_fontEngineData(fontEngineData),
204 qCDebug(lcQpaFonts) <<
__FUNCTION__ << name << lf.lfHeight;
205 hfont = CreateFontIndirect(&m_logfont);
207 qErrnoWarning(
"%s: CreateFontIndirect failed for family '%s'",
__FUNCTION__, qPrintable(name));
208 hfont = QWindowsFontDatabase::systemFont();
211 HDC hdc = m_fontEngineData->hdc;
212 SelectObject(hdc, hfont);
213 const BOOL res = GetTextMetrics(hdc, &tm);
215 qErrnoWarning(
"%s: GetTextMetrics failed",
__FUNCTION__);
216 ZeroMemory(&tm,
sizeof(TEXTMETRIC));
219 fontDef.pixelSize = -lf.lfHeight;
220 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
222 cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
225 hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0;
228QWindowsFontEngine::~QWindowsFontEngine()
231 free(designAdvances);
237 SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont());
239 if (!DeleteObject(hfont))
240 qErrnoWarning(
"%s: QFontEngineWin: failed to delete font...",
__FUNCTION__);
241 qCDebug(lcQpaFonts) <<
__FUNCTION__ << _name;
243 if (!uniqueFamilyName.isEmpty()) {
244 if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
245 QPlatformFontDatabase *pfdb = pi->fontDatabase();
246 static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
251glyph_t QWindowsFontEngine::glyphIndex(uint ucs4)
const
256 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
257 if (glyph == 0 && ucs4 < 0x100)
258 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
260 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
261 }
else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
268HGDIOBJ QWindowsFontEngine::selectDesignFont()
const
270 LOGFONT f = m_logfont;
271 f.lfHeight = -unitsPerEm;
273 HFONT designFont = CreateFontIndirect(&f);
274 return SelectObject(m_fontEngineData->hdc, designFont);
277int QWindowsFontEngine::stringToCMap(
const QChar *str,
int len, QGlyphLayout *glyphs,
int *nglyphs, QFontEngine::ShaperFlags flags)
const
279 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
280 if (*nglyphs < len) {
285 glyphs->numGlyphs = *nglyphs;
287 *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
289 if (!(flags & GlyphIndicesOnly))
290 recalcAdvances(glyphs, flags);
295inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph,
int &width)
297 GetCharWidthI(hdc, glyph, 1, 0, &width);
300void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags)
const
303 HDC hdc = m_fontEngineData->hdc;
306 const uint maxGlyph = ttf ? 0xffff : uint(QChar::LastValidCodePoint);
307 if (ttf && (flags & DesignMetrics)) {
308 for(
int i = 0; i < glyphs->numGlyphs; i++) {
309 unsigned int glyph = qMin(glyphs->glyphs[i], maxGlyph);
310 if (
int(glyph) >= designAdvancesSize) {
311 const int newSize =
int(glyph + 256) >> 8 << 8;
312 designAdvances =
reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) *
sizeof(QFixed)));
313 Q_CHECK_PTR(designAdvances);
314 for(
int i = designAdvancesSize; i < newSize; ++i)
315 designAdvances[i] = -1000000;
316 designAdvancesSize = newSize;
318 if (designAdvances[glyph] < -999999) {
320 oldFont = selectDesignFont();
323 calculateTTFGlyphWidth(hdc, glyph, width);
324 designAdvances[glyph] = QFixed(width) / designToDevice;
326 glyphs->advances[i] = designAdvances[glyph];
329 DeleteObject(SelectObject(hdc, oldFont));
331 for(
int i = 0; i < glyphs->numGlyphs; i++) {
332 unsigned int glyph = qMin(glyphs->glyphs[i], maxGlyph);
334 if (glyph >= widthCacheSize) {
335 const uint newSize = (glyph + 256) >> 8 << 8;
336 widthCache =
reinterpret_cast<
unsigned char *>(realloc(widthCache, newSize));
337 Q_CHECK_PTR(widthCache);
338 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
339 widthCacheSize = newSize;
341 glyphs->advances[i] = widthCache[glyph];
343 if (glyphs->advances[i].value() == 0) {
346 oldFont = SelectObject(hdc, hfont);
349 QChar ch[2] = { ushort(glyph), u'\0' };
351 if (QChar::requiresSurrogates(glyph)) {
352 ch[0] = QChar::highSurrogate(glyph);
353 ch[1] = QChar::lowSurrogate(glyph);
357 GetTextExtentPoint32(hdc,
reinterpret_cast<
const wchar_t *>(ch), chrLen, &size);
360 calculateTTFGlyphWidth(hdc, glyph, width);
362 glyphs->advances[i] = width;
364 if (width > 0 && width < 0x100)
365 widthCache[glyph] = uchar(width);
370 SelectObject(hdc, oldFont);
374bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph,
const QTransform &t, glyph_metrics_t *metrics)
const
376 Q_ASSERT(metrics != 0);
378 HDC hdc = m_fontEngineData->hdc;
383 mat.eM11.value = mat.eM22.value = 1;
384 mat.eM11.fract = mat.eM22.fract = 0;
385 mat.eM21.value = mat.eM12.value = 0;
386 mat.eM21.fract = mat.eM12.fract = 0;
388 if (t.type() > QTransform::TxTranslate) {
394 xform.eM11 = FLOAT(t.m11());
395 xform.eM12 = FLOAT(t.m12());
396 xform.eM21 = FLOAT(t.m21());
397 xform.eM22 = FLOAT(t.m22());
400 SetGraphicsMode(hdc, GM_ADVANCED);
401 SetWorldTransform(hdc, &xform);
404 uint format = GGO_METRICS;
406 format |= GGO_GLYPH_INDEX;
407 res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
409 if (t.type() > QTransform::TxTranslate) {
411 xform.eM11 = xform.eM22 = 1;
412 xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
413 SetWorldTransform(hdc, &xform);
414 SetGraphicsMode(hdc, GM_COMPATIBLE);
417 if (res != GDI_ERROR) {
418 *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
419 int(gm.gmBlackBoxX),
int(gm.gmBlackBoxY),
420 gm.gmCellIncX, gm.gmCellIncY);
427glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph,
const QTransform &t)
429 HDC hdc = m_fontEngineData->hdc;
430 SelectObject(hdc, hfont);
432 glyph_metrics_t glyphMetrics;
433 bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
435 if (!ttf && !success) {
437 wchar_t ch =
wchar_t(glyph);
439 GetCharABCWidthsFloat(hdc, ch, ch, &abc);
440 int width = qRound(abc.abcfB);
442 return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
458 qint16 subscriptXSize;
459 qint16 subscriptYSize;
460 qint16 subscriptXOffset;
461 qint16 subscriptYOffset;
462 qint16 superscriptXSize;
463 qint16 superscriptYSize;
464 qint16 superscriptXOffset;
465 qint16 superscriptYOffset;
466 qint16 strikeOutSize;
467 qint16 strikeOutPosition;
470 quint32 unicodeRanges[4];
473 quint16 firstCharIndex;
474 quint16 lastCharIndex;
476 qint16 typoDescender;
480 quint32 codepageRanges[2];
491QFixed QWindowsFontEngine::capHeight()
const
493 const QByteArray tableData = getSfntTable(QFont::Tag(
"OS/2").value());
494 if (size_t(tableData.size()) >=
sizeof(OS2Table)) {
495 const OS2Table *table =
reinterpret_cast<
const OS2Table *>(tableData.constData());
496 if (qFromBigEndian<quint16>(table->version) >= 2) {
497 qint16 capHeight = qFromBigEndian<qint16>(table->capHeight);
499 return QFixed(capHeight) / designToDevice;
502 return calculatedCapHeight();
505QFixed QWindowsFontEngine::xHeight()
const
509 return QFontEngine::xHeight();
512QFixed QWindowsFontEngine::averageCharWidth()
const
514 return tm.tmAveCharWidth;
517qreal QWindowsFontEngine::maxCharWidth()
const
519 return tm.tmMaxCharWidth;
522enum { max_font_count = 256 };
550 HDC hdc = m_fontEngineData->hdc;
551 SelectObject(hdc, hfont);
555 GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
557 *leftBearing = abcWidths.abcA;
559 *rightBearing = abcWidths.abcC;
561 QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
568 m_ascent = tm.tmAscent;
569 m_descent = tm.tmDescent;
570 m_leading = tm.tmExternalLeading;
572 QFontEngine::initializeHeightMetrics();
577 return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline();
582 if (lbearing == SHRT_MIN)
590 if (rbearing == SHRT_MIN) {
593 HDC hdc = m_fontEngineData->hdc;
594 SelectObject(hdc, hfont);
597 int n = tm.tmLastChar - tm.tmFirstChar;
598 if (n <= max_font_count) {
600 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
602 abc =
new ABC[char_table_entries+1];
604 GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
609 for (
int i = 1; i < n; i++) {
610 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
611 ml = qMin(ml,abc[i].abcA);
612 mr = qMin(mr,abc[i].abcC);
618 int n = tm.tmLastChar - tm.tmFirstChar+1;
619 if (n <= max_font_count) {
620 abc =
new ABCFLOAT[n];
621 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
623 abc =
new ABCFLOAT[char_table_entries];
625 GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
628 float fml = abc[0].abcfA;
629 float fmr = abc[0].abcfC;
630 for (
int i=1; i<n; i++) {
631 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
632 fml = qMin(fml,abc[i].abcfA);
633 fmr = qMin(fmr,abc[i].abcfC);
648 return ((p.value << 16) + p.fract) / 65536.0;
652 return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
656#define GGO_UNHINTED 0x0100
660 QPainterPath *path,
bool ttf, glyph_metrics_t *metric =
nullptr,
661 qreal scale = 1.0, qreal stretch = 1.0)
664 mat.eM11.value = mat.eM22.value = 1;
665 mat.eM11.fract = mat.eM22.fract = 0;
666 mat.eM21.value = mat.eM12.value = 0;
667 mat.eM21.fract = mat.eM12.fract = 0;
669 GLYPHMETRICS gMetric;
670 memset(&gMetric, 0,
sizeof(GLYPHMETRICS));
676 uint format = GGO_METRICS;
678 format |= GGO_GLYPH_INDEX;
679 if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR)
682 *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
683 int(gMetric.gmBlackBoxX),
int(gMetric.gmBlackBoxY),
684 gMetric.gmCellIncX, gMetric.gmCellIncY);
687 uint glyphFormat = GGO_NATIVE;
690 glyphFormat |= GGO_GLYPH_INDEX;
692 const DWORD bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
693 if (bufferSize == GDI_ERROR)
696 char *dataBuffer =
new char[bufferSize];
697 DWORD ret = GDI_ERROR;
698 ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
699 if (ret == GDI_ERROR) {
700 delete [] dataBuffer;
705 DWORD headerOffset = 0;
707 QPointF oset = position.toPointF();
708 while (headerOffset < bufferSize) {
709 const TTPOLYGONHEADER *ttph =
reinterpret_cast<
const TTPOLYGONHEADER *>(dataBuffer + headerOffset);
711 QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
712 path->moveTo(lastPoint + oset);
713 offset +=
sizeof(TTPOLYGONHEADER);
714 while (offset < headerOffset + ttph->cb) {
715 const TTPOLYCURVE *curve =
reinterpret_cast<
const TTPOLYCURVE *>(dataBuffer + offset);
716 switch (curve->wType) {
718 for (
int i=0; i<curve->cpfx; ++i) {
719 QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
724 case TT_PRIM_QSPLINE: {
725 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
726 QPointF prev(elm.x, elm.y);
728 for (
int i=0; i<curve->cpfx - 1; ++i) {
729 QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
730 QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
731 if (i < curve->cpfx - 2) {
732 endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
737 path->quadTo(p1, endPoint);
744 for (
int i=0; i<curve->cpfx; ) {
745 QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
746 QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
747 QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
748 path->cubicTo(p2, p3, p4);
753 qWarning(
"QFontEngineWin::addOutlineToPath, unhandled switch case");
755 offset +=
sizeof(TTPOLYCURVE) + (curve->cpfx-1) *
sizeof(POINTFX);
757 path->closeSubpath();
758 headerOffset += ttph->cb;
760 delete [] dataBuffer;
768 LOGFONT lf = m_logfont;
773 lf.lfHeight = -unitsPerEm;
775 HFONT hf = CreateFontIndirect(&lf);
776 HDC hdc = m_fontEngineData->hdc;
777 HGDIOBJ oldfont = SelectObject(hdc, hf);
779 qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
780 qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
781 for(
int i = 0; i < nglyphs; ++i) {
782 if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, 0,
792 DeleteObject(SelectObject(hdc, oldfont));
796 QPainterPath *path, QTextItem::RenderFlags flags)
798 if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
800 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
808 QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
816QT_BEGIN_INCLUDE_NAMESPACE
818QT_END_INCLUDE_NAMESPACE
822 if (synthesized_flags == -1) {
823 synthesized_flags = 0;
826 HDC hdc = m_fontEngineData->hdc;
827 SelectObject(hdc, hfont);
829 if (GetFontData(hdc, HEAD, 44, &data, 4) != GDI_ERROR) {
830 USHORT macStyle = qt_getUShort(data);
831 if (tm.tmItalic && !(macStyle & 2))
832 synthesized_flags = SynthesizedItalic;
833 if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1))
834 synthesized_flags |= SynthesizedBold;
838 if (fontDef.stretch != 100 && ttf)
839 synthesized_flags |= SynthesizedStretch;
842 return synthesized_flags;
852 LOGFONT lf = m_logfont;
853 lf.lfHeight = unitsPerEm;
854 HFONT hf = CreateFontIndirect(&lf);
855 HDC hdc = m_fontEngineData->hdc;
856 HGDIOBJ oldfont = SelectObject(hdc, hf);
857 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
858 if (otm ==
nullptr) {
859 DeleteObject(SelectObject(hdc, oldfont));
860 return QFontEngine::properties();
863 p.emSquare = unitsPerEm;
864 p.italicAngle = otm->otmItalicAngle;
865 const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1()
866 + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1();
867 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name);
868 p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
869 otm->otmrcFontBox.right - otm->otmrcFontBox.left,
870 otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
871 p.ascent = otm->otmAscent;
872 p.descent = -otm->otmDescent;
873 p.leading =
int(otm->otmLineGap);
875 p.lineWidth = otm->otmsUnderscoreSize;
877 DeleteObject(SelectObject(hdc, oldfont));
883 LOGFONT lf = m_logfont;
884 lf.lfHeight = -unitsPerEm;
886 if (flags & SynthesizedItalic)
889 HFONT hf = CreateFontIndirect(&lf);
890 HDC hdc = m_fontEngineData->hdc;
891 HGDIOBJ oldfont = SelectObject(hdc, hf);
895 addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
896 DeleteObject(SelectObject(hdc, oldfont));
901 if (!ttf && !cffTable)
903 HDC hdc = m_fontEngineData->hdc;
904 SelectObject(hdc, hfont);
905 DWORD t = qbswap<quint32>(tag);
906 *length = GetFontData(hdc, t, 0, buffer, *length);
907 return *length != GDI_ERROR && *length > 0;
910#if !defined(CLEARTYPE_QUALITY)
911# define CLEARTYPE_QUALITY 5
914QWindowsNativeImage *
QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
int margin,
916 QImage::Format mask_format)
918 Q_UNUSED(mask_format);
919 glyph_metrics_t gm = boundingBox(glyph);
923 int gx = gm.x.toInt();
924 int gy = gm.y.toInt();
925 int iw = gm.width.toInt();
926 int ih = gm.height.toInt();
928 if (iw <= 0 || ih <= 0)
931 bool has_transformation = t.type() > QTransform::TxTranslate;
933 unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
936 if (has_transformation) {
937 xform.eM11 = FLOAT(t.m11());
938 xform.eM12 = FLOAT(t.m12());
939 xform.eM21 = FLOAT(t.m21());
940 xform.eM22 = FLOAT(t.m22());
944 const HDC hdc = m_fontEngineData->hdc;
946 SetGraphicsMode(hdc, GM_ADVANCED);
947 SetWorldTransform(hdc, &xform);
948 HGDIOBJ old_font = SelectObject(hdc, font);
950 const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
953 memset(&mat, 0,
sizeof(mat));
954 mat.eM11.value = mat.eM22.value = 1;
956 const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat);
958 XFORM identity = {1, 0, 0, 1, 0, 0};
959 SetWorldTransform(hdc, &identity);
960 SetGraphicsMode(hdc, GM_COMPATIBLE);
961 SelectObject(hdc, old_font);
963 if (result == GDI_ERROR) {
964 const int errorCode =
int(GetLastError());
965 qErrnoWarning(errorCode,
"QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode);
969 iw =
int(tgm.gmBlackBoxX);
970 ih =
int(tgm.gmBlackBoxY);
972 xform.eDx -= tgm.gmptGlyphOrigin.x;
973 xform.eDy += tgm.gmptGlyphOrigin.y;
976 if (glyphBoundingBoxExceedsLimit(iw, ih, effectivePixelSizeSquared(t)))
980 QWindowsNativeImage *ni =
new QWindowsNativeImage(iw + 2 * margin,
982 QWindowsNativeImage::systemFormat());
985
987 ni->image().fill(0xffffffff);
991 SelectObject(hdc, GetStockObject(NULL_BRUSH));
992 SelectObject(hdc, GetStockObject(BLACK_PEN));
993 SetTextColor(hdc, RGB(0,0,0));
994 SetBkMode(hdc, TRANSPARENT);
995 SetTextAlign(hdc, TA_BASELINE);
997 HGDIOBJ old_font = SelectObject(hdc, font);
999 if (has_transformation) {
1000 SetGraphicsMode(hdc, GM_ADVANCED);
1001 SetWorldTransform(hdc, &xform);
1002 ExtTextOut(hdc, 0, 0, options, 0,
reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
1004 ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0,
reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
1007 SelectObject(hdc, old_font);
1012 const QFixedPoint &,
1013 const QTransform &matrix,
1017 if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB)
1018 margin = glyphMargin(QFontEngine::Format_A32);
1019 glyph_metrics_t gm = boundingBox(glyph, matrix);
1020 gm.width += margin * 2;
1021 gm.height += margin * 2;
1029 bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY);
1030 if (clearTypeTemporarilyDisabled) {
1031 LOGFONT lf = m_logfont;
1032 lf.lfQuality = ANTIALIASED_QUALITY;
1033 font = CreateFontIndirect(&lf);
1035 QImage::Format mask_format = QWindowsNativeImage::systemFormat();
1036 mask_format = QImage::Format_RGB32;
1038 const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1040 if (m_fontEngineData->clearTypeEnabled)
1045 QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8);
1050 for (
int y=0; y<mask->height(); ++y) {
1051 uchar *dest = alphaMap.scanLine(y);
1052 if (mask->image().format() == QImage::Format_RGB16) {
1053 const qint16 *src =
reinterpret_cast<
const qint16 *>(mask->image().constScanLine(y));
1054 for (
int x=0; x<mask->width(); ++x)
1055 dest[x] = 255 - qGray(src[x]);
1057 const uint *src =
reinterpret_cast<
const uint *>(mask->image().constScanLine(y));
1058 for (
int x=0; x<mask->width(); ++x) {
1059 if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
1060 dest[x] = 255 - qGray(src[x]);
1062 dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1069 if (clearTypeTemporarilyDisabled) {
1076#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1077#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1080 const QFixedPoint &,
1081 const QTransform &t)
1089 int margin = glyphMargin(QFontEngine::Format_A32);
1090 QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1097 const QImage source = mask->image().depth() == 32
1099 : mask->image().convertToFormat(QImage::Format_RGB32);
1101 QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1102 for (
int y=0; y<mask->height(); ++y) {
1103 auto dest =
reinterpret_cast<uint *>(rgbMask.scanLine(y));
1104 const uint *src =
reinterpret_cast<
const uint *>(source.constScanLine(y));
1105 for (
int x=0; x<mask->width(); ++x) {
1106 dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1117 QFontDef request = fontDef;
1118 QString actualFontName = request.family();
1119 if (!uniqueFamilyName.isEmpty())
1120 request.families = QStringList(uniqueFamilyName);
1121 request.pixelSize = pixelSize;
1122 const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName);
1124 QFontEngine *fontEngine =
1125 QWindowsFontDatabase::createEngine(request, faceName,
1126 QWindowsFontDatabase::defaultVerticalDPI(),
1129 fontEngine->fontDef.families = QStringList(actualFontName);
1130 if (!uniqueFamilyName.isEmpty()) {
1131 static_cast<
QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1132 if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
1133 QPlatformFontDatabase *pfdb = pi->fontDatabase();
1134 static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1150 HDC dc = m_fontEngineData->hdc;
1151 SelectObject(dc, hfont);
1153 GetTextFace(dc, 64, n);
1154 fontDef.families = QStringList(QString::fromWCharArray(n));
1155 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1156 if (fontDef.pointSize < 0) {
1157 fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1158 }
else if (fontDef.pixelSize == -1) {
1159 fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1166 return ttf || transform.type() <= QTransform::TxTranslate;
Standard Windows font engine.
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
FaceId faceId() const override
QImage alphaMapForGlyph(glyph_t, const QTransform &xform) override
void initFontInfo(const QFontDef &request, int dpi)
void initializeHeightMetrics() const override
QFixed emSquareSize() const override
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &, const QTransform &matrix, GlyphFormat) override
qreal minLeftBearing() const override
bool hasUnreliableGlyphOutline() const override
QFontEngine * cloneWithSize(qreal pixelSize) const override
void getGlyphBearings(glyph_t glyph, qreal *leftBearing=nullptr, qreal *rightBearing=nullptr) override
QImage alphaRGBMapForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, const QTransform &xform) override
bool supportsTransformation(const QTransform &transform) const override
qreal minRightBearing() const override
Qt::HANDLE handle() const override
void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override
Properties properties() const override
int synthesized() const override
static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, QPainterPath *path, bool ttf, glyph_metrics_t *metric=nullptr, qreal scale=1.0, qreal stretch=1.0)
static const int char_table_entries
#define SPI_SETFONTSMOOTHINGCONTRAST
#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4)
static double qt_fixed_to_double(const FIXED &p)
static QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch)
static const ushort char_table[]
#define SPI_GETFONTSMOOTHINGCONTRAST