Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsfontengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7#include <QtCore/qt_windows.h>
8#if QT_CONFIG(directwrite)
10#endif
11#include <QtGui/qpa/qplatformintegration.h>
12#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
13#include <QtGui/private/qguiapplication_p.h>
14#include <QtGui/QPaintDevice>
15#include <QtGui/QBitmap>
16#include <QtGui/QPainter>
17#include <QtGui/private/qpainter_p.h>
18#include <QtGui/QPaintEngine>
19#include <QtGui/private/qpaintengine_raster_p.h>
20#include <QtGui/private/qtgui-config_p.h>
21
22#include <QtCore/QtEndian>
23#include <QtCore/QFile>
24#include <QtCore/qmath.h>
25#include <QtCore/QTextStream>
26#include <QtCore/QThreadStorage>
27#include <QtCore/private/qsystemlibrary_p.h>
28#include <QtCore/private/qstringiterator_p.h>
29
30#include <QtCore/QDebug>
31
32#include <limits.h>
33
34#if QT_CONFIG(directwrite)
35# include <dwrite.h>
36# include <comdef.h>
37#endif
38
40
43
44//### mingw needed define
45#ifndef TT_PRIM_CSPLINE
46#define TT_PRIM_CSPLINE 3
47#endif
48
49// GetFontData expects the tags in little endian ;(
50#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (\
51 (((quint32)(ch4)) << 24) | \
52 (((quint32)(ch3)) << 16) | \
53 (((quint32)(ch2)) << 8) | \
54 ((quint32)(ch1)) \
55 )
56
57// common DC for all fonts
58
59// general font engine
60
62{
63 if (lineWidth > 0)
64 return lineWidth;
65
67}
68
69static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
70{
71 const auto size = GetOutlineTextMetrics(hdc, 0, nullptr);
72 auto otm = reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size));
73 GetOutlineTextMetrics(hdc, size, otm);
74 return otm;
75}
76
77bool QWindowsFontEngine::hasCFFTable() const
78{
79 HDC hdc = m_fontEngineData->hdc;
80 SelectObject(hdc, hfont);
81 return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR;
82}
83
84bool QWindowsFontEngine::hasCMapTable() const
85{
86 HDC hdc = m_fontEngineData->hdc;
87 SelectObject(hdc, hfont);
88 return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR;
89}
90
91static inline QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset)
92{
93 const uchar *p = reinterpret_cast<const uchar *>(otm) + quintptr(offset);
94 return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(p));
95}
96
98{
99 ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable();
100
101 cffTable = hasCFFTable();
102
103 HDC hdc = m_fontEngineData->hdc;
104 SelectObject(hdc, hfont);
105 bool symb = false;
106 if (ttf) {
107 cmapTable = getSfntTable(QFont::Tag("cmap").value());
108 cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
109 cmapTable.size(), &symb, &cmapSize);
110 }
111 if (!cmap) {
112 ttf = false;
113 symb = false;
114 }
115 symbol = symb;
116 designToDevice = 1;
117 _faceId.index = 0;
118 if (cmap) {
119 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
120 unitsPerEm = int(otm->otmEMSquare);
121 const QFixed unitsPerEmF(unitsPerEm);
122 designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize);
123 x_height = int(otm->otmsXHeight);
124 loadKerningPairs(designToDevice);
125 _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName));
126 lineWidth = otm->otmsUnderscoreSize;
127 fsType = otm->otmfsType;
128 free(otm);
129
130 } else {
131 unitsPerEm = tm.tmHeight;
132 }
133}
134
135int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const
136{
137 *mappedGlyphs = 0;
138 int glyph_pos = 0;
139 {
140 if (symbol) {
141 QStringIterator it(str, str + numChars);
142 while (it.hasNext()) {
143 const uint uc = it.next();
144 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
145 if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
146 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
147 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
148 (*mappedGlyphs)++;
149 ++glyph_pos;
150 }
151 } else if (ttf) {
152 QStringIterator it(str, str + numChars);
153 while (it.hasNext()) {
154 const uint uc = it.next();
155 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
156 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
157 (*mappedGlyphs)++;
158 ++glyph_pos;
159 }
160 } else {
161 QStringIterator it(str, str + numChars);
162 while (it.hasNext()) {
163 const uint uc = it.next();
164 if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar)
165 glyphs->glyphs[glyph_pos] = uc;
166 else
167 glyphs->glyphs[glyph_pos] = 0;
168 if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
169 (*mappedGlyphs)++;
170 ++glyph_pos;
171 }
172 }
173 }
174 glyphs->numGlyphs = glyph_pos;
175 return glyph_pos;
176}
177
187 LOGFONT lf,
188 const QSharedPointer<QWindowsFontEngineData> &fontEngineData)
189 : QFontEngine(Win),
190 m_fontEngineData(fontEngineData),
191 _name(name),
192 m_logfont(lf),
193 ttf(0),
194 hasOutline(0)
195{
196 qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight;
197 hfont = CreateFontIndirect(&m_logfont);
198 if (!hfont) {
199 qErrnoWarning("%s: CreateFontIndirect failed for family '%s'", __FUNCTION__, qPrintable(name));
201 }
202
203 HDC hdc = m_fontEngineData->hdc;
204 SelectObject(hdc, hfont);
205 const BOOL res = GetTextMetrics(hdc, &tm);
206 if (!res) {
207 qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
208 ZeroMemory(&tm, sizeof(TEXTMETRIC));
209 }
210
211 fontDef.pixelSize = -lf.lfHeight;
212 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
213
214 cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
215 getCMap();
216
217 hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0;
218}
219
221{
222 if (designAdvances)
223 free(designAdvances);
224
225 if (widthCache)
226 free(widthCache);
227
228 // make sure we aren't by accident still selected
229 SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont());
230
231 if (!DeleteObject(hfont))
232 qErrnoWarning("%s: QFontEngineWin: failed to delete font...", __FUNCTION__);
233 qCDebug(lcQpaFonts) << __FUNCTION__ << _name;
234
235 if (!uniqueFamilyName.isEmpty()) {
237 QPlatformFontDatabase *pfdb = pi->fontDatabase();
238 static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName);
239 }
240 }
241}
242
244{
245 glyph_t glyph = 0;
246
247 if (symbol) {
248 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
249 if (glyph == 0 && ucs4 < 0x100)
250 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
251 } else if (ttf) {
252 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
253 } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) {
254 glyph = ucs4;
255 }
256
257 return glyph;
258}
259
261{
262 LOGFONT f = m_logfont;
263 f.lfHeight = -unitsPerEm;
264 f.lfWidth = 0;
265 HFONT designFont = CreateFontIndirect(&f);
266 return SelectObject(m_fontEngineData->hdc, designFont);
267}
268
269int QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
270{
271 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
272 if (*nglyphs < len) {
273 *nglyphs = len;
274 return false;
275 }
276
277 glyphs->numGlyphs = *nglyphs;
278 int mappedGlyphs;
279 *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
280
281 if (!(flags & GlyphIndicesOnly))
282 recalcAdvances(glyphs, flags);
283
284 return mappedGlyphs;
285}
286
287inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
288{
289 GetCharWidthI(hdc, glyph, 1, 0, &width);
290}
291
292void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
293{
294 HGDIOBJ oldFont = 0;
295 HDC hdc = m_fontEngineData->hdc;
296 if (ttf && (flags & DesignMetrics)) {
297 for(int i = 0; i < glyphs->numGlyphs; i++) {
298 unsigned int glyph = glyphs->glyphs[i];
299 if (int(glyph) >= designAdvancesSize) {
300 const int newSize = int(glyph + 256) >> 8 << 8;
301 designAdvances = reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) * sizeof(QFixed)));
302 Q_CHECK_PTR(designAdvances);
303 for(int i = designAdvancesSize; i < newSize; ++i)
304 designAdvances[i] = -1000000;
305 designAdvancesSize = newSize;
306 }
307 if (designAdvances[glyph] < -999999) {
308 if (!oldFont)
309 oldFont = selectDesignFont();
310
311 int width = 0;
312 calculateTTFGlyphWidth(hdc, glyph, width);
313 designAdvances[glyph] = QFixed(width) / designToDevice;
314 }
315 glyphs->advances[i] = designAdvances[glyph];
316 }
317 if (oldFont)
318 DeleteObject(SelectObject(hdc, oldFont));
319 } else {
320 for(int i = 0; i < glyphs->numGlyphs; i++) {
321 unsigned int glyph = glyphs->glyphs[i];
322
323 if (glyph >= widthCacheSize) {
324 const uint newSize = (glyph + 256) >> 8 << 8;
325 widthCache = reinterpret_cast<unsigned char *>(realloc(widthCache, newSize * sizeof(QFixed)));
326 Q_CHECK_PTR(widthCache);
327 memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
328 widthCacheSize = newSize;
329 }
330 glyphs->advances[i] = widthCache[glyph];
331 // font-width cache failed
332 if (glyphs->advances[i].value() == 0) {
333 int width = 0;
334 if (!oldFont)
335 oldFont = SelectObject(hdc, hfont);
336
337 if (!ttf) {
338 QChar ch[2] = { ushort(glyph), u'\0' };
339 int chrLen = 1;
340 if (QChar::requiresSurrogates(glyph)) {
341 ch[0] = QChar::highSurrogate(glyph);
342 ch[1] = QChar::lowSurrogate(glyph);
343 ++chrLen;
344 }
345 SIZE size = {0, 0};
346 GetTextExtentPoint32(hdc, reinterpret_cast<const wchar_t *>(ch), chrLen, &size);
347 width = size.cx;
348 } else {
349 calculateTTFGlyphWidth(hdc, glyph, width);
350 }
351 glyphs->advances[i] = width;
352 // if glyph's within cache range, store it for later
353 if (width > 0 && width < 0x100)
354 widthCache[glyph] = uchar(width);
355 }
356 }
357
358 if (oldFont)
359 SelectObject(hdc, oldFont);
360 }
361}
362
364{
365 Q_ASSERT(metrics != 0);
366
367 HDC hdc = m_fontEngineData->hdc;
368
369 GLYPHMETRICS gm;
370 DWORD res = 0;
371 MAT2 mat;
372 mat.eM11.value = mat.eM22.value = 1;
373 mat.eM11.fract = mat.eM22.fract = 0;
374 mat.eM21.value = mat.eM12.value = 0;
375 mat.eM21.fract = mat.eM12.fract = 0;
376
377 if (t.type() > QTransform::TxTranslate) {
378 // We need to set the transform using the HDC's world
379 // matrix rather than using the MAT2 above, because the
380 // results provided when transforming via MAT2 does not
381 // match the glyphs that are drawn using a WorldTransform
382 XFORM xform;
383 xform.eM11 = FLOAT(t.m11());
384 xform.eM12 = FLOAT(t.m12());
385 xform.eM21 = FLOAT(t.m21());
386 xform.eM22 = FLOAT(t.m22());
387 xform.eDx = 0;
388 xform.eDy = 0;
389 SetGraphicsMode(hdc, GM_ADVANCED);
390 SetWorldTransform(hdc, &xform);
391 }
392
393 uint format = GGO_METRICS;
394 if (ttf)
395 format |= GGO_GLYPH_INDEX;
396 res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
397
398 if (t.type() > QTransform::TxTranslate) {
399 XFORM xform;
400 xform.eM11 = xform.eM22 = 1;
401 xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
402 SetWorldTransform(hdc, &xform);
403 SetGraphicsMode(hdc, GM_COMPATIBLE);
404 }
405
406 if (res != GDI_ERROR) {
407 *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
408 int(gm.gmBlackBoxX), int(gm.gmBlackBoxY),
409 gm.gmCellIncX, gm.gmCellIncY);
410 return true;
411 } else {
412 return false;
413 }
414}
415
417{
418 HDC hdc = m_fontEngineData->hdc;
419 SelectObject(hdc, hfont);
420
421 glyph_metrics_t glyphMetrics;
422 bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
423
424 if (!ttf && !success) {
425 // Bitmap fonts
426 wchar_t ch = wchar_t(glyph);
427 ABCFLOAT abc;
428 GetCharABCWidthsFloat(hdc, ch, ch, &abc);
429 int width = qRound(abc.abcfB);
430
431 return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
432 }
433
434 return glyphMetrics;
435}
436
437namespace {
438# pragma pack(1)
439
440 struct OS2Table
441 {
442 quint16 version;
443 qint16 avgCharWidth;
444 quint16 weightClass;
445 quint16 widthClass;
447 qint16 subscriptXSize;
448 qint16 subscriptYSize;
449 qint16 subscriptXOffset;
450 qint16 subscriptYOffset;
451 qint16 superscriptXSize;
452 qint16 superscriptYSize;
453 qint16 superscriptXOffset;
454 qint16 superscriptYOffset;
455 qint16 strikeOutSize;
456 qint16 strikeOutPosition;
457 qint16 familyClass;
458 quint8 panose[10];
459 quint32 unicodeRanges[4];
460 quint8 vendorID[4];
462 quint16 firstCharIndex;
463 quint16 lastCharIndex;
464 qint16 typoAscender;
465 qint16 typoDescender;
466 qint16 typoLineGap;
467 quint16 winAscent;
468 quint16 winDescent;
469 quint32 codepageRanges[2];
471 qint16 capHeight;
472 quint16 defaultChar;
473 quint16 breakChar;
474 quint16 maxContext;
475 };
476
477# pragma pack()
478}
479
481{
482 const QByteArray tableData = getSfntTable(QFont::Tag("OS/2").value());
483 if (size_t(tableData.size()) >= sizeof(OS2Table)) {
484 const OS2Table *table = reinterpret_cast<const OS2Table *>(tableData.constData());
485 if (qFromBigEndian<quint16>(table->version) >= 2) {
486 qint16 capHeight = qFromBigEndian<qint16>(table->capHeight);
487 if (capHeight > 0)
488 return QFixed(capHeight) / designToDevice;
489 }
490 }
491 return calculatedCapHeight();
492}
493
495{
496 if (x_height >= 0)
497 return x_height;
498 return QFontEngine::xHeight();
499}
500
502{
503 return tm.tmAveCharWidth;
504}
505
507{
508 return tm.tmMaxCharWidth;
509}
510
511enum { max_font_count = 256 };
512static const ushort char_table[] = {
513 40,
514 67,
515 70,
516 75,
517 86,
518 88,
519 89,
520 91,
521 102,
522 114,
523 124,
524 127,
525 205,
526 645,
527 884,
528 922,
529 1070,
530 12386,
531 0
532};
533
534static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
535
536#ifndef Q_CC_MINGW
537void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
538{
539 HDC hdc = m_fontEngineData->hdc;
540 SelectObject(hdc, hfont);
541
542 if (ttf) {
543 ABC abcWidths;
544 GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
545 if (leftBearing)
546 *leftBearing = abcWidths.abcA;
547 if (rightBearing)
548 *rightBearing = abcWidths.abcC;
549 } else {
550 QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
551 }
552}
553#endif // Q_CC_MINGW
554
556{
557 m_ascent = tm.tmAscent;
558 m_descent = tm.tmDescent;
559 m_leading = tm.tmExternalLeading;
560
562}
563
565{
566 return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline();
567}
568
570{
571 if (lbearing == SHRT_MIN)
572 minRightBearing(); // calculates both
573
574 return lbearing;
575}
576
578{
579 if (rbearing == SHRT_MIN) {
580 int ml = 0;
581 int mr = 0;
582 HDC hdc = m_fontEngineData->hdc;
583 SelectObject(hdc, hfont);
584 if (ttf) {
585 ABC *abc = nullptr;
586 int n = tm.tmLastChar - tm.tmFirstChar;
587 if (n <= max_font_count) {
588 abc = new ABC[n+1];
589 GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
590 } else {
591 abc = new ABC[char_table_entries+1];
592 for(int i = 0; i < char_table_entries; i++)
593 GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
595 }
596 ml = abc[0].abcA;
597 mr = abc[0].abcC;
598 for (int i = 1; i < n; i++) {
599 if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
600 ml = qMin(ml,abc[i].abcA);
601 mr = qMin(mr,abc[i].abcC);
602 }
603 }
604 delete [] abc;
605 } else {
606 ABCFLOAT *abc = 0;
607 int n = tm.tmLastChar - tm.tmFirstChar+1;
608 if (n <= max_font_count) {
609 abc = new ABCFLOAT[n];
610 GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
611 } else {
612 abc = new ABCFLOAT[char_table_entries];
613 for(int i = 0; i < char_table_entries; i++)
614 GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
616 }
617 float fml = abc[0].abcfA;
618 float fmr = abc[0].abcfC;
619 for (int i=1; i<n; i++) {
620 if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
621 fml = qMin(fml,abc[i].abcfA);
622 fmr = qMin(fmr,abc[i].abcfC);
623 }
624 }
625 ml = qFloor(fml);
626 mr = qFloor(fmr);
627 delete [] abc;
628 }
629 lbearing = ml;
630 rbearing = mr;
631 }
632
633 return rbearing;
634}
635
636static inline double qt_fixed_to_double(const FIXED &p) {
637 return ((p.value << 16) + p.fract) / 65536.0;
638}
639
640static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) {
641 return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
642}
643
644#ifndef GGO_UNHINTED
645#define GGO_UNHINTED 0x0100
646#endif
647
648static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
649 QPainterPath *path, bool ttf, glyph_metrics_t *metric = nullptr,
650 qreal scale = 1.0, qreal stretch = 1.0)
651{
652 MAT2 mat;
653 mat.eM11.value = mat.eM22.value = 1;
654 mat.eM11.fract = mat.eM22.fract = 0;
655 mat.eM21.value = mat.eM12.value = 0;
656 mat.eM21.fract = mat.eM12.fract = 0;
657
658 GLYPHMETRICS gMetric;
659 memset(&gMetric, 0, sizeof(GLYPHMETRICS));
660
661 if (metric) {
662 // If metrics requested, retrieve first using GGO_METRICS, because the returned
663 // values are incorrect for OpenType PS fonts if obtained at the same time as the
664 // glyph paths themselves (ie. with GGO_NATIVE as the format).
665 uint format = GGO_METRICS;
666 if (ttf)
667 format |= GGO_GLYPH_INDEX;
668 if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR)
669 return false;
670 // #### obey scale
671 *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
672 int(gMetric.gmBlackBoxX), int(gMetric.gmBlackBoxY),
673 gMetric.gmCellIncX, gMetric.gmCellIncY);
674 }
675
676 uint glyphFormat = GGO_NATIVE;
677
678 if (ttf)
679 glyphFormat |= GGO_GLYPH_INDEX;
680
681 const DWORD bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
682 if (bufferSize == GDI_ERROR)
683 return false;
684
685 char *dataBuffer = new char[bufferSize];
686 DWORD ret = GDI_ERROR;
687 ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
688 if (ret == GDI_ERROR) {
689 delete [] dataBuffer;
690 return false;
691 }
692
693 DWORD offset = 0;
694 DWORD headerOffset = 0;
695
696 QPointF oset = position.toPointF();
697 while (headerOffset < bufferSize) {
698 const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset);
699
700 QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
701 path->moveTo(lastPoint + oset);
702 offset += sizeof(TTPOLYGONHEADER);
703 while (offset < headerOffset + ttph->cb) {
704 const TTPOLYCURVE *curve = reinterpret_cast<const TTPOLYCURVE *>(dataBuffer + offset);
705 switch (curve->wType) {
706 case TT_PRIM_LINE: {
707 for (int i=0; i<curve->cpfx; ++i) {
708 QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
709 path->lineTo(p);
710 }
711 break;
712 }
713 case TT_PRIM_QSPLINE: {
714 const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
715 QPointF prev(elm.x, elm.y);
716 QPointF endPoint;
717 for (int i=0; i<curve->cpfx - 1; ++i) {
718 QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
719 QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
720 if (i < curve->cpfx - 2) {
721 endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
722 } else {
723 endPoint = p2;
724 }
725
726 path->quadTo(p1, endPoint);
727 prev = endPoint;
728 }
729
730 break;
731 }
732 case TT_PRIM_CSPLINE: {
733 for (int i=0; i<curve->cpfx; ) {
734 QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
735 QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
736 QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
737 path->cubicTo(p2, p3, p4);
738 }
739 break;
740 }
741 default:
742 qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
743 }
744 offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
745 }
746 path->closeSubpath();
747 headerOffset += ttph->cb;
748 }
749 delete [] dataBuffer;
750
751 return true;
752}
753
755 QPainterPath *path, QTextItem::RenderFlags)
756{
757 LOGFONT lf = m_logfont;
758 // The sign must be negative here to make sure we match against character height instead of
759 // hinted cell height. This ensures that we get linear matching, and we need this for
760 // paths since we later on apply a scaling transform to the glyph outline to get the
761 // font at the correct pixel size.
762 lf.lfHeight = -unitsPerEm;
763 lf.lfWidth = 0;
764 HFONT hf = CreateFontIndirect(&lf);
765 HDC hdc = m_fontEngineData->hdc;
766 HGDIOBJ oldfont = SelectObject(hdc, hf);
767
768 qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
769 qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
770 for(int i = 0; i < nglyphs; ++i) {
771 if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
772 scale, stretch)) {
773 // Some windows fonts, like "Modern", are vector stroke
774 // fonts, which are reported as TMPF_VECTOR but do not
775 // support GetGlyphOutline, and thus we set this bit so
776 // that addOutLineToPath can check it and return safely...
777 hasOutline = false;
778 break;
779 }
780 }
781 DeleteObject(SelectObject(hdc, oldfont));
782}
783
785 QPainterPath *path, QTextItem::RenderFlags flags)
786{
787 if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
788 hasOutline = true;
790 if (hasOutline) {
791 // has_outline is set to false if addGlyphToPath gets
792 // false from GetGlyphOutline, meaning its not an outline
793 // font.
794 return;
795 }
796 }
798}
799
801{
802 return _faceId;
803}
804
806#include <qdebug.h>
808
810{
811 if (synthesized_flags == -1) {
812 synthesized_flags = 0;
813 if (ttf) {
814 const DWORD HEAD = MAKE_LITTLE_ENDIAN_TAG('h', 'e', 'a', 'd');
815 HDC hdc = m_fontEngineData->hdc;
816 SelectObject(hdc, hfont);
817 uchar data[4];
818 GetFontData(hdc, HEAD, 44, &data, 4);
819 USHORT macStyle = qt_getUShort(data);
820 if (tm.tmItalic && !(macStyle & 2))
821 synthesized_flags = SynthesizedItalic;
822 if (fontDef.stretch != 100 && ttf)
823 synthesized_flags |= SynthesizedStretch;
824 if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1))
825 synthesized_flags |= SynthesizedBold;
826 //qDebug() << "font is" << _name <<
827 // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
828 }
829 }
830 return synthesized_flags;
831}
832
834{
835 return unitsPerEm;
836}
837
839{
840 LOGFONT lf = m_logfont;
841 lf.lfHeight = unitsPerEm;
842 HFONT hf = CreateFontIndirect(&lf);
843 HDC hdc = m_fontEngineData->hdc;
844 HGDIOBJ oldfont = SelectObject(hdc, hf);
845 OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
847 p.emSquare = unitsPerEm;
848 p.italicAngle = otm->otmItalicAngle;
849 const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1()
850 + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1();
852 p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
853 otm->otmrcFontBox.right - otm->otmrcFontBox.left,
854 otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
855 p.ascent = otm->otmAscent;
856 p.descent = -otm->otmDescent;
857 p.leading = int(otm->otmLineGap);
858 p.capHeight = 0;
859 p.lineWidth = otm->otmsUnderscoreSize;
860 free(otm);
861 DeleteObject(SelectObject(hdc, oldfont));
862 return p;
863}
864
866{
867 LOGFONT lf = m_logfont;
868 lf.lfHeight = -unitsPerEm;
869 int flags = synthesized();
871 lf.lfItalic = false;
872 lf.lfWidth = 0;
873 HFONT hf = CreateFontIndirect(&lf);
874 HDC hdc = m_fontEngineData->hdc;
875 HGDIOBJ oldfont = SelectObject(hdc, hf);
877 p.x = 0;
878 p.y = 0;
879 addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
880 DeleteObject(SelectObject(hdc, oldfont));
881}
882
884{
885 if (!ttf && !cffTable)
886 return false;
887 HDC hdc = m_fontEngineData->hdc;
888 SelectObject(hdc, hfont);
889 DWORD t = qbswap<quint32>(tag);
890 *length = GetFontData(hdc, t, 0, buffer, *length);
891 Q_ASSERT(*length == GDI_ERROR || int(*length) > 0);
892 return *length != GDI_ERROR;
893}
894
895#if !defined(CLEARTYPE_QUALITY)
896# define CLEARTYPE_QUALITY 5
897#endif
898
899QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
900 const QTransform &t,
901 QImage::Format mask_format)
902{
903 Q_UNUSED(mask_format);
904 glyph_metrics_t gm = boundingBox(glyph);
905
906// printf(" -> for glyph %4x\n", glyph);
907
908 int gx = gm.x.toInt();
909 int gy = gm.y.toInt();
910 int iw = gm.width.toInt();
911 int ih = gm.height.toInt();
912
913 if (iw <= 0 || ih <= 0)
914 return 0;
915
916 bool has_transformation = t.type() > QTransform::TxTranslate;
917
918 unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
919 XFORM xform;
920
921 if (has_transformation) {
922 xform.eM11 = FLOAT(t.m11());
923 xform.eM12 = FLOAT(t.m12());
924 xform.eM21 = FLOAT(t.m21());
925 xform.eM22 = FLOAT(t.m22());
926 xform.eDx = margin;
927 xform.eDy = margin;
928
929 const HDC hdc = m_fontEngineData->hdc;
930
931 SetGraphicsMode(hdc, GM_ADVANCED);
932 SetWorldTransform(hdc, &xform);
933 HGDIOBJ old_font = SelectObject(hdc, font);
934
935 const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
936 GLYPHMETRICS tgm;
937 MAT2 mat;
938 memset(&mat, 0, sizeof(mat));
939 mat.eM11.value = mat.eM22.value = 1;
940
941 const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat);
942
943 XFORM identity = {1, 0, 0, 1, 0, 0};
944 SetWorldTransform(hdc, &identity);
945 SetGraphicsMode(hdc, GM_COMPATIBLE);
946 SelectObject(hdc, old_font);
947
948 if (result == GDI_ERROR) {
949 const int errorCode = int(GetLastError());
950 qErrnoWarning(errorCode, "QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode);
951 return 0;
952 }
953
954 iw = int(tgm.gmBlackBoxX);
955 ih = int(tgm.gmBlackBoxY);
956
957 xform.eDx -= tgm.gmptGlyphOrigin.x;
958 xform.eDy += tgm.gmptGlyphOrigin.y;
959 }
960
961 // The padding here needs to be kept in sync with the values in alphaMapBoundingBox.
962 QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin,
963 ih + 2 * margin,
965
966 /*If cleartype is enabled we use the standard system format even on Windows CE
967 and not the special textbuffer format we have to use if cleartype is disabled*/
968
969 ni->image().fill(0xffffffff);
970
971 HDC hdc = ni->hdc();
972
973 SelectObject(hdc, GetStockObject(NULL_BRUSH));
974 SelectObject(hdc, GetStockObject(BLACK_PEN));
975 SetTextColor(hdc, RGB(0,0,0));
976 SetBkMode(hdc, TRANSPARENT);
977 SetTextAlign(hdc, TA_BASELINE);
978
979 HGDIOBJ old_font = SelectObject(hdc, font);
980
981 if (has_transformation) {
982 SetGraphicsMode(hdc, GM_ADVANCED);
983 SetWorldTransform(hdc, &xform);
984 ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
985 } else {
986 ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0);
987 }
988
989 SelectObject(hdc, old_font);
990 return ni;
991}
992
994 const QFixedPoint &,
995 const QTransform &matrix,
997{
998 int margin = 0;
1001 glyph_metrics_t gm = boundingBox(glyph, matrix);
1002 gm.width += margin * 2;
1003 gm.height += margin * 2;
1004 return gm;
1005}
1006
1008{
1009 HFONT font = hfont;
1010
1011 bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY);
1012 if (clearTypeTemporarilyDisabled) {
1013 LOGFONT lf = m_logfont;
1014 lf.lfQuality = ANTIALIASED_QUALITY;
1015 font = CreateFontIndirect(&lf);
1016 }
1018 mask_format = QImage::Format_RGB32;
1019
1020 const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
1021 if (mask == 0) {
1022 if (m_fontEngineData->clearTypeEnabled)
1023 DeleteObject(font);
1024 return QImage();
1025 }
1026
1027 QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8);
1028
1029
1030 // Copy data... Cannot use QPainter here as GDI has messed up the
1031 // Alpha channel of the ni.image pixels...
1032 for (int y=0; y<mask->height(); ++y) {
1033 uchar *dest = alphaMap.scanLine(y);
1034 if (mask->image().format() == QImage::Format_RGB16) {
1035 const qint16 *src = reinterpret_cast<const qint16 *>(mask->image().constScanLine(y));
1036 for (int x=0; x<mask->width(); ++x)
1037 dest[x] = 255 - qGray(src[x]);
1038 } else {
1039 const uint *src = reinterpret_cast<const uint *>(mask->image().constScanLine(y));
1040 for (int x=0; x<mask->width(); ++x) {
1042 dest[x] = 255 - qGray(src[x]);
1043 else
1044 dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
1045 }
1046 }
1047 }
1048
1049 // Cleanup...
1050 delete mask;
1051 if (clearTypeTemporarilyDisabled) {
1052 DeleteObject(font);
1053 }
1054
1055 return alphaMap;
1056}
1057
1058#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
1059#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
1060
1062 const QFixedPoint &,
1063 const QTransform &t)
1064{
1065 HFONT font = hfont;
1066
1067 UINT contrast;
1068 SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
1069 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(1000)), 0);
1070
1072 QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
1073 SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(contrast)), 0);
1074
1075 if (mask == 0)
1076 return QImage();
1077
1078 // Gracefully handle the odd case when the display is 16-bit
1079 const QImage source = mask->image().depth() == 32
1080 ? mask->image()
1081 : mask->image().convertToFormat(QImage::Format_RGB32);
1082
1083 QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
1084 for (int y=0; y<mask->height(); ++y) {
1085 auto dest = reinterpret_cast<uint *>(rgbMask.scanLine(y));
1086 const uint *src = reinterpret_cast<const uint *>(source.constScanLine(y));
1087 for (int x=0; x<mask->width(); ++x) {
1088 dest[x] = 0xffffffff - (0x00ffffff & src[x]);
1089 }
1090 }
1091
1092 delete mask;
1093
1094 return rgbMask;
1095}
1096
1098{
1100 QString actualFontName = request.families.constFirst();
1101 if (!uniqueFamilyName.isEmpty())
1102 request.families = QStringList(uniqueFamilyName);
1103 request.pixelSize = pixelSize;
1104 const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName);
1105
1106 QFontEngine *fontEngine =
1109 m_fontEngineData);
1110 if (fontEngine) {
1111 fontEngine->fontDef.families = QStringList(actualFontName);
1112 if (!uniqueFamilyName.isEmpty()) {
1113 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1115 QPlatformFontDatabase *pfdb = pi->fontDatabase();
1116 static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName);
1117 }
1118 }
1119 }
1120 return fontEngine;
1121}
1122
1124{
1125 return hfont;
1126}
1127
1129 int dpi)
1130{
1131 fontDef = request; // most settings are equal
1132 HDC dc = m_fontEngineData->hdc;
1133 SelectObject(dc, hfont);
1134 wchar_t n[64];
1135 GetTextFace(dc, 64, n);
1137 fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
1138 if (fontDef.pointSize < 0) {
1139 fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
1140 } else if (fontDef.pixelSize == -1) {
1141 fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
1142 }
1143}
1144
1146{
1147 // Support all transformations for ttf files, and translations for raster fonts
1148 return ttf || transform.type() <= QTransform::TxTranslate;
1149}
1150
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
void loadKerningPairs(QFixed scalingFactor)
QFixed calculatedCapHeight() const
static const uchar * getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing=nullptr, qreal *rightBearing=nullptr)
static bool isIgnorableChar(char32_t ucs4)
QFontDef fontDef
virtual int glyphMargin(GlyphFormat format)
QByteArray getSfntTable(uint tag) const
virtual void initializeHeightMetrics() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual QFixed lineThickness() const
void addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags)
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
virtual bool hasUnreliableGlyphOutline() const
virtual QFixed xHeight() const
static QPlatformIntegration * platformIntegration()
\inmodule QtGui
Definition qimage.h:37
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_Alpha8
Definition qimage.h:65
@ Format_RGB32
Definition qimage.h:46
@ Format_RGB16
Definition qimage.h:49
int depth() const
\inmodule QtGui
\inmodule QtGui
The QPlatformFontDatabase class makes it possible to customize how fonts are discovered and how they ...
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qrect.h:484
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
Font database for Windows.
static QFontEngine * createEngine(const QFontDef &request, const QString &faceName, int dpi, const QSharedPointer< QWindowsFontEngineData > &data)
Standard Windows font engine.
QFixed averageCharWidth() const override
bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
QFixed xHeight() const override
int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override
void setUniqueFamilyName(const QString &newName)
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
glyph_metrics_t boundingBox(glyph_t g) override
glyph_t glyphIndex(uint ucs4) const override
HGDIOBJ selectDesignFont() const
FaceId faceId() const override
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override
Returns true if the font table idetified by tag exists in the font; returns false otherwise.
void initFontInfo(const QFontDef &request, int dpi)
void initializeHeightMetrics() const override
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) 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
int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const
QWindowsFontEngine(const QString &name, LOGFONT lf, const QSharedPointer< QWindowsFontEngineData > &fontEngineData)
void getGlyphBearings(glyph_t glyph, qreal *leftBearing=nullptr, qreal *rightBearing=nullptr) override
QFixed capHeight() const override
QFixed lineThickness() const override
QImage alphaRGBMapForGlyph(glyph_t t, const QFixedPoint &subPixelPosition, const QTransform &xform) override
bool supportsTransformation(const QTransform &transform) const override
qreal minRightBearing() const override
QImage alphaMapForGlyph(glyph_t t) 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
qreal maxCharWidth() const override
Windows Native image.
static QImage::Format systemFormat()
QString str
[2]
QPixmap p2
QPixmap p1
[0]
QSet< QString >::iterator it
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
void * HANDLE
QList< QString > QStringList
Constructs a string list that contains the given string, str.
AudioChannelLayoutTag tag
static const QCssKnownValue positions[NumKnownPositionModes - 1]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
return ret
#define SIZE(large, small, mini)
int qFloor(T v)
Definition qmath.h:42
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum src
GLenum GLuint buffer
GLint GLsizei width
GLenum type
GLbitfield flags
GLenum GLuint GLintptr offset
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint y
GLsizei GLsizei GLchar * source
GLuint GLenum GLenum transform
GLuint res
GLuint GLenum matrix
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLsizei void * table
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr int qGray(int r, int g, int b)
Definition qrgb.h:36
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1531
#define QT_BEGIN_INCLUDE_NAMESPACE
#define QT_END_INCLUDE_NAMESPACE
unsigned int glyph_t
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
short qint16
Definition qtypes.h:47
unsigned short quint16
Definition qtypes.h:48
size_t quintptr
Definition qtypes.h:167
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
double qreal
Definition qtypes.h:187
unsigned char quint8
Definition qtypes.h:46
quint16 qt_getUShort(const unsigned char *p)
static OUTLINETEXTMETRIC * getOutlineTextMetric(HDC hdc)
static const ushort char_table[]
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)
#define TT_PRIM_CSPLINE
void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
static QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset)
#define SPI_SETFONTSMOOTHINGCONTRAST
#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4)
@ max_font_count
static const int char_table_entries
static double qt_fixed_to_double(const FIXED &p)
static QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch)
#define SPI_GETFONTSMOOTHINGCONTRAST
Q_CHECK_PTR(a=new int[80])
QItemSelection * selection
[0]
QNetworkRequest request(url)
QFixed x
Definition qfixed_p.h:162
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35
constexpr int value() const
Definition qfixed_p.h:38
uint stretch
Definition qfont_p.h:65
uint fixedPitch
Definition qfont_p.h:71
qreal pixelSize
Definition qfont_p.h:61
QStringList families
Definition qfont_p.h:54
qreal pointSize
Definition qfont_p.h:60
The QFont::Tag type provides access to advanced font features.
Definition qfont.h:215
glyph_t * glyphs
QFixed * advances
glyph_metrics_t transformed(const QTransform &xform) const