QtBase  v6.3.1
qfontengine.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <qdebug.h>
41 #include <private/qfontengine_p.h>
42 #include <private/qfontengineglyphcache_p.h>
43 #include <private/qguiapplication_p.h>
44 
45 #include <qpa/qplatformfontdatabase.h>
46 #include <qpa/qplatformintegration.h>
47 
48 #include "qbitmap.h"
49 #include "qpainter.h"
50 #include "qpainterpath.h"
51 #include "qvarlengtharray.h"
52 #include <qmath.h>
53 #include <qendian.h>
54 #include <private/qstringiterator_p.h>
55 
56 #if QT_CONFIG(harfbuzz)
57 # include "qharfbuzzng_p.h"
58 # include <hb-ot.h>
59 #endif
60 
61 #include <algorithm>
62 #include <limits.h>
63 
65 
66 static inline bool qtransform_equals_no_translate(const QTransform &a, const QTransform &b)
67 {
68  if (a.type() <= QTransform::TxTranslate && b.type() <= QTransform::TxTranslate) {
69  return true;
70  } else {
71  // We always use paths for perspective text anyway, so no
72  // point in checking the full matrix...
75 
76  return a.m11() == b.m11()
77  && a.m12() == b.m12()
78  && a.m21() == b.m21()
79  && a.m22() == b.m22();
80  }
81 }
82 
83 template<typename T>
84 static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output)
85 {
86  if (source + sizeof(T) > end)
87  return false;
88 
89  *output = qFromBigEndian<T>(source);
90  return true;
91 }
92 
93 // Harfbuzz helper functions
94 
95 #if QT_CONFIG(harfbuzz)
96 Q_GLOBAL_STATIC_WITH_ARGS(bool, useHarfbuzzNG,(qgetenv("QT_HARFBUZZ") != "old"))
97 
98 bool qt_useHarfbuzzNG()
99 {
100  return *useHarfbuzzNG();
101 }
102 #endif
103 
104 int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
105 {
106  Q_UNUSED(glyph);
107  Q_UNUSED(flags);
108  Q_UNUSED(point);
109  Q_UNUSED(xpos);
110  Q_UNUSED(ypos);
111  Q_UNUSED(nPoints);
112  return Err_Not_Covered;
113 }
114 
115 static bool qt_get_font_table_default(void *user_data, uint tag, uchar *buffer, uint *length)
116 {
118  return fe->getSfntTableData(tag, buffer, length);
119 }
120 
121 
122 #ifdef QT_BUILD_INTERNAL
123 // for testing purpose only, not thread-safe!
124 static QList<QFontEngine *> *enginesCollector = nullptr;
125 
126 Q_AUTOTEST_EXPORT void QFontEngine_startCollectingEngines()
127 {
128  delete enginesCollector;
129  enginesCollector = new QList<QFontEngine *>();
130 }
131 
132 Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
133 {
134  Q_ASSERT(enginesCollector);
135  QList<QFontEngine *> ret = *enginesCollector;
136  delete enginesCollector;
137  enginesCollector = nullptr;
138  return ret;
139 }
140 #endif // QT_BUILD_INTERNAL
141 
142 
143 // QFontEngine
144 
145 #define kBearingNotInitialized std::numeric_limits<qreal>::max()
146 
148  : m_type(type), ref(0),
149  font_(),
150  face_(),
151  m_heightMetricsQueried(false),
152  m_minLeftBearing(kBearingNotInitialized),
153  m_minRightBearing(kBearingNotInitialized)
154 {
155  faceData.user_data = this;
156  faceData.get_font_table = qt_get_font_table_default;
157 
158  cache_cost = 0;
159  fsType = 0;
160  symbol = false;
161  isSmoothlyScalable = false;
162 
165 
166 #ifdef QT_BUILD_INTERNAL
167  if (enginesCollector)
168  enginesCollector->append(this);
169 #endif
170 }
171 
173 {
174 #ifdef QT_BUILD_INTERNAL
175  if (enginesCollector)
176  enginesCollector->removeOne(this);
177 #endif
178 }
179 
181 {
182  // ad hoc algorithm
183  int score = fontDef.weight * fontDef.pixelSize / 10;
184  int lw = score / 700;
185 
186  // looks better with thicker line for small pointsizes
187  if (lw < 2 && score >= 1050) lw = 2;
188  if (lw == 0) lw = 1;
189 
190  return lw;
191 }
192 
194 {
195  return ((lineThickness() * 2) + 3) / 6;
196 }
197 
199 {
201 #if QT_CONFIG(harfbuzz)
202  if (qt_useHarfbuzzNG())
203  return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
204 #endif
205  return nullptr;
206 }
207 
209 {
211 #if QT_CONFIG(harfbuzz)
212  if (qt_useHarfbuzzNG())
213  return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
214 #endif
215  return nullptr;
216 }
217 
219 {
220  if (type() <= QFontEngine::Multi)
221  return true;
222 
223  // ### TODO: This only works for scripts that require OpenType. More generally
224  // for scripts that do not require OpenType we should just look at the list of
225  // supported writing systems in the font's OS/2 table.
227  return true;
228 
229 #if QT_CONFIG(harfbuzz)
230  if (qt_useHarfbuzzNG()) {
231  // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
232  uint lenMort = 0, lenMorx = 0;
233  if (getSfntTableData(MAKE_TAG('m','o','r','t'), nullptr, &lenMort) || getSfntTableData(MAKE_TAG('m','o','r','x'), nullptr, &lenMorx))
234  return true;
235 
236  if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
237  unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
239 
241  &script_count, script_tags,
242  nullptr, nullptr);
243 
244  if (hb_ot_layout_table_select_script(face, HB_OT_TAG_GSUB, script_count, script_tags, nullptr, nullptr))
245  return true;
246  }
247  }
248 #endif
249  return false;
250 }
251 
252 bool QFontEngine::canRender(const QChar *str, int len) const
253 {
255  while (it.hasNext()) {
256  if (glyphIndex(it.next()) == 0)
257  return false;
258  }
259 
260  return true;
261 }
262 
264 {
266 
267  if (matrix.type() > QTransform::TxTranslate) {
268  return metrics.transformed(matrix);
269  }
270  return metrics;
271 }
272 
274 {
275  const glyph_t glyph = glyphIndex('H');
276  glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
277  return bb.height;
278 }
279 
281 {
282  const glyph_t glyph = glyphIndex('x');
283  glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
284  return bb.height;
285 }
286 
288 {
289  const glyph_t glyph = glyphIndex('x');
290  glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
291  return bb.xoff;
292 }
293 
295 {
296  return transform.type() < QTransform::TxProject;
297 }
298 
300 {
301  return true;
302 }
303 
304 void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
306 {
307  QFixed xpos;
308  QFixed ypos;
309 
310  const bool transform = matrix.m11() != 1.
311  || matrix.m12() != 0.
312  || matrix.m21() != 0.
313  || matrix.m22() != 1.;
314  if (!transform) {
315  xpos = QFixed::fromReal(matrix.dx());
316  ypos = QFixed::fromReal(matrix.dy());
317  }
318 
319  int current = 0;
321  int i = glyphs.numGlyphs;
322  int totalKashidas = 0;
323  while(i--) {
324  if (glyphs.attributes[i].dontPrint)
325  continue;
326  xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
327  totalKashidas += glyphs.justifications[i].nKashidas;
328  }
329  positions.resize(glyphs.numGlyphs+totalKashidas);
330  glyphs_out.resize(glyphs.numGlyphs+totalKashidas);
331 
332  i = 0;
333  while(i < glyphs.numGlyphs) {
334  if (glyphs.attributes[i].dontPrint) {
335  ++i;
336  continue;
337  }
338  xpos -= glyphs.advances[i];
339 
340  QFixed gpos_x = xpos + glyphs.offsets[i].x;
341  QFixed gpos_y = ypos + glyphs.offsets[i].y;
342  if (transform) {
343  QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
344  gpos = gpos * matrix;
345  gpos_x = QFixed::fromReal(gpos.x());
346  gpos_y = QFixed::fromReal(gpos.y());
347  }
348  positions[current].x = gpos_x;
349  positions[current].y = gpos_y;
350  glyphs_out[current] = glyphs.glyphs[i];
351  ++current;
352  if (glyphs.justifications[i].nKashidas) {
353  QChar ch = u'\x640'; // Kashida character
354 
355  glyph_t kashidaGlyph = glyphIndex(ch.unicode());
356  QFixed kashidaWidth;
357 
358  QGlyphLayout g;
359  g.numGlyphs = 1;
360  g.glyphs = &kashidaGlyph;
361  g.advances = &kashidaWidth;
362  recalcAdvances(&g, { });
363 
364  for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
365  xpos -= kashidaWidth;
366 
367  QFixed gpos_x = xpos + glyphs.offsets[i].x;
368  QFixed gpos_y = ypos + glyphs.offsets[i].y;
369  if (transform) {
370  QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
371  gpos = gpos * matrix;
372  gpos_x = QFixed::fromReal(gpos.x());
373  gpos_y = QFixed::fromReal(gpos.y());
374  }
375  positions[current].x = gpos_x;
376  positions[current].y = gpos_y;
377  glyphs_out[current] = kashidaGlyph;
378  ++current;
379  }
380  } else {
381  xpos -= QFixed::fromFixed(glyphs.justifications[i].space_18d6);
382  }
383  ++i;
384  }
385  } else {
386  positions.resize(glyphs.numGlyphs);
387  glyphs_out.resize(glyphs.numGlyphs);
388  int i = 0;
389  if (!transform) {
390  while (i < glyphs.numGlyphs) {
391  if (!glyphs.attributes[i].dontPrint) {
392  positions[current].x = xpos + glyphs.offsets[i].x;
393  positions[current].y = ypos + glyphs.offsets[i].y;
394  glyphs_out[current] = glyphs.glyphs[i];
395  xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
396  ++current;
397  }
398  ++i;
399  }
400  } else {
401  while (i < glyphs.numGlyphs) {
402  if (!glyphs.attributes[i].dontPrint) {
403  QFixed gpos_x = xpos + glyphs.offsets[i].x;
404  QFixed gpos_y = ypos + glyphs.offsets[i].y;
405  QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
406  gpos = gpos * matrix;
407  positions[current].x = QFixed::fromReal(gpos.x());
408  positions[current].y = QFixed::fromReal(gpos.y());
409  glyphs_out[current] = glyphs.glyphs[i];
410  xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
411  ++current;
412  }
413  ++i;
414  }
415  }
416  }
417  positions.resize(current);
418  glyphs_out.resize(current);
419  Q_ASSERT(positions.size() == glyphs_out.size());
420 }
421 
422 void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
423 {
424  glyph_metrics_t gi = boundingBox(glyph);
425  if (leftBearing != nullptr)
426  *leftBearing = gi.leftBearing().toReal();
427  if (rightBearing != nullptr)
428  *rightBearing = gi.rightBearing().toReal();
429 }
430 
432 {
433  QByteArray hhea = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
434  if (hhea.size() >= 10) {
435  qint16 ascent = qFromBigEndian<qint16>(hhea.constData() + 4);
436  qint16 descent = qFromBigEndian<qint16>(hhea.constData() + 6);
437  qint16 leading = qFromBigEndian<qint16>(hhea.constData() + 8);
438 
439  // Some fonts may have invalid HHEA data. We detect this and bail out.
440  if (ascent == 0 && descent == 0)
441  return false;
442 
443  QFixed unitsPerEm = emSquareSize();
446 
448 
449  return true;
450  }
451 
452  return false;
453 }
454 
456 {
457  bool hasEmbeddedBitmaps =
458  !getSfntTable(MAKE_TAG('E', 'B', 'L', 'C')).isEmpty()
459  || !getSfntTable(MAKE_TAG('C', 'B', 'L', 'C')).isEmpty()
460  || !getSfntTable(MAKE_TAG('b', 'd', 'a', 't')).isEmpty();
461  if (!hasEmbeddedBitmaps) {
462  // Get HHEA table values if available
464 
465  // Allow OS/2 metrics to override if present
466  processOS2Table();
467  }
468 
469  m_heightMetricsQueried = true;
470 }
471 
473 {
474  QByteArray os2 = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
475  if (os2.size() >= 78) {
476  quint16 fsSelection = qFromBigEndian<quint16>(os2.constData() + 62);
477  qint16 typoAscent = qFromBigEndian<qint16>(os2.constData() + 68);
478  qint16 typoDescent = qFromBigEndian<qint16>(os2.constData() + 70);
479  qint16 typoLineGap = qFromBigEndian<qint16>(os2.constData() + 72);
480  quint16 winAscent = qFromBigEndian<quint16>(os2.constData() + 74);
481  quint16 winDescent = qFromBigEndian<quint16>(os2.constData() + 76);
482 
483  enum { USE_TYPO_METRICS = 0x80 };
484  QFixed unitsPerEm = emSquareSize();
485  if (fsSelection & USE_TYPO_METRICS) {
486  // Some fonts may have invalid OS/2 data. We detect this and bail out.
487  if (typoAscent == 0 && typoDescent == 0)
488  return false;
489  m_ascent = QFixed::fromReal(typoAscent * fontDef.pixelSize) / unitsPerEm;
490  m_descent = -QFixed::fromReal(typoDescent * fontDef.pixelSize) / unitsPerEm;
491  m_leading = QFixed::fromReal(typoLineGap * fontDef.pixelSize) / unitsPerEm;
492  } else {
493  // Some fonts may have invalid OS/2 data. We detect this and bail out.
494  if (winAscent == 0 && winDescent == 0)
495  return false;
496  m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize) / unitsPerEm;
497  m_descent = QFixed::fromReal(winDescent * fontDef.pixelSize) / unitsPerEm;
498  }
499 
500  return true;
501  }
502 
503  return false;
504 }
505 
507 {
510 
511  return m_leading;
512 }
513 
515 {
518 
519  return m_ascent;
520 }
521 
523 {
526 
527  return m_descent;
528 }
529 
531 {
532  if (m_minLeftBearing == kBearingNotInitialized)
533  minRightBearing(); // Initializes both (see below)
534 
535  return m_minLeftBearing;
536 }
537 
538 #define q16Dot16ToFloat(i) ((i) / 65536.0)
539 
540 #define kMinLeftSideBearingOffset 12
541 #define kMinRightSideBearingOffset 14
542 
544 {
545  if (m_minRightBearing == kBearingNotInitialized) {
546 
547  // Try the 'hhea' font table first, which covers the entire font
548  QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
549  if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {
550  const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());
551  Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);
552 
553  qint16 minLeftSideBearing = qFromBigEndian<qint16>(tableData + kMinLeftSideBearingOffset);
554  qint16 minRightSideBearing = qFromBigEndian<qint16>(tableData + kMinRightSideBearingOffset);
555 
556  // The table data is expressed as FUnits, meaning we have to take the number
557  // of units per em into account. Since pixelSize already has taken DPI into
558  // account we can use that directly instead of the point size.
559  int unitsPerEm = emSquareSize().toInt();
560  qreal funitToPixelFactor = fontDef.pixelSize / unitsPerEm;
561 
562  // Some fonts on OS X (such as Gurmukhi Sangam MN, Khmer MN, Lao Sangam MN, etc.), have
563  // invalid values for their NBSPACE left bearing, causing the 'hhea' minimum bearings to
564  // be way off. We detect this by assuming that the minimum bearsings are within a certain
565  // range of the em square size.
566  static const int largestValidBearing = 4 * unitsPerEm;
567 
568  if (qAbs(minLeftSideBearing) < largestValidBearing)
569  m_minLeftBearing = minLeftSideBearing * funitToPixelFactor;
570  if (qAbs(minRightSideBearing) < largestValidBearing)
571  m_minRightBearing = minRightSideBearing * funitToPixelFactor;
572  }
573 
574  // Fallback in case of missing 'hhea' table (bitmap fonts e.g.) or broken 'hhea' values
575  if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized) {
576 
577  // To balance performance and correctness we only look at a subset of the
578  // possible glyphs in the font, based on which characters are more likely
579  // to have a left or right bearing.
580  static const ushort characterSubset[] = {
581  '(', 'C', 'F', 'K', 'V', 'X', 'Y', ']', '_', 'f', 'r', '|',
582  127, 205, 645, 884, 922, 1070, 12386
583  };
584 
585  // The font may have minimum bearings larger than 0, so we have to start at the max
586  m_minLeftBearing = m_minRightBearing = std::numeric_limits<qreal>::max();
587 
588  for (uint i = 0; i < (sizeof(characterSubset) / sizeof(ushort)); ++i) {
589  const glyph_t glyph = glyphIndex(characterSubset[i]);
590  if (!glyph)
591  continue;
592 
593  glyph_metrics_t glyphMetrics = const_cast<QFontEngine *>(this)->boundingBox(glyph);
594 
595  // Glyphs with no contours shouldn't contribute to bearings
596  if (!glyphMetrics.width || !glyphMetrics.height)
597  continue;
598 
599  m_minLeftBearing = qMin(m_minLeftBearing, glyphMetrics.leftBearing().toReal());
600  m_minRightBearing = qMin(m_minRightBearing, glyphMetrics.rightBearing().toReal());
601  }
602  }
603 
604  if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized)
605  qWarning() << "Failed to compute left/right minimum bearings for"
606  << fontDef.families.first();
607  }
608 
609  return m_minRightBearing;
610 }
611 
613 {
614  glyph_metrics_t overall;
615 
616  QFixed ymax = 0;
617  QFixed xmax = 0;
618  for (int i = 0; i < glyphs.numGlyphs; i++) {
619  // If shaping has found this should be ignored, ignore it.
620  if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint)
621  continue;
622  glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);
623  QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;
624  QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;
625  overall.x = qMin(overall.x, x);
626  overall.y = qMin(overall.y, y);
627  xmax = qMax(xmax, x.ceil() + bb.width);
628  ymax = qMax(ymax, y.ceil() + bb.height);
629  overall.xoff += glyphs.effectiveAdvance(i);
630  overall.yoff += bb.yoff;
631  }
632  overall.height = qMax(overall.height, ymax - overall.y);
633  overall.width = xmax - overall.x;
634 
635  return overall;
636 }
637 
638 
640  QTextItem::RenderFlags flags)
641 {
642  if (!glyphs.numGlyphs)
643  return;
644 
646  QVarLengthArray<glyph_t> positioned_glyphs;
648  getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
649  addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);
650 }
651 
652 #define GRID(x, y) grid[(y)*(w+1) + (x)]
653 #define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))
654 
655 enum { EdgeRight = 0x1,
656  EdgeDown = 0x2,
657  EdgeLeft = 0x4,
658  EdgeUp = 0x8
659 };
660 
661 static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path)
662 {
663  Q_UNUSED(h);
664 
665  path->moveTo(x + x0, y + y0);
666  while (GRID(x, y)) {
667  if (GRID(x, y) & EdgeRight) {
668  while (GRID(x, y) & EdgeRight) {
669  GRID(x, y) &= ~EdgeRight;
670  ++x;
671  }
672  Q_ASSERT(x <= w);
673  path->lineTo(x + x0, y + y0);
674  continue;
675  }
676  if (GRID(x, y) & EdgeDown) {
677  while (GRID(x, y) & EdgeDown) {
678  GRID(x, y) &= ~EdgeDown;
679  ++y;
680  }
681  Q_ASSERT(y <= h);
682  path->lineTo(x + x0, y + y0);
683  continue;
684  }
685  if (GRID(x, y) & EdgeLeft) {
686  while (GRID(x, y) & EdgeLeft) {
687  GRID(x, y) &= ~EdgeLeft;
688  --x;
689  }
690  Q_ASSERT(x >= 0);
691  path->lineTo(x + x0, y + y0);
692  continue;
693  }
694  if (GRID(x, y) & EdgeUp) {
695  while (GRID(x, y) & EdgeUp) {
696  GRID(x, y) &= ~EdgeUp;
697  --y;
698  }
699  Q_ASSERT(y >= 0);
700  path->lineTo(x + x0, y + y0);
701  continue;
702  }
703  }
704  path->closeSubpath();
705 }
706 
707 Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
708 {
709  uint *grid = new uint[(w+1)*(h+1)];
710  // set up edges
711  for (int y = 0; y <= h; ++y) {
712  for (int x = 0; x <= w; ++x) {
713  bool topLeft = (x == 0 || y == 0) ? false : SET(x - 1, y - 1);
714  bool topRight = (x == w || y == 0) ? false : SET(x, y - 1);
715  bool bottomLeft = (x == 0 || y == h) ? false : SET(x - 1, y);
716  bool bottomRight = (x == w || y == h) ? false : SET(x, y);
717 
718  GRID(x, y) = 0;
719  if ((!topRight) & bottomRight)
720  GRID(x, y) |= EdgeRight;
721  if ((!bottomRight) & bottomLeft)
722  GRID(x, y) |= EdgeDown;
723  if ((!bottomLeft) & topLeft)
724  GRID(x, y) |= EdgeLeft;
725  if ((!topLeft) & topRight)
726  GRID(x, y) |= EdgeUp;
727  }
728  }
729 
730  // collect edges
731  for (int y = 0; y < h; ++y) {
732  for (int x = 0; x < w; ++x) {
733  if (!GRID(x, y))
734  continue;
735  // found start of a contour, follow it
736  collectSingleContour(x0, y0, grid, x, y, w, h, path);
737  }
738  }
739  delete [] grid;
740 }
741 
742 #undef GRID
743 #undef SET
744 
745 
747  QPainterPath *path, QTextItem::RenderFlags flags)
748 {
749 // TODO what to do with 'flags' ??
750  Q_UNUSED(flags);
751  QFixed advanceX = QFixed::fromReal(x);
752  QFixed advanceY = QFixed::fromReal(y);
753  for (int i=0; i < glyphs.numGlyphs; ++i) {
755  if (metrics.width.value() == 0 || metrics.height.value() == 0) {
756  advanceX += glyphs.advances[i];
757  continue;
758  }
759  const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);
760 
761  const int w = alphaMask.width();
762  const int h = alphaMask.height();
763  const qsizetype srcBpl = alphaMask.bytesPerLine();
764  QImage bitmap;
765  if (alphaMask.depth() == 1) {
766  bitmap = alphaMask;
767  } else {
769  const uchar *imageData = alphaMask.bits();
770  const qsizetype destBpl = bitmap.bytesPerLine();
771  uchar *bitmapData = bitmap.bits();
772 
773  for (int yi = 0; yi < h; ++yi) {
774  const uchar *src = imageData + yi*srcBpl;
775  uchar *dst = bitmapData + yi*destBpl;
776  for (int xi = 0; xi < w; ++xi) {
777  const int byte = xi / 8;
778  const int bit = xi % 8;
779  if (bit == 0)
780  dst[byte] = 0;
781  if (src[xi])
782  dst[byte] |= 128 >> bit;
783  }
784  }
785  }
786  const uchar *bitmap_data = bitmap.constBits();
787  QFixedPoint offset = glyphs.offsets[i];
788  advanceX += offset.x;
789  advanceY += offset.y;
790  qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);
791  advanceX += glyphs.advances[i];
792  }
793 }
794 
795 void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
796  QPainterPath *path, QTextItem::RenderFlags flags)
797 {
798  qreal x = positions[0].x.toReal();
799  qreal y = positions[0].y.toReal();
800  QVarLengthGlyphLayoutArray g(nGlyphs);
801 
802  for (int i = 0; i < nGlyphs - 1; ++i) {
803  g.glyphs[i] = glyphs[i];
804  g.advances[i] = positions[i + 1].x - positions[i].x;
805  }
806  g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1];
807  g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth());
808 
810 }
811 
812 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/)
813 {
814  // For font engines don't support subpixel positioning
815  return alphaMapForGlyph(glyph);
816 }
817 
819 {
820  QImage i = alphaMapForGlyph(glyph);
821  if (t.type() > QTransform::TxTranslate)
822  i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
823  Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
824 
825  return i;
826 }
827 
828 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t)
829 {
831  return alphaMapForGlyph(glyph, t);
832 
833  QImage i = alphaMapForGlyph(glyph, subPixelPosition);
834  if (t.type() > QTransform::TxTranslate)
835  i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
836  Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
837 
838  return i;
839 }
840 
841 QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/, const QTransform &t)
842 {
843  const QImage alphaMask = alphaMapForGlyph(glyph, t);
844  QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
845 
846  for (int y=0; y<alphaMask.height(); ++y) {
847  uint *dst = (uint *) rgbMask.scanLine(y);
848  const uchar *src = alphaMask.constScanLine(y);
849  for (int x=0; x<alphaMask.width(); ++x) {
850  int val = src[x];
851  dst[x] = qRgb(val, val, val);
852  }
853  }
854 
855  return rgbMask;
856 }
857 
858 QImage QFontEngine::bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform&, const QColor &)
859 {
860  Q_UNUSED(subPixelPosition);
861 
862  return QImage();
863 }
864 
866 {
867  if (m_subPixelPositionCount <= 1
870  return QFixedPoint();
871  }
872 
873  auto f = [&](QFixed v) {
874  if (v != 0) {
875  v = v - v.floor() + QFixed::fromFixed(1);
876  QFixed fraction = (v * m_subPixelPositionCount).floor();
877  v = fraction / QFixed(m_subPixelPositionCount);
878  }
879  return v;
880  };
881 
882  return QFixedPoint(f(position.x), f(position.y));
883 }
884 
886  const QFixedPoint &,
888  const QTransform &)
889 {
890  return nullptr;
891 }
892 
894 {
895  glyph_metrics_t gm = boundingBox(glyph);
896  int glyph_x = qFloor(gm.x.toReal());
897  int glyph_y = qFloor(gm.y.toReal());
898  int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x;
899  int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
900 
901  if (glyph_width <= 0 || glyph_height <= 0)
902  return QImage();
903  QFixedPoint pt;
904  pt.x = -glyph_x;
905  pt.y = -glyph_y; // the baseline
907  path.setFillRule(Qt::WindingFill);
908  QImage im(glyph_width, glyph_height, QImage::Format_ARGB32_Premultiplied);
909  im.fill(Qt::transparent);
910  QPainter p(&im);
911  p.setRenderHint(QPainter::Antialiasing);
912  addGlyphsToPath(&glyph, &pt, 1, &path, { });
913  p.setPen(Qt::NoPen);
914  p.setBrush(Qt::black);
915  p.drawPath(path);
916  p.end();
917 
918  QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
919 
920  for (int y=0; y<im.height(); ++y) {
921  uchar *dst = (uchar *) alphaMap.scanLine(y);
922  const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));
923  for (int x=0; x<im.width(); ++x)
924  dst[x] = qAlpha(src[x]);
925  }
926 
927  return alphaMap;
928 }
929 
931 {
932 }
933 
935 {
936  Properties p;
937  p.postscriptName =
940  p.ascent = ascent();
941  p.descent = descent();
942  p.leading = leading();
943  p.emSquare = p.ascent;
944  p.boundingBox = QRectF(0, -p.ascent.toReal(), maxCharWidth(), (p.ascent + p.descent).toReal());
945  p.italicAngle = 0;
946  p.capHeight = p.ascent;
947  p.lineWidth = lineThickness();
948  return p;
949 }
950 
952 {
953  *metrics = boundingBox(glyph);
954  QFixedPoint p;
955  p.x = 0;
956  p.y = 0;
957  addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
958 }
959 
972 {
973  Q_UNUSED(tag);
974  Q_UNUSED(buffer);
975  Q_UNUSED(length);
976  return false;
977 }
978 
980 {
982  uint len = 0;
983  if (!getSfntTableData(tag, nullptr, &len))
984  return table;
985  table.resize(len);
986  if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
987  return QByteArray();
988  return table;
989 }
990 
992 {
993  m_glyphCaches.remove(context);
994 }
995 
997 {
998  Q_ASSERT(cache);
999 
1000  GlyphCaches &caches = m_glyphCaches[context];
1001  for (auto & e : caches) {
1002  if (cache == e.cache.data())
1003  return;
1004  }
1005 
1006  // Limit the glyph caches to 4 per context. This covers all 90 degree rotations,
1007  // and limits memory use when there is continuous or random rotation
1008  if (caches.size() == 4)
1009  caches.pop_back();
1010 
1011  GlyphCacheEntry entry;
1012  entry.cache = cache;
1013  caches.push_front(entry);
1014 
1015 }
1016 
1019  const QTransform &transform,
1020  const QColor &color) const
1021 {
1023  if (caches == m_glyphCaches.cend())
1024  return nullptr;
1025 
1026  for (auto &e : *caches) {
1027  QFontEngineGlyphCache *cache = e.cache.data();
1028  if (format == cache->glyphFormat()
1029  && (format != Format_ARGB || color == cache->color())
1030  && qtransform_equals_no_translate(cache->m_transform, transform)) {
1031  return cache;
1032  }
1033  }
1034 
1035  return nullptr;
1036 }
1037 
1038 static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)
1039 {
1040  uint left_right = (left << 16) + right;
1041 
1042  left = 0, right = numPairs - 1;
1043  while (left <= right) {
1044  int middle = left + ( ( right - left ) >> 1 );
1045 
1046  if (pairs[middle].left_right == left_right)
1047  return pairs[middle].adjust;
1048 
1049  if (pairs[middle].left_right < left_right)
1050  left = middle + 1;
1051  else
1052  right = middle - 1;
1053  }
1054  return 0;
1055 }
1056 
1057 void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1058 {
1059  int numPairs = kerning_pairs.size();
1060  if (!numPairs)
1061  return;
1062 
1063  const KernPair *pairs = kerning_pairs.constData();
1064 
1065  if (flags & DesignMetrics) {
1066  for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1067  glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
1068  } else {
1069  for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1070  glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
1071  }
1072 }
1073 
1075 {
1076  kerning_pairs.clear();
1077 
1078  QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
1079  if (tab.isEmpty())
1080  return;
1081 
1082  const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
1083  const uchar *end = table + tab.size();
1084 
1085  quint16 version;
1086  if (!qSafeFromBigEndian(table, end, &version))
1087  return;
1088 
1089  if (version != 0) {
1090 // qDebug("wrong version");
1091  return;
1092  }
1093 
1094  quint16 numTables;
1095  if (!qSafeFromBigEndian(table + 2, end, &numTables))
1096  return;
1097 
1098  {
1099  int offset = 4;
1100  for(int i = 0; i < numTables; ++i) {
1101  const uchar *header = table + offset;
1102 
1103  quint16 version;
1104  if (!qSafeFromBigEndian(header, end, &version))
1105  goto end;
1106 
1107  quint16 length;
1108  if (!qSafeFromBigEndian(header + 2, end, &length))
1109  goto end;
1110 
1111  quint16 coverage;
1112  if (!qSafeFromBigEndian(header + 4, end, &coverage))
1113  goto end;
1114 
1115 // qDebug("subtable: version=%d, coverage=%x",version, coverage);
1116  if (version == 0 && coverage == 0x0001) {
1117  if (offset + length > tab.size()) {
1118 // qDebug("length ouf ot bounds");
1119  goto end;
1120  }
1121  const uchar *data = table + offset + 6;
1122 
1123  quint16 nPairs;
1124  if (!qSafeFromBigEndian(data, end, &nPairs))
1125  goto end;
1126 
1127  if (nPairs * 6 + 8 > length - 6) {
1128 // qDebug("corrupt table!");
1129  // corrupt table
1130  goto end;
1131  }
1132 
1133  int off = 8;
1134  for(int i = 0; i < nPairs; ++i) {
1136 
1137  quint16 tmp;
1138  if (!qSafeFromBigEndian(data + off, end, &tmp))
1139  goto end;
1140 
1141  p.left_right = uint(tmp) << 16;
1142  if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
1143  goto end;
1144 
1145  p.left_right |= tmp;
1146 
1147  if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
1148  goto end;
1149 
1150  p.adjust = QFixed(int(short(tmp))) / scalingFactor;
1151  kerning_pairs.append(p);
1152  off += 6;
1153  }
1154  }
1155  offset += length;
1156  }
1157  }
1158 end:
1159  std::sort(kerning_pairs.begin(), kerning_pairs.end());
1160 // for (int i = 0; i < kerning_pairs.count(); ++i)
1161 // qDebug() << 'i' << i << "left_right" << Qt::hex << kerning_pairs.at(i).left_right;
1162 }
1163 
1164 
1166 {
1167  QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
1168  if (maxpTable.size() < 6)
1169  return 0;
1170 
1171  const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
1172  const uchar *end = source + maxpTable.size();
1173 
1174  quint16 count = 0;
1175  qSafeFromBigEndian(source, end, &count);
1176  return count;
1177 }
1178 
1180 {
1181  return nullptr;
1182 }
1183 
1184 const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
1185 {
1186  const uchar *header = table;
1187  const uchar *endPtr = table + tableSize;
1188 
1189  // version check
1190  quint16 version;
1191  if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
1192  return nullptr;
1193 
1194  quint16 numTables;
1195  if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
1196  return nullptr;
1197 
1198  const uchar *maps = table + 4;
1199 
1200  enum {
1201  Invalid,
1202  AppleRoman,
1203  Symbol,
1204  Unicode11,
1205  Unicode,
1206  MicrosoftUnicode,
1207  MicrosoftUnicodeExtended
1208  };
1209 
1210  int symbolTable = -1;
1211  int tableToUse = -1;
1212  int score = Invalid;
1213  for (int n = 0; n < numTables; ++n) {
1214  quint16 platformId;
1215  if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
1216  return nullptr;
1217 
1218  quint16 platformSpecificId = 0;
1219  if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
1220  return nullptr;
1221 
1222  switch (platformId) {
1223  case 0: // Unicode
1224  if (score < Unicode &&
1225  (platformSpecificId == 0 ||
1226  platformSpecificId == 2 ||
1227  platformSpecificId == 3)) {
1228  tableToUse = n;
1229  score = Unicode;
1230  } else if (score < Unicode11 && platformSpecificId == 1) {
1231  tableToUse = n;
1232  score = Unicode11;
1233  }
1234  break;
1235  case 1: // Apple
1236  if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman
1237  tableToUse = n;
1238  score = AppleRoman;
1239  }
1240  break;
1241  case 3: // Microsoft
1242  switch (platformSpecificId) {
1243  case 0:
1244  symbolTable = n;
1245  if (score < Symbol) {
1246  tableToUse = n;
1247  score = Symbol;
1248  }
1249  break;
1250  case 1:
1251  if (score < MicrosoftUnicode) {
1252  tableToUse = n;
1253  score = MicrosoftUnicode;
1254  }
1255  break;
1256  case 0xa:
1257  if (score < MicrosoftUnicodeExtended) {
1258  tableToUse = n;
1259  score = MicrosoftUnicodeExtended;
1260  }
1261  break;
1262  default:
1263  break;
1264  }
1265  default:
1266  break;
1267  }
1268  }
1269  if (tableToUse < 0)
1270  return nullptr;
1271 
1272 resolveTable:
1273  *isSymbolFont = (symbolTable > -1);
1274 
1275  quint32 unicode_table = 0;
1276  if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
1277  return nullptr;
1278 
1279  if (!unicode_table)
1280  return nullptr;
1281 
1282  // get the header of the unicode table
1283  header = table + unicode_table;
1284 
1285  quint16 format;
1286  if (!qSafeFromBigEndian(header, endPtr, &format))
1287  return nullptr;
1288 
1289  quint32 length;
1290  if (format < 8) {
1291  quint16 tmp;
1292  if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
1293  return nullptr;
1294  length = tmp;
1295  } else {
1296  if (!qSafeFromBigEndian(header + 4, endPtr, &length))
1297  return nullptr;
1298  }
1299 
1300  if (table + unicode_table + length > endPtr)
1301  return nullptr;
1302  *cmapSize = length;
1303 
1304  // To support symbol fonts that contain a unicode table for the symbol area
1305  // we check the cmap tables and fall back to symbol font unless that would
1306  // involve losing information from the unicode table
1307  if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) {
1308  const uchar *selectedTable = table + unicode_table;
1309 
1310  // Check that none of the latin1 range are in the unicode table
1311  bool unicodeTableHasLatin1 = false;
1312  for (int uc=0x00; uc<0x100; ++uc) {
1313  if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1314  unicodeTableHasLatin1 = true;
1315  break;
1316  }
1317  }
1318 
1319  // Check that at least one symbol char is in the unicode table
1320  bool unicodeTableHasSymbols = false;
1321  if (!unicodeTableHasLatin1) {
1322  for (int uc=0xf000; uc<0xf100; ++uc) {
1323  if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1324  unicodeTableHasSymbols = true;
1325  break;
1326  }
1327  }
1328  }
1329 
1330  // Fall back to symbol table
1331  if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) {
1332  tableToUse = symbolTable;
1333  score = Symbol;
1334  goto resolveTable;
1335  }
1336  }
1337 
1338  return table + unicode_table;
1339 }
1340 
1341 quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
1342 {
1343  const uchar *end = cmap + cmapSize;
1344  quint16 format;
1345  if (!qSafeFromBigEndian(cmap, end, &format))
1346  return 0;
1347 
1348  if (format == 0) {
1349  const uchar *ptr = cmap + 6 + unicode;
1350  if (unicode < 256 && ptr < end)
1351  return quint32(*ptr);
1352  } else if (format == 4) {
1353  /* some fonts come with invalid cmap tables, where the last segment
1354  specified end = start = rangeoffset = 0xffff, delta = 0x0001
1355  Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue
1356  by returning 0 for 0xffff
1357  */
1358  if (unicode >= 0xffff)
1359  return 0;
1360 
1361  quint16 segCountX2;
1362  if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
1363  return 0;
1364 
1365  const unsigned char *ends = cmap + 14;
1366 
1367  int i = 0;
1368  for (; i < segCountX2/2; ++i) {
1369  quint16 codePoint;
1370  if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
1371  return 0;
1372  if (codePoint >= unicode)
1373  break;
1374  }
1375 
1376  const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
1377 
1378  quint16 startIndex;
1379  if (!qSafeFromBigEndian(idx, end, &startIndex))
1380  return 0;
1381  if (startIndex > unicode)
1382  return 0;
1383 
1384  idx += segCountX2;
1385 
1386  quint16 tmp;
1387  if (!qSafeFromBigEndian(idx, end, &tmp))
1388  return 0;
1389  qint16 idDelta = qint16(tmp);
1390 
1391  idx += segCountX2;
1392 
1393  quint16 idRangeoffset_t;
1394  if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
1395  return 0;
1396 
1398  if (idRangeoffset_t) {
1399  quint16 id;
1400  if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
1401  return 0;
1402 
1403  if (id)
1404  glyphIndex = (idDelta + id) % 0x10000;
1405  else
1406  glyphIndex = 0;
1407  } else {
1408  glyphIndex = (idDelta + unicode) % 0x10000;
1409  }
1410  return glyphIndex;
1411  } else if (format == 6) {
1412  quint16 tableSize;
1413  if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
1414  return 0;
1415 
1416  quint16 firstCode6;
1417  if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
1418  return 0;
1419  if (unicode < firstCode6)
1420  return 0;
1421 
1422  quint16 entryCount6;
1423  if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
1424  return 0;
1425  if (entryCount6 * 2 + 10 > tableSize)
1426  return 0;
1427 
1428  quint16 sentinel6 = firstCode6 + entryCount6;
1429  if (unicode >= sentinel6)
1430  return 0;
1431 
1432  quint16 entryIndex6 = unicode - firstCode6;
1433 
1434  quint16 index = 0;
1435  qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
1436  return index;
1437  } else if (format == 12) {
1438  quint32 nGroups;
1439  if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
1440  return 0;
1441 
1442  cmap += 16; // move to start of groups
1443 
1444  int left = 0, right = nGroups - 1;
1445  while (left <= right) {
1446  int middle = left + ( ( right - left ) >> 1 );
1447 
1448  quint32 startCharCode;
1449  if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
1450  return 0;
1451 
1452  if (unicode < startCharCode)
1453  right = middle - 1;
1454  else {
1455  quint32 endCharCode;
1456  if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
1457  return 0;
1458 
1459  if (unicode <= endCharCode) {
1460  quint32 index;
1461  if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
1462  return 0;
1463 
1464  return index + unicode - startCharCode;
1465  }
1466  left = middle + 1;
1467  }
1468  }
1469  } else {
1470  qDebug("cmap table of format %d not implemented", format);
1471  }
1472 
1473  return 0;
1474 }
1475 
1477 {
1478  QByteArray f = family;
1479  f.replace(' ', "");
1480  f.replace('(', "");
1481  f.replace(')', "");
1482  f.replace('<', "");
1483  f.replace('>', "");
1484  f.replace('[', "");
1485  f.replace(']', "");
1486  f.replace('{', "");
1487  f.replace('}', "");
1488  f.replace('/', "");
1489  f.replace('%', "");
1490  return f;
1491 }
1492 
1493 // Allow font engines (e.g. Windows) that can not reliably create
1494 // outline paths for distance-field rendering to switch the scene
1495 // graph over to native text rendering.
1497 {
1498  // Color glyphs (Emoji) are generally not suited for outlining
1500 }
1501 
1503 {
1504  if (glyphs.numGlyphs >= 1) {
1505  glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
1506  glyph_metrics_t gi = boundingBox(glyph);
1507  if (gi.isValid())
1508  return gi.rightBearing();
1509  }
1510  return 0;
1511 }
1512 
1513 
1514 QFontEngine::GlyphCacheEntry::GlyphCacheEntry()
1515 {
1516 }
1517 
1518 QFontEngine::GlyphCacheEntry::GlyphCacheEntry(const GlyphCacheEntry &o)
1519  : cache(o.cache)
1520 {
1521 }
1522 
1523 QFontEngine::GlyphCacheEntry::~GlyphCacheEntry()
1524 {
1525 }
1526 
1527 QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const GlyphCacheEntry &o)
1528 {
1529  cache = o.cache;
1530  return *this;
1531 }
1532 
1533 // ------------------------------------------------------------------
1534 // The box font engine
1535 // ------------------------------------------------------------------
1536 
1538  : QFontEngine(Box),
1539  _size(size)
1540 {
1541  cache_cost = sizeof(QFontEngineBox);
1542 }
1543 
1545  : QFontEngine(type),
1546  _size(size)
1547 {
1548  cache_cost = sizeof(QFontEngineBox);
1549 }
1550 
1552 {
1553 }
1554 
1556 {
1557  Q_UNUSED(ucs4);
1558  return 1;
1559 }
1560 
1561 bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
1562 {
1563  Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
1564  if (*nglyphs < len) {
1565  *nglyphs = len;
1566  return false;
1567  }
1568 
1569  int ucs4Length = 0;
1571  while (it.hasNext()) {
1572  it.advance();
1573  glyphs->glyphs[ucs4Length++] = 1;
1574  }
1575 
1576  *nglyphs = ucs4Length;
1577  glyphs->numGlyphs = ucs4Length;
1578 
1579  if (!(flags & GlyphIndicesOnly))
1580  recalcAdvances(glyphs, flags);
1581 
1582  return true;
1583 }
1584 
1585 void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
1586 {
1587  for (int i = 0; i < glyphs->numGlyphs; i++)
1588  glyphs->advances[i] = _size;
1589 }
1590 
1591 void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1592 {
1593  if (!glyphs.numGlyphs)
1594  return;
1595 
1596  QVarLengthArray<QFixedPoint> positions;
1597  QVarLengthArray<glyph_t> positioned_glyphs;
1599  getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1600 
1601  QSize s(_size - 3, _size - 3);
1602  for (int k = 0; k < positions.size(); k++)
1603  path->addRect(QRectF(positions[k].toPointF(), s));
1604 }
1605 
1607 {
1608  glyph_metrics_t overall;
1609  overall.width = _size*glyphs.numGlyphs;
1610  overall.height = _size;
1611  overall.xoff = overall.width;
1612  return overall;
1613 }
1614 
1616 {
1617  if (!ti.glyphs.numGlyphs)
1618  return;
1619 
1620  // any fixes here should probably also be done in QPaintEnginePrivate::drawBoxTextItem
1621  QSize s(_size - 3, _size - 3);
1622 
1623  QVarLengthArray<QFixedPoint> positions;
1624  QVarLengthArray<glyph_t> glyphs;
1626  ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1627  if (glyphs.size() == 0)
1628  return;
1629 
1630 
1631  QPainter *painter = p->painter();
1632  painter->save();
1634  QPen pen = painter->pen();
1635  pen.setWidthF(lineThickness().toReal());
1636  painter->setPen(pen);
1637  for (int k = 0; k < positions.size(); k++)
1638  painter->drawRect(QRectF(positions[k].toPointF(), s));
1639  painter->restore();
1640 }
1641 
1643 {
1644  return glyph_metrics_t(0, -_size, _size, _size, _size, 0);
1645 }
1646 
1648 {
1649  QFontEngineBox *fe = new QFontEngineBox(pixelSize);
1650  return fe;
1651 }
1652 
1654 {
1655  return _size;
1656 }
1657 
1659 {
1660  return _size;
1661 }
1662 
1664 {
1665  return 0;
1666 }
1667 
1669 {
1670  QFixed l = _size * QFixed::fromReal(qreal(0.15));
1671  return l.ceil();
1672 }
1673 
1675 {
1676  return _size;
1677 }
1678 
1679 bool QFontEngineBox::canRender(const QChar *, int) const
1680 {
1681  return true;
1682 }
1683 
1685 {
1686  QImage image(_size, _size, QImage::Format_Alpha8);
1687  image.fill(0);
1688 
1689  uchar *bits = image.bits();
1690  for (int i=2; i <= _size-3; ++i) {
1691  bits[i + 2 * image.bytesPerLine()] = 255;
1692  bits[i + (_size - 3) * image.bytesPerLine()] = 255;
1693  bits[2 + i * image.bytesPerLine()] = 255;
1694  bits[_size - 3 + i * image.bytesPerLine()] = 255;
1695  }
1696  return image;
1697 }
1698 
1699 // ------------------------------------------------------------------
1700 // Multi engine
1701 // ------------------------------------------------------------------
1702 
1704 { return glyph >> 24; }
1705 
1706 // strip high byte from glyph
1707 static inline glyph_t stripped(glyph_t glyph)
1708 { return glyph & 0x00ffffff; }
1709 
1711  : QFontEngine(Multi),
1712  m_fallbackFamilies(fallbackFamilies),
1713  m_script(script),
1714  m_fallbackFamiliesQueried(!m_fallbackFamilies.isEmpty())
1715 {
1717 
1718  if (m_fallbackFamilies.isEmpty()) {
1719  // defer obtaining the fallback families until loadEngine(1)
1720  m_fallbackFamilies << QString();
1721  }
1722 
1723  m_engines.resize(m_fallbackFamilies.size() + 1);
1724 
1725  engine->ref.ref();
1726  m_engines[0] = engine;
1727 
1728  fontDef = engine->fontDef;
1730 }
1731 
1733 {
1734  for (int i = 0; i < m_engines.size(); ++i) {
1735  QFontEngine *fontEngine = m_engines.at(i);
1736  if (fontEngine && !fontEngine->ref.deref())
1737  delete fontEngine;
1738  }
1739 }
1740 
1742 
1744 {
1746  if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)
1747  styleHint = QFont::TypeWriter;
1748 
1750  QFont::Style(fontDef.style), styleHint,
1751  QChar::Script(m_script)));
1752 }
1753 
1755 {
1756  Q_ASSERT(!m_fallbackFamiliesQueried);
1757 
1758  m_fallbackFamilies = fallbackFamilies;
1759  if (m_fallbackFamilies.isEmpty()) {
1760  // turns out we lied about having any fallback at all
1761  Q_ASSERT(m_engines.size() == 2); // see c-tor for details
1762  QFontEngine *engine = m_engines.at(0);
1763  engine->ref.ref();
1764  m_engines[1] = engine;
1765  m_fallbackFamilies << fontDef.families.first();
1766  } else {
1767  m_engines.resize(m_fallbackFamilies.size() + 1);
1768  }
1769 
1770  m_fallbackFamiliesQueried = true;
1771 }
1772 
1774 {
1775  if (!m_fallbackFamiliesQueried && at > 0)
1777  Q_ASSERT(at < m_engines.size());
1778  if (!m_engines.at(at)) {
1780  if (!engine)
1783  engine->ref.ref();
1784  m_engines[at] = engine;
1785  }
1786 }
1787 
1789 {
1791  request.styleStrategy |= QFont::NoFontMerging;
1792  request.families = QStringList(fallbackFamilyAt(at - 1));
1793 
1794  // At this point, the main script of the text has already been considered
1795  // when fetching the list of fallback families from the database, and the
1796  // info about the actual script of the characters may have been discarded,
1797  // so we do not check for writing system support, but instead just load
1798  // the family indiscriminately.
1800  engine->fontDef.weight = request.weight;
1801  if (request.style > QFont::StyleNormal)
1802  engine->fontDef.style = request.style;
1803  return engine;
1804  }
1805 
1806  return nullptr;
1807 }
1808 
1810 {
1811  glyph_t glyph = engine(0)->glyphIndex(ucs4);
1812  if (glyph == 0
1813  && ucs4 != QChar::LineSeparator
1814  && ucs4 != QChar::LineFeed
1815  && ucs4 != QChar::CarriageReturn
1816  && ucs4 != QChar::ParagraphSeparator) {
1817  if (!m_fallbackFamiliesQueried)
1818  const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1819  for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1820  QFontEngine *engine = m_engines.at(x);
1821  if (!engine) {
1822  if (!shouldLoadFontEngineForCharacter(x, ucs4))
1823  continue;
1824  const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1825  engine = m_engines.at(x);
1826  }
1827  Q_ASSERT(engine != nullptr);
1828  if (engine->type() == Box)
1829  continue;
1830 
1831  glyph = engine->glyphIndex(ucs4);
1832  if (glyph != 0) {
1833  // set the high byte to indicate which engine the glyph came from
1834  glyph |= (x << 24);
1835  break;
1836  }
1837  }
1838  }
1839 
1840  return glyph;
1841 }
1842 
1844  QGlyphLayout *glyphs, int *nglyphs,
1845  QFontEngine::ShaperFlags flags) const
1846 {
1847  if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
1848  return false;
1849 
1850  int glyph_pos = 0;
1852 
1853  int lastFallback = -1;
1854  while (it.hasNext()) {
1855  const char32_t ucs4 = it.peekNext();
1856 
1857  // If we applied a fallback font to previous glyph, and the current is either
1858  // ZWJ or ZWNJ, we should also try applying the same fallback font to that, in order
1859  // to get the correct shaping rules applied.
1860  if (lastFallback >= 0 && (ucs4 == 0x200d || ucs4 == 0x200c)) {
1861  QFontEngine *engine = m_engines.at(lastFallback);
1862  glyph_t glyph = engine->glyphIndex(ucs4);
1863  if (glyph != 0) {
1864  glyphs->glyphs[glyph_pos] = glyph;
1865  if (!(flags & GlyphIndicesOnly)) {
1866  QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1868  }
1869 
1870  // set the high byte to indicate which engine the glyph came from
1871  glyphs->glyphs[glyph_pos] |= (lastFallback << 24);
1872  } else {
1873  lastFallback = -1;
1874  }
1875  } else {
1876  lastFallback = -1;
1877  }
1878 
1879  if (glyphs->glyphs[glyph_pos] == 0
1880  && ucs4 != QChar::LineSeparator
1881  && ucs4 != QChar::LineFeed
1882  && ucs4 != QChar::CarriageReturn
1883  && ucs4 != QChar::ParagraphSeparator) {
1884  if (!m_fallbackFamiliesQueried)
1885  const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1886  for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1887  QFontEngine *engine = m_engines.at(x);
1888  if (!engine) {
1889  if (!shouldLoadFontEngineForCharacter(x, ucs4))
1890  continue;
1891  const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1892  engine = m_engines.at(x);
1893  if (!engine)
1894  continue;
1895  }
1896  Q_ASSERT(engine != nullptr);
1897  if (engine->type() == Box)
1898  continue;
1899 
1900  glyph_t glyph = engine->glyphIndex(ucs4);
1901  if (glyph != 0) {
1902  glyphs->glyphs[glyph_pos] = glyph;
1903  if (!(flags & GlyphIndicesOnly)) {
1904  QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1906  }
1907 
1908  lastFallback = x;
1909 
1910  // set the high byte to indicate which engine the glyph came from
1911  glyphs->glyphs[glyph_pos] |= (x << 24);
1912  break;
1913  }
1914  }
1915  }
1916 
1917  it.advance();
1918  ++glyph_pos;
1919  }
1920 
1921  *nglyphs = glyph_pos;
1922  glyphs->numGlyphs = glyph_pos;
1923 
1924  return true;
1925 }
1926 
1928 {
1929  Q_UNUSED(at);
1930  Q_UNUSED(ucs4);
1931  return true;
1932 }
1933 
1935 {
1936  if (glyphs.numGlyphs <= 0)
1937  return glyph_metrics_t();
1938 
1939  glyph_metrics_t overall;
1940 
1941  int which = highByte(glyphs.glyphs[0]);
1942  int start = 0;
1943  int end, i;
1944  for (end = 0; end < glyphs.numGlyphs; ++end) {
1945  const int e = highByte(glyphs.glyphs[end]);
1946  if (e == which)
1947  continue;
1948 
1949  // set the high byte to zero
1950  for (i = start; i < end; ++i)
1951  glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1952 
1953  // merge the bounding box for this run
1954  const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1955 
1956  overall.x = qMin(overall.x, gm.x);
1957  overall.y = qMin(overall.y, gm.y);
1958  overall.width = overall.xoff + gm.width;
1959  overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1960  qMin(overall.y, gm.y);
1961  overall.xoff += gm.xoff;
1962  overall.yoff += gm.yoff;
1963 
1964  // reset the high byte for all glyphs
1965  const int hi = which << 24;
1966  for (i = start; i < end; ++i)
1967  glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1968 
1969  // change engine
1970  start = end;
1971  which = e;
1972  }
1973 
1974  // set the high byte to zero
1975  for (i = start; i < end; ++i)
1976  glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1977 
1978  // merge the bounding box for this run
1979  const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1980 
1981  overall.x = qMin(overall.x, gm.x);
1982  overall.y = qMin(overall.y, gm.y);
1983  overall.width = overall.xoff + gm.width;
1984  overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1985  qMin(overall.y, gm.y);
1986  overall.xoff += gm.xoff;
1987  overall.yoff += gm.yoff;
1988 
1989  // reset the high byte for all glyphs
1990  const int hi = which << 24;
1991  for (i = start; i < end; ++i)
1992  glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1993 
1994  return overall;
1995 }
1996 
1997 void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
1998 {
1999  int which = highByte(glyph);
2000  ensureEngineAt(which);
2001  engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
2002 }
2003 
2005  QPainterPath *path, QTextItem::RenderFlags flags)
2006 {
2007  if (glyphs.numGlyphs <= 0)
2008  return;
2009 
2010  int which = highByte(glyphs.glyphs[0]);
2011  int start = 0;
2012  int end, i;
2013  if (flags & QTextItem::RightToLeft) {
2014  for (int gl = 0; gl < glyphs.numGlyphs; gl++)
2015  x += glyphs.advances[gl].toReal();
2016  }
2017  for (end = 0; end < glyphs.numGlyphs; ++end) {
2018  const int e = highByte(glyphs.glyphs[end]);
2019  if (e == which)
2020  continue;
2021 
2022  if (flags & QTextItem::RightToLeft) {
2023  for (i = start; i < end; ++i)
2024  x -= glyphs.advances[i].toReal();
2025  }
2026 
2027  // set the high byte to zero
2028  for (i = start; i < end; ++i)
2029  glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2030  engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2031  // reset the high byte for all glyphs and update x and y
2032  const int hi = which << 24;
2033  for (i = start; i < end; ++i)
2034  glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2035 
2037  for (i = start; i < end; ++i)
2038  x += glyphs.advances[i].toReal();
2039  }
2040 
2041  // change engine
2042  start = end;
2043  which = e;
2044  }
2045 
2046  if (flags & QTextItem::RightToLeft) {
2047  for (i = start; i < end; ++i)
2048  x -= glyphs.advances[i].toReal();
2049  }
2050 
2051  // set the high byte to zero
2052  for (i = start; i < end; ++i)
2053  glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2054 
2055  engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2056 
2057  // reset the high byte for all glyphs
2058  const int hi = which << 24;
2059  for (i = start; i < end; ++i)
2060  glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2061 }
2062 
2063 void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2064 {
2065  if (glyphs->numGlyphs <= 0)
2066  return;
2067 
2068  int which = highByte(glyphs->glyphs[0]);
2069  int start = 0;
2070  int end, i;
2071  for (end = 0; end < glyphs->numGlyphs; ++end) {
2072  const int e = highByte(glyphs->glyphs[end]);
2073  if (e == which)
2074  continue;
2075 
2076  // set the high byte to zero
2077  for (i = start; i < end; ++i)
2078  glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2079 
2080  QGlyphLayout offs = glyphs->mid(start, end - start);
2081  engine(which)->recalcAdvances(&offs, flags);
2082 
2083  // reset the high byte for all glyphs and update x and y
2084  const int hi = which << 24;
2085  for (i = start; i < end; ++i)
2086  glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2087 
2088  // change engine
2089  start = end;
2090  which = e;
2091  }
2092 
2093  // set the high byte to zero
2094  for (i = start; i < end; ++i)
2095  glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2096 
2097  QGlyphLayout offs = glyphs->mid(start, end - start);
2098  engine(which)->recalcAdvances(&offs, flags);
2099 
2100  // reset the high byte for all glyphs
2101  const int hi = which << 24;
2102  for (i = start; i < end; ++i)
2103  glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2104 }
2105 
2106 void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2107 {
2108  if (glyphs->numGlyphs <= 0)
2109  return;
2110 
2111  int which = highByte(glyphs->glyphs[0]);
2112  int start = 0;
2113  int end, i;
2114  for (end = 0; end < glyphs->numGlyphs; ++end) {
2115  const int e = highByte(glyphs->glyphs[end]);
2116  if (e == which)
2117  continue;
2118 
2119  // set the high byte to zero
2120  for (i = start; i < end; ++i)
2121  glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2122 
2123  QGlyphLayout offs = glyphs->mid(start, end - start);
2124  engine(which)->doKerning(&offs, flags);
2125 
2126  // reset the high byte for all glyphs and update x and y
2127  const int hi = which << 24;
2128  for (i = start; i < end; ++i)
2129  glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2130 
2131  // change engine
2132  start = end;
2133  which = e;
2134  }
2135 
2136  // set the high byte to zero
2137  for (i = start; i < end; ++i)
2138  glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2139 
2140  QGlyphLayout offs = glyphs->mid(start, end - start);
2141  engine(which)->doKerning(&offs, flags);
2142 
2143  // reset the high byte for all glyphs
2144  const int hi = which << 24;
2145  for (i = start; i < end; ++i)
2146  glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2147 }
2148 
2150 {
2151  const int which = highByte(glyph);
2152  return engine(which)->boundingBox(stripped(glyph));
2153 }
2154 
2156 { return engine(0)->ascent(); }
2157 
2159 { return engine(0)->capHeight(); }
2160 
2162 { return engine(0)->descent(); }
2163 
2165 {
2166  return engine(0)->leading();
2167 }
2168 
2170 {
2171  return engine(0)->xHeight();
2172 }
2173 
2175 {
2176  return engine(0)->averageCharWidth();
2177 }
2178 
2180 {
2181  return engine(0)->lineThickness();
2182 }
2183 
2185 {
2186  return engine(0)->underlinePosition();
2187 }
2188 
2190 {
2191  return engine(0)->maxCharWidth();
2192 }
2193 
2195 {
2196  return engine(0)->minLeftBearing();
2197 }
2198 
2200 {
2201  return engine(0)->minRightBearing();
2202 }
2203 
2204 bool QFontEngineMulti::canRender(const QChar *string, int len) const
2205 {
2206  if (engine(0)->canRender(string, len))
2207  return true;
2208 
2209  int nglyphs = len;
2210 
2211  QVarLengthArray<glyph_t> glyphs(nglyphs);
2212 
2213  QGlyphLayout g;
2214  g.numGlyphs = nglyphs;
2215  g.glyphs = glyphs.data();
2216  if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
2217  Q_UNREACHABLE();
2218 
2219  for (int i = 0; i < nglyphs; i++) {
2220  if (glyphs[i] == 0)
2221  return false;
2222  }
2223 
2224  return true;
2225 }
2226 
2227 /* Implement alphaMapForGlyph() which is called by QPA Windows code.
2228  * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
2229 
2231 {
2232  const int which = highByte(glyph);
2233  return engine(which)->alphaMapForGlyph(stripped(glyph));
2234 }
2235 
2237 {
2238  const int which = highByte(glyph);
2239  return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
2240 }
2241 
2243 {
2244  const int which = highByte(glyph);
2245  return engine(which)->alphaMapForGlyph(stripped(glyph), t);
2246 }
2247 
2249  const QFixedPoint &subPixelPosition,
2250  const QTransform &t)
2251 {
2252  const int which = highByte(glyph);
2253  return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
2254 }
2255 
2257  const QFixedPoint &subPixelPosition,
2258  const QTransform &t)
2259 {
2260  const int which = highByte(glyph);
2261  return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
2262 }
2263 
2264 /*
2265  This is used indirectly by Qt WebKit when using QTextLayout::setRawFont
2266 
2267  The purpose of this is to provide the necessary font fallbacks when drawing complex
2268  text. Since Qt WebKit ends up repeatedly creating QTextLayout instances and passing them
2269  the same raw font over and over again, we want to cache the corresponding multi font engine
2270  as it may contain fallback font engines already.
2271 */
2273 {
2274  QFontEngine *engine = nullptr;
2275  QFontCache::Key key(fe->fontDef, script, /*multi = */true);
2277  // We can't rely on the fontDef (and hence the cache Key)
2278  // alone to distinguish webfonts, since these should not be
2279  // accidentally shared, even if the resulting fontcache key
2280  // is strictly identical. See:
2281  // http://www.w3.org/TR/css3-fonts/#font-face-rule
2282  const bool faceIsLocal = !fe->faceId().filename.isEmpty();
2284  end = fc->engineCache.end();
2285  while (it != end && it.key() == key) {
2286  Q_ASSERT(it.value().data->type() == QFontEngine::Multi);
2287  QFontEngineMulti *cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);
2288  if (fe == cachedEngine->engine(0) || (faceIsLocal && fe->faceId().filename == cachedEngine->engine(0)->faceId().filename)) {
2289  engine = cachedEngine;
2290  fc->updateHitCountAndTimeStamp(it.value());
2291  break;
2292  }
2293  ++it;
2294  }
2295  if (!engine) {
2297  fc->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
2298  }
2299  Q_ASSERT(engine);
2300  return engine;
2301 }
2302 
2304  : QFontEngineBox(TestFontEngine, size)
2305 {}
2306 
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
xD9 x84 xD8 xAD xD9 x80 xF0 x90 xAC x9A xE0 xA7 xA6 xE0 xA7 xAA xF0 x91 x84 xA4 xF0 x91 x84 x89 xF0 x91 x84 x9B xF0 x90 x8A xAB xF0 x90 x8B x89 xE2 xB2 x9E xE2 xB2 x9F xD0 xBE xD0 x9E xF0 x90 x90 x84 xF0 x90 x90 xAC xE1 x83 x98 xE1 x83 x94 xE1 x83 x90 xE1 xB2 xBF xE2 xB0 x95 xE2 xB1 x85 xCE xBF xCE x9F xE0 xA8 xA0 xE0 xA8 xB0 xE0 xA9 xA6 Kayah xEA xA4 x8D xEA xA4 x80 Khmer xE1 xA7 xA1 xE1 xA7 xAA xE0 xBB x90 Latin Subscript xE2 x82 x92 xE2 x82 x80 xEA x93 xB3 xF0 x96 xB9 xA1 xF0 x96 xB9 x9B xF0 x96 xB9 xAF xE1 x80 x9D xE1 x80 x84 xE1 x80 x82 no script
Definition: afscript.h:271
Arabic default style
Definition: afstyles.h:94
FT_UInt idx
Definition: cffcmap.c:135
bool ref() noexcept
Definition: qbasicatomic.h:101
bool deref() noexcept
Definition: qbasicatomic.h:102
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
qsizetype size() const noexcept
Definition: qbytearray.h:470
const char * constData() const noexcept
Definition: qbytearray.h:144
bool isEmpty() const noexcept
Definition: qbytearray.h:129
static QByteArray number(int, int base=10)
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
Definition: qbytearray.h:278
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
@ CarriageReturn
Definition: qchar.h:91
@ ParagraphSeparator
Definition: qchar.h:99
@ LineSeparator
Definition: qchar.h:100
@ LineFeed
Definition: qchar.h:89
Script
Definition: qchar.h:180
@ Script_Common
Definition: qchar.h:183
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
The QFlag class is a helper data type for QFlags.
Definition: qflags.h:53
EngineCache engineCache
Definition: qfont_p.h:280
static QFontCache * instance()
Definition: qfont.cpp:2858
void updateHitCountAndTimeStamp(Engine &value)
Definition: qfont.cpp:3001
void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti=false)
Definition: qfont.cpp:3013
static QFontEngine * findFont(const QFontDef &request, int script, bool preferScriptOverFamily=false)
void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si)
virtual QImage alphaMapForGlyph(glyph_t) override
virtual qreal maxCharWidth() const override
virtual QFontEngine * cloneWithSize(qreal pixelSize) const override
virtual QFixed leading() const override
virtual bool canRender(const QChar *string, int len) const override
virtual glyph_t glyphIndex(uint ucs4) const override
virtual QFixed descent() const override
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override
virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
virtual QFixed ascent() const override
virtual QFixed capHeight() const override
QFontEngineBox(int size)
glyph_metrics_t tightBoundingBox(const QGlyphLayout &glyphs)
virtual bool supportsHorizontalSubPixelPositions() const
virtual QFixed capHeight() const =0
virtual QFixed descent() const
void setGlyphCache(const void *key, QFontEngineGlyphCache *data)
virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
virtual Properties properties() const
void loadKerningPairs(QFixed scalingFactor)
QFixed calculatedCapHeight() const
static const uchar * getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
virtual int glyphCount() const
virtual QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color=QColor())
virtual Qt::HANDLE handle() const
virtual qreal minRightBearing() const
virtual ~QFontEngine()
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
virtual bool expectsGammaCorrectedBlending() const
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)=0
int m_subPixelPositionCount
virtual qreal minLeftBearing() const
bool m_heightMetricsQueried
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
virtual FaceId faceId() const
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing=nullptr, qreal *rightBearing=nullptr)
virtual Glyph * glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t)
QFixed m_ascent
bool supportsScript(QChar::Script script) const
virtual qreal maxCharWidth() const =0
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
QFontDef fontDef
void * harfbuzzFont() const
virtual QFixed ascent() const
bool canRender(uint ucs4) const
virtual QImage alphaMapForGlyph(glyph_t)
struct QFontEngine::FaceData faceData
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t)
QFontEngine(Type type)
QByteArray getSfntTable(uint tag) const
virtual QFixed averageCharWidth() const
virtual void removeGlyphFromCache(glyph_t)
virtual void initializeHeightMetrics() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual bool supportsVerticalSubPixelPositions() const
static bool scriptRequiresOpenType(QChar::Script script)
bool processOS2Table() const
virtual void doKerning(QGlyphLayout *, ShaperFlags) const
Type type() const
bool processHheaTable() const
QFixed m_leading
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
void clearGlyphCache(const void *key)
virtual glyph_t glyphIndex(uint ucs4) const =0
virtual QFixed lineThickness() const
virtual QFixed underlinePosition() const
void addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags)
bool isSmoothlyScalable
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const
virtual bool supportsTransformation(const QTransform &transform) const
QAtomicInt ref
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
GlyphFormat glyphFormat
QFixed lastRightBearing(const QGlyphLayout &glyphs)
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const
QList< KernPair > kerning_pairs
QFontEngineGlyphCache * glyphCache(const void *key, GlyphFormat format, const QTransform &transform, const QColor &color=QColor()) const
virtual QFixed leading() const
void * harfbuzzFace() const
virtual bool hasUnreliableGlyphOutline() const
virtual QFixed xHeight() const
virtual QFixed emSquareSize() const
virtual QFixedPoint subPixelPositionFor(const QFixedPoint &position) const
QFixed m_descent
void ensureEngineAt(int at)
virtual glyph_t glyphIndex(uint ucs4) const override
virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override
virtual QFixed ascent() const override
virtual QFixed capHeight() const override
QString fallbackFamilyAt(int at) const
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override
virtual QFixed descent() const override
virtual QFixed leading() const override
virtual QFixed lineThickness() const override
virtual bool canRender(const QChar *string, int len) const override
virtual qreal maxCharWidth() const override
virtual QFixed xHeight() const override
static QFontEngine * createMultiFontEngine(QFontEngine *fe, int script)
virtual void ensureFallbackFamiliesQueried()
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags) override
QFontEngine * engine(int at) const
virtual qreal minLeftBearing() const override
virtual void doKerning(QGlyphLayout *, ShaperFlags) const override
void setFallbackFamiliesList(const QStringList &fallbackFamilies)
virtual qreal minRightBearing() const override
virtual QFixed underlinePosition() const override
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing=nullptr, qreal *rightBearing=nullptr) override
virtual QImage alphaMapForGlyph(glyph_t) override
QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies=QStringList())
virtual QFontEngine * loadEngine(int at)
virtual QFixed averageCharWidth() const override
static uchar highByte(glyph_t glyph)
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override
StyleHint
Definition: qfont.h:59
@ AnyStyle
Definition: qfont.h:65
@ TypeWriter
Definition: qfont.h:62
@ NoFontMerging
Definition: qfont.h:84
Style
Definition: qfont.h:109
@ StyleNormal
Definition: qfont.h:110
static QPlatformIntegration * platformIntegration()
static QGuiApplicationPrivate * instance()
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qhash.h:773
bool remove(const Key &key)
Definition: qhash.h:911
const_iterator constFind(const Key &key) const noexcept
Definition: qhash.h:1224
const_iterator cend() const noexcept
Definition: qhash.h:1161
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
qsizetype bytesPerLine() const
Definition: qimage.cpp:1536
uchar * scanLine(int)
Definition: qimage.cpp:1613
int width() const
Definition: qimage.cpp:1331
uchar * bits()
Definition: qimage.cpp:1675
int height() const
Definition: qimage.cpp:1343
@ Format_Alpha8
Definition: qimage.h:101
@ Format_RGB32
Definition: qimage.h:82
@ Format_Mono
Definition: qimage.h:79
@ Format_ARGB32_Premultiplied
Definition: qimage.h:84
void fill(uint pixel)
Definition: qimage.cpp:1736
const uchar * constScanLine(int) const
Definition: qimage.cpp:1655
int depth() const
Definition: qimage.cpp:1385
qsizetype size() const noexcept
Definition: qlist.h:414
bool removeOne(const AT &t)
Definition: qlist.h:596
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
void resize(qsizetype size)
Definition: qlist.h:420
void append(parameter_type t)
Definition: qlist.h:469
iterator end()
Definition: qmap.h:1332
iterator find(const Key &key)
Definition: qmap.h:1372
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:87
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:82
const QPen & pen() const
Definition: qpainter.cpp:3736
void drawRect(const QRectF &rect)
Definition: qpainter.h:554
void setPen(const QColor &color)
Definition: qpainter.cpp:3640
void restore()
Definition: qpainter.cpp:1611
void save()
Definition: qpainter.cpp:1577
void setBrush(const QBrush &brush)
Definition: qpainter.cpp:3755
@ Antialiasing
Definition: qpainter.h:88
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:61
void setWidthF(qreal width)
Definition: qpen.cpp:680
virtual QFontEngineMulti * fontEngineMulti(QFontEngine *fontEngine, QChar::Script script)
virtual QPlatformFontDatabase * fontDatabase() const
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr qreal x() const noexcept
Definition: qpoint.h:361
constexpr qreal y() const noexcept
Definition: qpoint.h:366
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:55
The QString class provides a Unicode character string.
Definition: qstring.h:388
The QStringList class provides a list of strings.
QTestFontEngine(int size)
Internal QTextItem.
RenderFlags flags
QGlyphLayout glyphs
QFontEngine * fontEngine
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
static QTransform fromTranslate(qreal dx, qreal dy)
Definition: qtransform.cpp:437
constexpr size_type size() const noexcept
void resize(qsizetype sz)
T * data() noexcept
QString str
[2]
double e
QCache< int, Employee > cache
[0]
int const char * version
Definition: zlib.h:814
HB_EXTERN hb_tag_t const hb_tag_t * script_tags
hb_bool_t hb_ot_layout_table_select_script(hb_face_t *face, hb_tag_t table_tag, unsigned int script_count, const hb_tag_t *script_tags, unsigned int *script_index, hb_tag_t *chosen_script)
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
@ transparent
Definition: qnamespace.h:78
@ black
Definition: qnamespace.h:61
@ NoPen
Definition: qnamespace.h:1112
void * HANDLE
Definition: qnamespace.h:1561
@ NoBrush
Definition: qnamespace.h:1140
@ WindingFill
Definition: qnamespace.h:1322
Definition: image.cpp:51
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
[3]
#define Q_UNREACHABLE()
QList< QString > QStringList
Definition: qcontainerfwd.h:64
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
#define SET(x, y)
QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
#define kBearingNotInitialized
@ EdgeRight
@ EdgeDown
@ EdgeLeft
@ EdgeUp
#define GRID(x, y)
#define kMinLeftSideBearingOffset
#define q16Dot16ToFloat(i)
#define kMinRightSideBearingOffset
#define MAKE_TAG(ch1, ch2, ch3, ch4)
Definition: qfontengine_p.h:68
@ Err_Not_Covered
Definition: qfontengine_p.h:78
unsigned int quint32
Definition: qglobal.h:288
short qint16
Definition: qglobal.h:285
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
#define Q_AUTOTEST_EXPORT
Definition: qglobal.h:579
unsigned short quint16
Definition: qglobal.h:286
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
unsigned short ushort
Definition: qglobal.h:333
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
hb_face_t * hb_qt_face_get_for_engine(QFontEngine *fe)
hb_font_t * hb_qt_font_get_for_engine(QFontEngine *fe)
hb_script_t hb_qt_script_to_script(QChar::Script script)
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
int qFloor(T v)
Definition: qmath.h:78
int qCeil(T v)
Definition: qmath.h:72
@ Invalid
Definition: qmetaobject_p.h:68
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum GLuint id
[6]
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLenum face
GLfloat GLfloat f
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum src
GLenum GLuint buffer
GLuint color
[2]
GLint left
GLenum GLenum dst
GLuint GLfloat x0
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint ref
GLfloat n
GLint GLsizei GLsizei GLenum format
GLuint GLfloat GLfloat y0
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLeglImageOES image
GLuint GLenum GLenum transform
Definition: qopenglext.h:11564
GLuint GLfloat * val
Definition: qopenglext.h:1513
GLuint entry
Definition: qopenglext.h:11002
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition: qopenglext.h:6904
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
Definition: qopenglext.h:5182
GLenum GLsizei len
Definition: qopenglext.h:3292
GLuint GLenum matrix
Definition: qopenglext.h:11564
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
constexpr QRgb qRgb(int r, int g, int b)
Definition: qrgb.h:66
constexpr int qAlpha(QRgb rgb)
Definition: qrgb.h:63
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
unsigned int glyph_t
Q_UNUSED(salary)
[21]
#define HB_LANGUAGE_INVALID
Definition: hb-common.h:324
uint32_t hb_tag_t
Definition: hb-common.h:157
HB_EXTERN hb_font_get_glyph_func_t void * user_data
HB_EXTERN void hb_ot_tags_from_script_and_language(hb_script_t script, hb_language_t language, unsigned int *script_count, hb_tag_t *script_tags, unsigned int *language_count, hb_tag_t *language_tags)
Definition: hb-ot-tag.cc:380
#define HB_OT_MAX_TAGS_PER_SCRIPT
Definition: hb-ot-layout.h:99
#define HB_OT_TAG_GSUB
Definition: hb-ot-layout.h:58
QByteArray imageData
[15]
QPainter painter(this)
[7]
QAction * at
QHttpRequestHeader header("GET", QUrl::toPercentEncoding("/index.html"))
[1]
QNetworkRequest request(url)
QStringList::Iterator it
constexpr static QFixed fromReal(qreal r)
Definition: qfixed_p.h:71
constexpr int toInt() const
Definition: qfixed_p.h:77
constexpr QFixed ceil() const
Definition: qfixed_p.h:83
constexpr qreal toReal() const
Definition: qfixed_p.h:78
constexpr static QFixed fromFixed(int fixed)
Definition: qfixed_p.h:72
QFixed y
Definition: qfixed_p.h:192
QFixed x
Definition: qfixed_p.h:191
uint style
Definition: qfont_p.h:101
uint fixedPitch
Definition: qfont_p.h:106
qreal pixelSize
Definition: qfont_p.h:96
uint weight
Definition: qfont_p.h:105
QStringList families
Definition: qfont_p.h:90
uint styleHint
Definition: qfont_p.h:104
qt_get_font_table_func_t get_font_table
QGlyphJustification * justifications
QFixed effectiveAdvance(int item) const
QGlyphAttributes * attributes
glyph_t * glyphs
QGlyphLayout mid(int position, int n=-1) const
QFixedPoint * offsets
QFixed * advances
Definition: symbols.h:69
Definition: main.cpp:38
Definition: moc.h:48
QFixed rightBearing() const
bool isValid() const
QFixed leftBearing() const
QThreadStorage< QCache< QString, SomeClass > > caches
[7]
Definition: threads.cpp:96
FT_UInt FT_UInt FT_Vector * kerning
Definition: ttdriver.c:206
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154