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);
73 auto otm =
reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size));
74 GetOutlineTextMetrics(hdc, size, otm);
78bool QWindowsFontEngine::hasCFFTable()
const
80 HDC hdc = m_fontEngineData->hdc;
81 SelectObject(hdc, hfont);
85bool QWindowsFontEngine::hasCMapTable()
const
87 HDC hdc = m_fontEngineData->hdc;
88 SelectObject(hdc, hfont);
92static inline QString stringFromOutLineTextMetric(
const OUTLINETEXTMETRIC *otm, PSTR offset)
94 const uchar *p =
reinterpret_cast<
const uchar *>(otm) + quintptr(offset);
95 return QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(p));
98void QWindowsFontEngine::getCMap()
100 ttf = (
bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable();
102 cffTable = hasCFFTable();
104 HDC hdc = m_fontEngineData->hdc;
105 SelectObject(hdc, hfont);
108 cmapTable = getSfntTable(QFont::Tag(
"cmap").value());
109 cmap = QFontEngine::getCMap(
reinterpret_cast<
const uchar *>(cmapTable.constData()),
110 cmapTable.size(), &symb, &cmapSize);
120 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
121 unitsPerEm =
int(otm->otmEMSquare);
122 const QFixed unitsPerEmF(unitsPerEm);
123 designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize);
124 x_height =
int(otm->otmsXHeight);
125 loadKerningPairs(designToDevice);
126 _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName));
127 lineWidth = otm->otmsUnderscoreSize;
128 fsType = otm->otmfsType;
132 unitsPerEm = tm.tmHeight;
136int QWindowsFontEngine::getGlyphIndexes(
const QChar *str,
int numChars, QGlyphLayout *glyphs,
int *mappedGlyphs)
const
142 QStringIterator it(str, str + numChars);
143 while (it.hasNext()) {
144 const uint uc = it.next();
145 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
146 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
147 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
148 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
153 QStringIterator it(str, str + numChars);
154 while (it.hasNext()) {
155 const uint uc = it.next();
156 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
157 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
162 QStringIterator it(str, str + numChars);
163 while (it.hasNext()) {
164 const uint uc = it.next();
165 if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar)
166 glyphs->glyphs[glyph_pos] = uc;
168 glyphs->glyphs[glyph_pos] = 0;
169 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
175 glyphs->numGlyphs = glyph_pos;
180
181
182
183
184
185
187QWindowsFontEngine::QWindowsFontEngine(
const QString &name,
189 const QSharedPointer<QWindowsFontEngineData> &fontEngineData)
191 m_fontEngineData(fontEngineData),
197 qCDebug(lcQpaFonts) <<
__FUNCTION__ << name << lf.lfHeight;
198 hfont = CreateFontIndirect(&m_logfont);
200 qErrnoWarning(
"%s: CreateFontIndirect failed for family '%s'",
__FUNCTION__, qPrintable(name));
201 hfont = QWindowsFontDatabase::systemFont();
204 HDC hdc = m_fontEngineData->hdc;
205 SelectObject(hdc, hfont);
206 const BOOL res = GetTextMetrics(hdc, &tm);
208 qErrnoWarning(
"%s: GetTextMetrics failed",
__FUNCTION__);
209 ZeroMemory(&tm,
sizeof(TEXTMETRIC));
212 fontDef.pixelSize = -lf.lfHeight;
213 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
215 cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
218 hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0;
221QWindowsFontEngine::~QWindowsFontEngine()
224 free(designAdvances);
230 SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont());
232 if (!DeleteObject(hfont))
233 qErrnoWarning(
"%s: QFontEngineWin: failed to delete font...",
__FUNCTION__);
234 qCDebug(lcQpaFonts) <<
__FUNCTION__ << _name;
236 if (!uniqueFamilyName.isEmpty()) {
237 if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
238 QPlatformFontDatabase *pfdb = pi->fontDatabase();
239 static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
244glyph_t QWindowsFontEngine::glyphIndex(uint ucs4)
const
249 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
250 if (glyph == 0 && ucs4 < 0x100)
251 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
253 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
254 }
else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
261HGDIOBJ QWindowsFontEngine::selectDesignFont()
const
263 LOGFONT f = m_logfont;
264 f.lfHeight = -unitsPerEm;
266 HFONT designFont = CreateFontIndirect(&f);
267 return SelectObject(m_fontEngineData->hdc, designFont);
270int QWindowsFontEngine::stringToCMap(
const QChar *str,
int len, QGlyphLayout *glyphs,
int *nglyphs, QFontEngine::ShaperFlags flags)
const
272 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
273 if (*nglyphs < len) {
278 glyphs->numGlyphs = *nglyphs;
280 *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
282 if (!(flags & GlyphIndicesOnly))
283 recalcAdvances(glyphs, flags);
288inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph,
int &width)
290 GetCharWidthI(hdc, glyph, 1, 0, &width);
293void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags)
const
296 HDC hdc = m_fontEngineData->hdc;
297 if (ttf && (flags & DesignMetrics)) {
298 for(
int i = 0; i < glyphs->numGlyphs; i++) {
299 unsigned int glyph = glyphs->glyphs[i];
300 if (
int(glyph) >= designAdvancesSize) {
301 const int newSize =
int(glyph + 256) >> 8 << 8;
302 designAdvances =
reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) *
sizeof(QFixed)));
303 Q_CHECK_PTR(designAdvances);
304 for(
int i = designAdvancesSize; i < newSize; ++i)
305 designAdvances[i] = -1000000;
306 designAdvancesSize = newSize;
308 if (designAdvances[glyph] < -999999) {
310 oldFont = selectDesignFont();
313 calculateTTFGlyphWidth(hdc, glyph, width);
314 designAdvances[glyph] = QFixed(width) / designToDevice;
316 glyphs->advances[i] = designAdvances[glyph];
319 DeleteObject(SelectObject(hdc, oldFont));
321 for(
int i = 0; i < glyphs->numGlyphs; i++) {
322 unsigned int glyph = glyphs->glyphs[i];
324 if (glyph >= widthCacheSize) {
325 const uint newSize = (glyph + 256) >> 8 << 8;
326 widthCache =
reinterpret_cast<
unsigned char *>(realloc(widthCache, newSize *
sizeof(QFixed)));
327 Q_CHECK_PTR(widthCache);
328 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
329 widthCacheSize = newSize;
331 glyphs->advances[i] = widthCache[glyph];
333 if (glyphs->advances[i].value() == 0) {
336 oldFont = SelectObject(hdc, hfont);
339 QChar ch[2] = { ushort(glyph), u'\0' };
341 if (QChar::requiresSurrogates(glyph)) {
342 ch[0] = QChar::highSurrogate(glyph);
343 ch[1] = QChar::lowSurrogate(glyph);
347 GetTextExtentPoint32(hdc,
reinterpret_cast<
const wchar_t *>(ch), chrLen, &size);
350 calculateTTFGlyphWidth(hdc, glyph, width);
352 glyphs->advances[i] = width;
354 if (width > 0 && width < 0x100)
355 widthCache[glyph] = uchar(width);
360 SelectObject(hdc, oldFont);
364bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph,
const QTransform &t, glyph_metrics_t *metrics)
const
366 Q_ASSERT(metrics != 0);
368 HDC hdc = m_fontEngineData->hdc;
373 mat.eM11.value = mat.eM22.value = 1;
374 mat.eM11.fract = mat.eM22.fract = 0;
375 mat.eM21.value = mat.eM12.value = 0;
376 mat.eM21.fract = mat.eM12.fract = 0;
378 if (t.type() > QTransform::TxTranslate) {
384 xform.eM11 = FLOAT(t.m11());
385 xform.eM12 = FLOAT(t.m12());
386 xform.eM21 = FLOAT(t.m21());
387 xform.eM22 = FLOAT(t.m22());
390 SetGraphicsMode(hdc, GM_ADVANCED);
391 SetWorldTransform(hdc, &xform);
394 uint format = GGO_METRICS;
396 format |= GGO_GLYPH_INDEX;
397 res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
399 if (t.type() > QTransform::TxTranslate) {
401 xform.eM11 = xform.eM22 = 1;
402 xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
403 SetWorldTransform(hdc, &xform);
404 SetGraphicsMode(hdc, GM_COMPATIBLE);
407 if (res != GDI_ERROR) {
408 *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
409 int(gm.gmBlackBoxX),
int(gm.gmBlackBoxY),
410 gm.gmCellIncX, gm.gmCellIncY);
417glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph,
const QTransform &t)
419 HDC hdc = m_fontEngineData->hdc;
420 SelectObject(hdc, hfont);
422 glyph_metrics_t glyphMetrics;
423 bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
425 if (!ttf && !success) {
427 wchar_t ch =
wchar_t(glyph);
429 GetCharABCWidthsFloat(hdc, ch, ch, &abc);
430 int width = qRound(abc.abcfB);
432 return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
448 qint16 subscriptXSize;
449 qint16 subscriptYSize;
450 qint16 subscriptXOffset;
451 qint16 subscriptYOffset;
452 qint16 superscriptXSize;
453 qint16 superscriptYSize;
454 qint16 superscriptXOffset;
455 qint16 superscriptYOffset;
456 qint16 strikeOutSize;
457 qint16 strikeOutPosition;
460 quint32 unicodeRanges[4];
463 quint16 firstCharIndex;
464 quint16 lastCharIndex;
466 qint16 typoDescender;
470 quint32 codepageRanges[2];
481QFixed QWindowsFontEngine::capHeight()
const
483 const QByteArray tableData = getSfntTable(QFont::Tag(
"OS/2").value());
484 if (size_t(tableData.size()) >=
sizeof(OS2Table)) {
485 const OS2Table *table =
reinterpret_cast<
const OS2Table *>(tableData.constData());
486 if (qFromBigEndian<quint16>(table->version) >= 2) {
487 qint16 capHeight = qFromBigEndian<qint16>(table->capHeight);
489 return QFixed(capHeight) / designToDevice;
492 return calculatedCapHeight();
495QFixed QWindowsFontEngine::xHeight()
const
499 return QFontEngine::xHeight();
502QFixed QWindowsFontEngine::averageCharWidth()
const
504 return tm.tmAveCharWidth;
507qreal QWindowsFontEngine::maxCharWidth()
const
509 return tm.tmMaxCharWidth;
512enum { max_font_count = 256 };
540 HDC hdc = m_fontEngineData->hdc;
541 SelectObject(hdc, hfont);
545 GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
547 *leftBearing = abcWidths.abcA;
549 *rightBearing = abcWidths.abcC;
551 QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
558 m_ascent = tm.tmAscent;
559 m_descent = tm.tmDescent;
560 m_leading = tm.tmExternalLeading;
562 QFontEngine::initializeHeightMetrics();
567 return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline();
572 if (lbearing == SHRT_MIN)
580 if (rbearing == SHRT_MIN) {
583 HDC hdc = m_fontEngineData->hdc;
584 SelectObject(hdc, hfont);
587 int n = tm.tmLastChar - tm.tmFirstChar;
588 if (n <= max_font_count) {
590 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
592 abc =
new ABC[char_table_entries+1];
594 GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
599 for (
int i = 1; i < n; i++) {
600 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
601 ml = qMin(ml,abc[i].abcA);
602 mr = qMin(mr,abc[i].abcC);
608 int n = tm.tmLastChar - tm.tmFirstChar+1;
609 if (n <= max_font_count) {
610 abc =
new ABCFLOAT[n];
611 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
613 abc =
new ABCFLOAT[char_table_entries];
615 GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
618 float fml = abc[0].abcfA;
619 float fmr = abc[0].abcfC;
620 for (
int i=1; i<n; i++) {
621 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
622 fml = qMin(fml,abc[i].abcfA);
623 fmr = qMin(fmr,abc[i].abcfC);
638 return ((p.value << 16) + p.fract) / 65536.0;
642 return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
646#define GGO_UNHINTED 0x0100
650 QPainterPath *path,
bool ttf, glyph_metrics_t *metric =
nullptr,
651 qreal scale = 1.0, qreal stretch = 1.0)
654 mat.eM11.value = mat.eM22.value = 1;
655 mat.eM11.fract = mat.eM22.fract = 0;
656 mat.eM21.value = mat.eM12.value = 0;
657 mat.eM21.fract = mat.eM12.fract = 0;
659 GLYPHMETRICS gMetric;
660 memset(&gMetric, 0,
sizeof(GLYPHMETRICS));
666 uint format = GGO_METRICS;
668 format |= GGO_GLYPH_INDEX;
669 if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR)
672 *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
673 int(gMetric.gmBlackBoxX),
int(gMetric.gmBlackBoxY),
674 gMetric.gmCellIncX, gMetric.gmCellIncY);
677 uint glyphFormat = GGO_NATIVE;
680 glyphFormat |= GGO_GLYPH_INDEX;
682 const DWORD bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
683 if (bufferSize == GDI_ERROR)
686 char *dataBuffer =
new char[bufferSize];
687 DWORD ret = GDI_ERROR;
688 ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
689 if (ret == GDI_ERROR) {
690 delete [] dataBuffer;
695 DWORD headerOffset = 0;
697 QPointF oset = position.toPointF();
698 while (headerOffset < bufferSize) {
699 const TTPOLYGONHEADER *ttph =
reinterpret_cast<
const TTPOLYGONHEADER *>(dataBuffer + headerOffset);
701 QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
702 path->moveTo(lastPoint + oset);
703 offset +=
sizeof(TTPOLYGONHEADER);
704 while (offset < headerOffset + ttph->cb) {
705 const TTPOLYCURVE *curve =
reinterpret_cast<
const TTPOLYCURVE *>(dataBuffer + offset);
706 switch (curve->wType) {
708 for (
int i=0; i<curve->cpfx; ++i) {
709 QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
714 case TT_PRIM_QSPLINE: {
715 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
716 QPointF prev(elm.x, elm.y);
718 for (
int i=0; i<curve->cpfx - 1; ++i) {
719 QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
720 QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
721 if (i < curve->cpfx - 2) {
722 endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
727 path->quadTo(p1, endPoint);
734 for (
int i=0; i<curve->cpfx; ) {
735 QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
736 QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
737 QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
738 path->cubicTo(p2, p3, p4);
743 qWarning(
"QFontEngineWin::addOutlineToPath, unhandled switch case");
745 offset +=
sizeof(TTPOLYCURVE) + (curve->cpfx-1) *
sizeof(POINTFX);
747 path->closeSubpath();
748 headerOffset += ttph->cb;
750 delete [] dataBuffer;
758 LOGFONT lf = m_logfont;
763 lf.lfHeight = -unitsPerEm;
765 HFONT hf = CreateFontIndirect(&lf);
766 HDC hdc = m_fontEngineData->hdc;
767 HGDIOBJ oldfont = SelectObject(hdc, hf);
769 qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
770 qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
771 for(
int i = 0; i < nglyphs; ++i) {
772 if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, 0,
782 DeleteObject(SelectObject(hdc, oldfont));
786 QPainterPath *path, QTextItem::RenderFlags flags)
788 if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
790 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
798 QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
806QT_BEGIN_INCLUDE_NAMESPACE
808QT_END_INCLUDE_NAMESPACE
812 if (synthesized_flags == -1) {
813 synthesized_flags = 0;
816 HDC hdc = m_fontEngineData->hdc;
817 SelectObject(hdc, hfont);
819 GetFontData(hdc, HEAD, 44, &data, 4);
820 USHORT macStyle = qt_getUShort(data);
821 if (tm.tmItalic && !(macStyle & 2))
822 synthesized_flags = SynthesizedItalic;
823 if (fontDef.stretch != 100 && ttf)
824 synthesized_flags |= SynthesizedStretch;
825 if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1))
826 synthesized_flags |= SynthesizedBold;
831 return synthesized_flags;
841 LOGFONT lf = m_logfont;
842 lf.lfHeight = unitsPerEm;
843 HFONT hf = CreateFontIndirect(&lf);
844 HDC hdc = m_fontEngineData->hdc;
845 HGDIOBJ oldfont = SelectObject(hdc, hf);
846 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
848 p.emSquare = unitsPerEm;
849 p.italicAngle = otm->otmItalicAngle;
850 const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1()
851 + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1();
852 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name);
853 p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
854 otm->otmrcFontBox.right - otm->otmrcFontBox.left,
855 otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
856 p.ascent = otm->otmAscent;
857 p.descent = -otm->otmDescent;
858 p.leading =
int(otm->otmLineGap);
860 p.lineWidth = otm->otmsUnderscoreSize;
862 DeleteObject(SelectObject(hdc, oldfont));
868 LOGFONT lf = m_logfont;
869 lf.lfHeight = -unitsPerEm;
871 if (flags & SynthesizedItalic)
874 HFONT hf = CreateFontIndirect(&lf);
875 HDC hdc = m_fontEngineData->hdc;
876 HGDIOBJ oldfont = SelectObject(hdc, hf);
880 addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
881 DeleteObject(SelectObject(hdc, oldfont));
886 if (!ttf && !cffTable)
888 HDC hdc = m_fontEngineData->hdc;
889 SelectObject(hdc, hfont);
890 DWORD t = qbswap<quint32>(tag);
891 *length = GetFontData(hdc, t, 0, buffer, *length);
892 Q_ASSERT(*length == GDI_ERROR ||
int(*length) > 0);
893 return *length != GDI_ERROR;
896#if !defined(CLEARTYPE_QUALITY)
897# define CLEARTYPE_QUALITY 5
900QWindowsNativeImage *
QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
int margin,
902 QImage::Format mask_format)
904 Q_UNUSED(mask_format);
905 glyph_metrics_t gm = boundingBox(glyph);
909 int gx = gm.x.toInt();
910 int gy = gm.y.toInt();
911 int iw = gm.width.toInt();
912 int ih = gm.height.toInt();
914 if (iw <= 0 || ih <= 0)
917 bool has_transformation = t.type() > QTransform::TxTranslate;
919 unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
922 if (has_transformation) {
923 xform.eM11 = FLOAT(t.m11());
924 xform.eM12 = FLOAT(t.m12());
925 xform.eM21 = FLOAT(t.m21());
926 xform.eM22 = FLOAT(t.m22());
930 const HDC hdc = m_fontEngineData->hdc;
932 SetGraphicsMode(hdc, GM_ADVANCED);
933 SetWorldTransform(hdc, &xform);
934 HGDIOBJ old_font = SelectObject(hdc, font);
936 const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
939 memset(&mat, 0,
sizeof(mat));
940 mat.eM11.value = mat.eM22.value = 1;
942 const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat);
944 XFORM identity = {1, 0, 0, 1, 0, 0};
945 SetWorldTransform(hdc, &identity);
946 SetGraphicsMode(hdc, GM_COMPATIBLE);
947 SelectObject(hdc, old_font);
949 if (result == GDI_ERROR) {
950 const int errorCode =
int(GetLastError());
951 qErrnoWarning(errorCode,
"QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode);
955 iw =
int(tgm.gmBlackBoxX);
956 ih =
int(tgm.gmBlackBoxY);
958 xform.eDx -= tgm.gmptGlyphOrigin.x;
959 xform.eDy += tgm.gmptGlyphOrigin.y;
963 QWindowsNativeImage *ni =
new QWindowsNativeImage(iw + 2 * margin,
965 QWindowsNativeImage::systemFormat());
968
970 ni->image().fill(0xffffffff);
974 SelectObject(hdc, GetStockObject(NULL_BRUSH));
975 SelectObject(hdc, GetStockObject(BLACK_PEN));
976 SetTextColor(hdc, RGB(0,0,0));
977 SetBkMode(hdc, TRANSPARENT);
978 SetTextAlign(hdc, TA_BASELINE);
980 HGDIOBJ old_font = SelectObject(hdc, font);
982 if (has_transformation) {
983 SetGraphicsMode(hdc, GM_ADVANCED);
984 SetWorldTransform(hdc, &xform);
985 ExtTextOut(hdc, 0, 0, options, 0,
reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
987 ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0,
reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
990 SelectObject(hdc, old_font);
996 const QTransform &matrix,
1000 if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB)
1001 margin = glyphMargin(QFontEngine::Format_A32);
1002 glyph_metrics_t gm = boundingBox(glyph, matrix);
1003 gm.width += margin * 2;
1004 gm.height += margin * 2;
1012 bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY);
1013 if (clearTypeTemporarilyDisabled) {
1014 LOGFONT lf = m_logfont;
1015 lf.lfQuality = ANTIALIASED_QUALITY;
1016 font = CreateFontIndirect(&lf);
1018 QImage::Format mask_format = QWindowsNativeImage::systemFormat();
1019 mask_format = QImage::Format_RGB32;
1021 const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1023 if (m_fontEngineData->clearTypeEnabled)
1028 QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8);
1033 for (
int y=0; y<mask->height(); ++y) {
1034 uchar *dest = alphaMap.scanLine(y);
1035 if (mask->image().format() == QImage::Format_RGB16) {
1036 const qint16 *src =
reinterpret_cast<
const qint16 *>(mask->image().constScanLine(y));
1037 for (
int x=0; x<mask->width(); ++x)
1038 dest[x] = 255 - qGray(src[x]);
1040 const uint *src =
reinterpret_cast<
const uint *>(mask->image().constScanLine(y));
1041 for (
int x=0; x<mask->width(); ++x) {
1042 if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
1043 dest[x] = 255 - qGray(src[x]);
1045 dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1052 if (clearTypeTemporarilyDisabled) {
1059#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1060#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1063 const QFixedPoint &,
1064 const QTransform &t)
1072 int margin = glyphMargin(QFontEngine::Format_A32);
1073 QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1080 const QImage source = mask->image().depth() == 32
1082 : mask->image().convertToFormat(QImage::Format_RGB32);
1084 QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1085 for (
int y=0; y<mask->height(); ++y) {
1086 auto dest =
reinterpret_cast<uint *>(rgbMask.scanLine(y));
1087 const uint *src =
reinterpret_cast<
const uint *>(source.constScanLine(y));
1088 for (
int x=0; x<mask->width(); ++x) {
1089 dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1100 QFontDef request = fontDef;
1101 QString actualFontName = request.families.constFirst();
1102 if (!uniqueFamilyName.isEmpty())
1103 request.families = QStringList(uniqueFamilyName);
1104 request.pixelSize = pixelSize;
1105 const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName);
1107 QFontEngine *fontEngine =
1108 QWindowsFontDatabase::createEngine(request, faceName,
1109 QWindowsFontDatabase::defaultVerticalDPI(),
1112 fontEngine->fontDef.families = QStringList(actualFontName);
1113 if (!uniqueFamilyName.isEmpty()) {
1114 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1115 if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) {
1116 QPlatformFontDatabase *pfdb = pi->fontDatabase();
1117 static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1133 HDC dc = m_fontEngineData->hdc;
1134 SelectObject(dc, hfont);
1136 GetTextFace(dc, 64, n);
1137 fontDef.families = QStringList(QString::fromWCharArray(n));
1138 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1139 if (fontDef.pointSize < 0) {
1140 fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1141 }
else if (fontDef.pixelSize == -1) {
1142 fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1149 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