QtBase  v6.3.1
qfontengine_ft.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 "qdir.h"
41 #include "qmetatype.h"
42 #include "qtextstream.h"
43 #include "qvariant.h"
44 #include "qfontengine_ft_p.h"
45 #include "private/qimage_p.h"
46 #include <private/qstringiterator_p.h>
47 #include <qguiapplication.h>
48 #include <qscreen.h>
49 #include <qpa/qplatformscreen.h>
50 #include <QtCore/QUuid>
51 #include <QtGui/QPainterPath>
52 
53 #ifndef QT_NO_FREETYPE
54 
55 #include "qfile.h"
56 #include "qfileinfo.h"
57 #include <qscopedvaluerollback.h>
58 #include "qthreadstorage.h"
59 #include <qmath.h>
60 #include <qendian.h>
61 
62 #include <memory>
63 
64 #include <ft2build.h>
65 #include FT_FREETYPE_H
66 #include FT_OUTLINE_H
67 #include FT_SYNTHESIS_H
68 #include FT_TRUETYPE_TABLES_H
69 #include FT_TYPE1_TABLES_H
70 #include FT_GLYPH_H
71 #include FT_MODULE_H
72 #include FT_LCD_FILTER_H
73 
74 #if defined(FT_CONFIG_OPTIONS_H)
75 #include FT_CONFIG_OPTIONS_H
76 #endif
77 
78 #if defined(FT_FONT_FORMATS_H)
79 #include FT_FONT_FORMATS_H
80 #endif
81 
82 #ifdef QT_LINUXBASE
83 #include FT_ERRORS_H
84 #endif
85 
86 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
87 # define QT_MAX_CACHED_GLYPH_SIZE 64
88 #endif
89 
91 
92 #define FLOOR(x) ((x) & -64)
93 #define CEIL(x) (((x)+63) & -64)
94 #define TRUNC(x) ((x) >> 6)
95 #define ROUND(x) (((x)+32) & -64)
96 
97 static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
98 {
100 
101  bool result = false;
102  if (FT_IS_SFNT(face)) {
103  FT_ULong len = *length;
105  *length = len;
106  Q_ASSERT(!result || int(*length) > 0);
107  }
108 
109  return result;
110 }
111 
112 static QFontEngineFT::Glyph emptyGlyph;
113 
114 static const QFontEngine::HintStyle ftInitialDefaultHintStyle =
115 #ifdef Q_OS_WIN
117 #else
119 #endif
120 
121 // -------------------------- Freetype support ------------------------------
122 
124 {
125 public:
127  : library(nullptr)
128  { }
129  ~QtFreetypeData();
130 
131  struct FaceStyle {
134 
136  : faceFileName(std::move(faceFileName)),
137  styleName(std::move(styleName))
138  {}
139  };
140 
144 };
145 
147 {
149  iter.value()->cleanup();
150  faces.clear();
152  library = nullptr;
153 }
154 
155 inline bool operator==(const QtFreetypeData::FaceStyle &style1, const QtFreetypeData::FaceStyle &style2)
156 {
157  return style1.faceFileName == style2.faceFileName && style1.styleName == style2.styleName;
158 }
159 
160 inline size_t qHash(const QtFreetypeData::FaceStyle &style, size_t seed)
161 {
162  return qHashMulti(seed, style.faceFileName, style.styleName);
163 }
164 
166 
168 {
169  QtFreetypeData *&freetypeData = theFreetypeData()->localData();
170  if (!freetypeData)
171  freetypeData = new QtFreetypeData;
172  if (!freetypeData->library) {
173  FT_Init_FreeType(&freetypeData->library);
174 #if defined(FT_FONT_FORMATS_H)
175  // Freetype defaults to disabling stem-darkening on CFF, we re-enable it.
176  FT_Bool no_darkening = false;
177  FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening);
178 #endif
179  }
180  return freetypeData;
181 }
182 
184 {
185  QtFreetypeData *freetypeData = qt_getFreetypeData();
186  Q_ASSERT(freetypeData->library);
187  return freetypeData->library;
188 }
189 
191 {
192  int fsType = 0;
194  if (os2)
195  fsType = os2->fsType;
196  return fsType;
197 }
198 
199 int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
200 {
201  if (int error = FT_Load_Glyph(face, glyph, flags))
202  return error;
203 
204  if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
205  return Err_Invalid_SubTable;
206 
207  *nPoints = face->glyph->outline.n_points;
208  if (!(*nPoints))
209  return Err_Ok;
210 
211  if (point > *nPoints)
212  return Err_Invalid_SubTable;
213 
214  *xpos = QFixed::fromFixed(face->glyph->outline.points[point].x);
215  *ypos = QFixed::fromFixed(face->glyph->outline.points[point].y);
216 
217  return Err_Ok;
218 }
219 
221 {
222 #ifdef FT_HAS_COLOR
223  return !FT_IS_SCALABLE(face) && FT_HAS_COLOR(face);
224 #else
225  return false;
226 #endif
227 }
228 
230 
231 /*
232  * One font file can contain more than one font (bold/italic for example)
233  * find the right one and return it.
234  *
235  * Returns the freetype face or 0 in case of an empty file or any other problems
236  * (like not being able to open the file)
237  */
239  const QByteArray &fontData)
240 {
241  if (face_id.filename.isEmpty() && fontData.isEmpty())
242  return nullptr;
243 
244  QtFreetypeData *freetypeData = qt_getFreetypeData();
245 
246  QFreetypeFace *freetype = freetypeData->faces.value(face_id, nullptr);
247  if (freetype) {
248  freetype->ref.ref();
249  } else {
250  const auto deleter = [](QFreetypeFace *f) { delete f; };
251  std::unique_ptr<QFreetypeFace, decltype(deleter)> newFreetype(new QFreetypeFace, deleter);
252  FT_Face face;
253  if (!face_id.filename.isEmpty()) {
255  if (face_id.filename.startsWith(":qmemoryfonts/")) {
256  // from qfontdatabase.cpp
257  QByteArray idx = face_id.filename;
258  idx.remove(0, 14); // remove ':qmemoryfonts/'
259  bool ok = false;
260  newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
261  if (!ok)
262  newFreetype->fontData = QByteArray();
263  } else if (!QFileInfo(fileName).isNativePath()) {
265  if (!file.open(QIODevice::ReadOnly)) {
266  return nullptr;
267  }
268  newFreetype->fontData = file.readAll();
269  }
270  } else {
271  newFreetype->fontData = fontData;
272  }
273  if (!newFreetype->fontData.isEmpty()) {
274  if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
275  return nullptr;
276  }
277  } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
278  return nullptr;
279  }
280  newFreetype->face = face;
281 
282  newFreetype->ref.storeRelaxed(1);
283  newFreetype->xsize = 0;
284  newFreetype->ysize = 0;
285  newFreetype->matrix.xx = 0x10000;
286  newFreetype->matrix.yy = 0x10000;
287  newFreetype->matrix.xy = 0;
288  newFreetype->matrix.yx = 0;
289  newFreetype->unicode_map = nullptr;
290  newFreetype->symbol_map = nullptr;
291 
292  memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
293 
294  for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
295  FT_CharMap cm = newFreetype->face->charmaps[i];
296  switch(cm->encoding) {
297  case FT_ENCODING_UNICODE:
298  newFreetype->unicode_map = cm;
299  break;
300  case FT_ENCODING_APPLE_ROMAN:
301  case FT_ENCODING_ADOBE_LATIN_1:
302  if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
303  newFreetype->unicode_map = cm;
304  break;
305  case FT_ENCODING_ADOBE_CUSTOM:
306  case FT_ENCODING_MS_SYMBOL:
307  if (!newFreetype->symbol_map)
308  newFreetype->symbol_map = cm;
309  break;
310  default:
311  break;
312  }
313  }
314 
315  if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
316  FT_Set_Char_Size(face, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0);
317 
318  FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
319  QT_TRY {
320  freetypeData->faces.insert(face_id, newFreetype.get());
321  } QT_CATCH(...) {
322  newFreetype.release()->release(face_id);
323  // we could return null in principle instead of throwing
324  QT_RETHROW;
325  }
326  freetype = newFreetype.release();
327  }
328  return freetype;
329 }
330 
331 void QFreetypeFace::cleanup()
332 {
333  hbFace.reset();
335  face = nullptr;
336 }
337 
339 {
340  if (!ref.deref()) {
341  if (face) {
342  QtFreetypeData *freetypeData = qt_getFreetypeData();
343 
344  cleanup();
345 
346  auto it = freetypeData->faces.constFind(face_id);
347  if (it != freetypeData->faces.constEnd())
348  freetypeData->faces.erase(it);
349 
350  if (freetypeData->faces.isEmpty()) {
351  FT_Done_FreeType(freetypeData->library);
352  freetypeData->library = nullptr;
353  }
354  }
355 
356  delete this;
357  }
358 }
359 
360 static int computeFaceIndex(const QString &faceFileName, const QString &styleName)
361 {
363 
364  int faceIndex = 0;
365  int numFaces = 0;
366 
367  do {
368  FT_Face face;
369 
371  if (error != FT_Err_Ok) {
372  qDebug() << "FT_New_Face failed for face index" << faceIndex << ':' << Qt::hex << error;
373  break;
374  }
375 
376  QString faceStyleName = QString::fromLatin1(face->style_name);
377  numFaces = face->num_faces;
378 
380 
381  if (faceStyleName == styleName)
382  return faceIndex;
383  } while (++faceIndex < numFaces);
384 
385  // Fall back to the first font face in the file
386  return 0;
387 }
388 
389 int QFreetypeFace::getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName)
390 {
391  QtFreetypeData *freetypeData = qt_getFreetypeData();
392 
393  // Try to get from cache
394  QtFreetypeData::FaceStyle faceStyle(faceFileName, styleName);
395  int faceIndex = freetypeData->faceIndices.value(faceStyle, -1);
396 
397  if (faceIndex >= 0)
398  return faceIndex;
399 
400  faceIndex = computeFaceIndex(faceFileName, styleName);
401 
402  freetypeData->faceIndices.insert(faceStyle, faceIndex);
403 
404  return faceIndex;
405 }
406 
407 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor)
408 {
409  *ysize = qRound(fontDef.pixelSize * 64);
410  *xsize = *ysize * fontDef.stretch / 100;
411  *scalableBitmapScaleFactor = 1;
412  *outline_drawing = false;
413 
414  if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
415  int best = 0;
416  if (!isScalableBitmap()) {
417  /*
418  * Bitmap only faces must match exactly, so find the closest
419  * one (height dominant search)
420  */
421  for (int i = 1; i < face->num_fixed_sizes; i++) {
422  if (qAbs(*ysize - face->available_sizes[i].y_ppem) <
423  qAbs(*ysize - face->available_sizes[best].y_ppem) ||
424  (qAbs(*ysize - face->available_sizes[i].y_ppem) ==
425  qAbs(*ysize - face->available_sizes[best].y_ppem) &&
426  qAbs(*xsize - face->available_sizes[i].x_ppem) <
427  qAbs(*xsize - face->available_sizes[best].x_ppem))) {
428  best = i;
429  }
430  }
431  } else {
432  // Select the shortest bitmap strike whose height is larger than the desired height
433  for (int i = 1; i < face->num_fixed_sizes; i++) {
434  if (face->available_sizes[i].y_ppem < *ysize) {
435  if (face->available_sizes[i].y_ppem > face->available_sizes[best].y_ppem)
436  best = i;
437  } else if (face->available_sizes[best].y_ppem < *ysize) {
438  best = i;
439  } else if (face->available_sizes[i].y_ppem < face->available_sizes[best].y_ppem) {
440  best = i;
441  }
442  }
443  }
444 
445  // According to freetype documentation we must use FT_Select_Size
446  // to make sure we can select the desired bitmap strike index
447  if (FT_Select_Size(face, best) == 0) {
448  if (isScalableBitmap())
449  *scalableBitmapScaleFactor = QFixed::fromReal((qreal)fontDef.pixelSize / face->available_sizes[best].height);
450  *xsize = face->available_sizes[best].x_ppem;
451  *ysize = face->available_sizes[best].y_ppem;
452  } else {
453  *xsize = *ysize = 0;
454  }
455  } else {
456  *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
457  }
458 }
459 
461 {
463  p.postscriptName = FT_Get_Postscript_Name(face);
464  PS_FontInfoRec font_info;
465  if (FT_Get_PS_Font_Info(face, &font_info) == 0)
466  p.copyright = font_info.notice;
467  if (FT_IS_SCALABLE(face)) {
468  p.ascent = face->ascender;
469  p.descent = -face->descender;
470  p.leading = face->height - face->ascender + face->descender;
471  p.emSquare = face->units_per_EM;
472  p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
473  face->bbox.xMax - face->bbox.xMin,
474  face->bbox.yMax - face->bbox.yMin);
475  } else {
476  p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
477  p.descent = QFixed::fromFixed(-face->size->metrics.descender);
478  p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
479  p.emSquare = face->size->metrics.y_ppem;
480 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
481  p.boundingBox = QRectF(0, -p.ascent.toReal(),
482  face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
483  }
484  p.italicAngle = 0;
485  p.capHeight = p.ascent;
486  p.lineWidth = face->underline_thickness;
487 
488  return p;
489 }
490 
492 {
493  return ft_getSfntTable(face, tag, buffer, length);
494 }
495 
496 /* Some fonts (such as MingLiu rely on hinting to scale different
497  components to their correct sizes. While this is really broken (it
498  should be done in the component glyph itself, not the hinter) we
499  will have to live with it.
500 
501  This means we can not use FT_LOAD_NO_HINTING to get the glyph
502  outline. All we can do is to load the unscaled glyph and scale it
503  down manually when required.
504 */
505 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
506 {
507  x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
508  y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
509  FT_Vector *p = g->outline.points;
510  const FT_Vector *e = p + g->outline.n_points;
511  while (p < e) {
512  p->x = FT_MulFix(p->x, x_scale);
513  p->y = FT_MulFix(p->y, y_scale);
514  ++p;
515  }
516 }
517 
518 #define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO // qDebug
520 {
521  const qreal factor = 1/64.;
522  scaleOutline(face, g, x_scale, y_scale);
523 
524  QPointF cp = point.toPointF();
525 
526  // convert the outline to a painter path
527  int i = 0;
528  for (int j = 0; j < g->outline.n_contours; ++j) {
529  int last_point = g->outline.contours[j];
530  GLYPH2PATH_DEBUG() << "contour:" << i << "to" << last_point;
531  QPointF start = QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
532  if (!(g->outline.tags[i] & 1)) { // start point is not on curve:
533  if (!(g->outline.tags[last_point] & 1)) { // end point is not on curve:
534  GLYPH2PATH_DEBUG() << " start and end point are not on curve";
535  start = (QPointF(g->outline.points[last_point].x*factor,
536  -g->outline.points[last_point].y*factor) + start) / 2.0;
537  } else {
538  GLYPH2PATH_DEBUG() << " end point is on curve, start is not";
539  start = QPointF(g->outline.points[last_point].x*factor,
540  -g->outline.points[last_point].y*factor);
541  }
542  --i; // to use original start point as control point below
543  }
544  start += cp;
545  GLYPH2PATH_DEBUG() << " start at" << start;
546 
547  path->moveTo(start);
548  QPointF c[4];
549  c[0] = start;
550  int n = 1;
551  while (i < last_point) {
552  ++i;
553  c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
554  GLYPH2PATH_DEBUG() << " " << i << c[n] << "tag =" << (int)g->outline.tags[i]
555  << ": on curve =" << (bool)(g->outline.tags[i] & 1);
556  ++n;
557  switch (g->outline.tags[i] & 3) {
558  case 2:
559  // cubic bezier element
560  if (n < 4)
561  continue;
562  c[3] = (c[3] + c[2])/2;
563  --i;
564  break;
565  case 0:
566  // quadratic bezier element
567  if (n < 3)
568  continue;
569  c[3] = (c[1] + c[2])/2;
570  c[2] = (2*c[1] + c[3])/3;
571  c[1] = (2*c[1] + c[0])/3;
572  --i;
573  break;
574  case 1:
575  case 3:
576  if (n == 2) {
577  GLYPH2PATH_DEBUG() << " lineTo" << c[1];
578  path->lineTo(c[1]);
579  c[0] = c[1];
580  n = 1;
581  continue;
582  } else if (n == 3) {
583  c[3] = c[2];
584  c[2] = (2*c[1] + c[3])/3;
585  c[1] = (2*c[1] + c[0])/3;
586  }
587  break;
588  }
589  GLYPH2PATH_DEBUG() << " cubicTo" << c[1] << c[2] << c[3];
590  path->cubicTo(c[1], c[2], c[3]);
591  c[0] = c[3];
592  n = 1;
593  }
594 
595  if (n == 1) {
596  GLYPH2PATH_DEBUG() << " closeSubpath";
597  path->closeSubpath();
598  } else {
599  c[3] = start;
600  if (n == 2) {
601  c[2] = (2*c[1] + c[3])/3;
602  c[1] = (2*c[1] + c[0])/3;
603  }
604  GLYPH2PATH_DEBUG() << " close cubicTo" << c[1] << c[2] << c[3];
605  path->cubicTo(c[1], c[2], c[3]);
606  }
607  ++i;
608  }
609 }
610 
611 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
612 
614 {
615  if (slot->format != FT_GLYPH_FORMAT_BITMAP
617  return;
618 
619  QPointF cp = point.toPointF();
620  qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
621  slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
622 }
623 
624 static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
625 {
626  const int offs = bgr ? -1 : 1;
627  const int w = width * 3;
628  while (height--) {
629  uint *dd = dst;
630  for (int x = 0; x < w; x += 3) {
631  uchar red = src[x + 1 - offs];
632  uchar green = src[x + 1];
633  uchar blue = src[x + 1 + offs];
634  *dd++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue;
635  }
636  dst += width;
637  src += src_pitch;
638  }
639 }
640 
641 static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
642 {
643  const int offs = bgr ? -src_pitch : src_pitch;
644  while (height--) {
645  for (int x = 0; x < width; x++) {
646  uchar red = src[x + src_pitch - offs];
647  uchar green = src[x + src_pitch];
648  uchar blue = src[x + src_pitch + offs];
649  *dst++ = (0XFFU << 24) | (red << 16) | (green << 8) | blue;
650  }
651  src += 3*src_pitch;
652  }
653 }
654 
655 static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint()
656 {
657  static int type = -1;
658  if (type == -1) {
661  }
662  return static_cast<QFontEngine::SubpixelAntialiasingType>(type);
663 }
664 
666 {
667  auto engine = std::make_unique<QFontEngineFT>(fontDef);
668 
671 
672  if (antialias) {
673  QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
676  engine->subpixelType = QFontEngine::Subpixel_None;
677  } else {
679  engine->subpixelType = subpixelType;
680  }
681  }
682 
683  if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
684  qWarning("QFontEngineFT: Failed to create FreeType font engine");
685  return nullptr;
686  }
687 
688  engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
689  return engine.release();
690 }
691 
692 namespace {
693  class QFontEngineFTRawData: public QFontEngineFT
694  {
695  public:
696  QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef)
697  {
698  }
699 
700  void updateFamilyNameAndStyle()
701  {
702  fontDef.families = QStringList(QString::fromLatin1(freetype->face->family_name));
703 
704  if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
705  fontDef.style = QFont::StyleItalic;
706 
707  if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
708  fontDef.weight = QFont::Bold;
709  }
710 
711  bool initFromData(const QByteArray &fontData)
712  {
713  FaceId faceId;
714  faceId.filename = "";
715  faceId.index = 0;
716  faceId.uuid = QUuid::createUuid().toByteArray();
717 
718  return init(faceId, true, Format_None, fontData);
719  }
720  };
721 }
722 
724 {
726  fontDef.pixelSize = pixelSize;
728  fontDef.hintingPreference = hintingPreference;
729 
730  QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
731  if (!fe->initFromData(fontData)) {
732  delete fe;
733  return nullptr;
734  }
735 
736  fe->updateFamilyNameAndStyle();
737  fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
738 
739  return fe;
740 }
741 
743  : QFontEngine(Freetype)
744 {
745  fontDef = fd;
746  matrix.xx = 0x10000;
747  matrix.yy = 0x10000;
748  matrix.xy = 0;
749  matrix.yx = 0;
750  cache_cost = 100 * 1024;
751  kerning_pairs_loaded = false;
752  transform = false;
753  embolden = false;
754  obliquen = false;
755  antialias = true;
756  freetype = nullptr;
758  default_hint_style = ftInitialDefaultHintStyle;
761  defaultFormat = Format_None;
762  embeddedbitmap = false;
763  const QByteArray env = qgetenv("QT_NO_FT_CACHE");
764  cacheEnabled = env.isEmpty() || env.toInt() == 0;
766  forceAutoHint = false;
767  stemDarkeningDriver = false;
768 }
769 
771 {
772  if (freetype)
773  freetype->release(face_id);
774 }
775 
776 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
777  const QByteArray &fontData)
778 {
780 }
781 
782 static void dont_delete(void*) {}
783 
784 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
785  QFreetypeFace *freetypeFace)
786 {
787  freetype = freetypeFace;
788  if (!freetype) {
789  xsize = 0;
790  ysize = 0;
791  return false;
792  }
793  defaultFormat = format;
794  this->antialias = antialias;
795 
796  if (!antialias)
798  else
799  glyphFormat = defaultFormat;
800 
801  face_id = faceId;
802 
803  symbol = freetype->symbol_map != nullptr;
804  PS_FontInfoRec psrec;
805  // don't assume that type1 fonts are symbol fonts by default
806  if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
807  symbol = !fontDef.families.isEmpty() && bool(fontDef.families.first().contains(QLatin1String("symbol"), Qt::CaseInsensitive));
808  }
809 
810  freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing, &scalableBitmapScaleFactor);
811 
812  FT_Face face = lockFace();
813 
814  if (FT_IS_SCALABLE(face)) {
815  bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
816  if (fake_oblique)
817  obliquen = true;
818  FT_Set_Transform(face, &matrix, nullptr);
820  // fake bold
821  if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD")) {
822  if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
823  if (os2->usWeightClass < 700 &&
824  (fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) {
825  embolden = true;
826  }
827  }
828  }
829  // underline metrics
830  line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
831  QFixed center_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
832  underline_position = center_position - line_thickness / 2;
833  } else {
834  // ad hoc algorithm
835  int score = fontDef.weight * fontDef.pixelSize;
836  line_thickness = score / 700;
837  // looks better with thicker line for small pointsizes
838  if (line_thickness < 2 && score >= 1050)
839  line_thickness = 2;
840  underline_position = ((line_thickness * 2) + 3) / 6;
841 
842  if (isScalableBitmap()) {
843  glyphFormat = defaultFormat = GlyphFormat::Format_ARGB;
844  cacheEnabled = false;
845  }
846  }
847  if (line_thickness < 1)
848  line_thickness = 1;
849 
850  metrics = face->size->metrics;
851 
852  /*
853  TrueType fonts with embedded bitmaps may have a bitmap font specific
854  ascent/descent in the EBLC table. There is no direct public API
855  to extract those values. The only way we've found is to trick freetype
856  into thinking that it's not a scalable font in FT_Select_Size so that
857  the metrics are retrieved from the bitmap strikes.
858  */
859  if (FT_IS_SCALABLE(face)) {
860  for (int i = 0; i < face->num_fixed_sizes; ++i) {
861  if (xsize == face->available_sizes[i].x_ppem && ysize == face->available_sizes[i].y_ppem) {
862  face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
863 
865  if (face->size->metrics.ascender + face->size->metrics.descender > 0) {
866  FT_Pos leading = metrics.height - metrics.ascender + metrics.descender;
867  metrics.ascender = face->size->metrics.ascender;
868  metrics.descender = face->size->metrics.descender;
869  if (metrics.descender > 0
870  && QString::fromUtf8(face->family_name) == QLatin1String("Courier New")) {
871  metrics.descender *= -1;
872  }
873  metrics.height = metrics.ascender - metrics.descender + leading;
874  }
875  FT_Set_Char_Size(face, xsize, ysize, 0, 0);
876 
877  face->face_flags |= FT_FACE_FLAG_SCALABLE;
878  break;
879  }
880  }
881  }
882 #if defined(FT_FONT_FORMATS_H)
883  const char *fmt = FT_Get_Font_Format(face);
884  if (fmt && qstrncmp(fmt, "CFF", 4) == 0) {
885  FT_Bool no_stem_darkening = true;
886  FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening);
887  if (err == FT_Err_Ok)
888  stemDarkeningDriver = !no_stem_darkening;
889  else
890  stemDarkeningDriver = false;
891  }
892 #endif
893 
894  fontDef.styleName = QString::fromUtf8(face->style_name);
895 
896  if (!freetype->hbFace) {
898  faceData.get_font_table = ft_getSfntTable;
899  (void)harfbuzzFace(); // populates face_
900  freetype->hbFace = std::move(face_);
901  } else {
902  Q_ASSERT(!face_);
903  }
904  // we share the HB face in QFreeTypeFace, so do not let ~QFontEngine() destroy it
905  face_ = Holder(freetype->hbFace.get(), dont_delete);
906 
907  unlockFace();
908 
909  fsType = freetype->fsType();
910  return true;
911 }
912 
914 {
915  switch (hintingPreference) {
918  break;
921  break;
924  break;
926  setDefaultHintStyle(ftInitialDefaultHintStyle);
927  break;
928  }
929 }
930 
932 {
934 }
935 
937 {
938  return stemDarkeningDriver;
939 }
940 
941 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
942  bool &hsubpixel, int &vfactor) const
943 {
944  int load_flags = FT_LOAD_DEFAULT | default_load_flags;
945  int load_target = default_hint_style == HintLight
948 
949  if (format == Format_Mono) {
950  load_target = FT_LOAD_TARGET_MONO;
951  } else if (format == Format_A32) {
953  hsubpixel = true;
955  vfactor = 3;
956  } else if (format == Format_ARGB) {
957 #ifdef FT_LOAD_COLOR
958  load_flags |= FT_LOAD_COLOR;
959 #endif
960  }
961 
962  if (set && set->outline_drawing)
963  load_flags |= FT_LOAD_NO_BITMAP;
964 
965  if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
966  load_flags |= FT_LOAD_NO_HINTING;
967  else
968  load_flags |= load_target;
969 
970  if (forceAutoHint)
971  load_flags |= FT_LOAD_FORCE_AUTOHINT;
972 
973  return load_flags;
974 }
975 
976 static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info)
977 {
978  // false if exceeds QFontEngineFT::Glyph metrics
979  return info.width > 0xFF || info.height > 0xFF || info.linearAdvance > 0x7FFF;
980 }
981 
982 static inline void transformBoundingBox(int *left, int *top, int *right, int *bottom, FT_Matrix *matrix)
983 {
984  int l, r, t, b;
986  vector.x = *left;
987  vector.y = *top;
989  l = r = vector.x;
990  t = b = vector.y;
991  vector.x = *right;
992  vector.y = *top;
994  if (l > vector.x) l = vector.x;
995  if (r < vector.x) r = vector.x;
996  if (t < vector.y) t = vector.y;
997  if (b > vector.y) b = vector.y;
998  vector.x = *right;
999  vector.y = *bottom;
1001  if (l > vector.x) l = vector.x;
1002  if (r < vector.x) r = vector.x;
1003  if (t < vector.y) t = vector.y;
1004  if (b > vector.y) b = vector.y;
1005  vector.x = *left;
1006  vector.y = *bottom;
1008  if (l > vector.x) l = vector.x;
1009  if (r < vector.x) r = vector.x;
1010  if (t < vector.y) t = vector.y;
1011  if (b > vector.y) b = vector.y;
1012  *left = l;
1013  *right = r;
1014  *top = t;
1015  *bottom = b;
1016 }
1017 
1019  const QFixedPoint &subPixelPosition,
1021  bool fetchMetricsOnly,
1022  bool disableOutlineDrawing) const
1023 {
1024 // Q_ASSERT(freetype->lock == 1);
1025 
1026  if (format == Format_None)
1027  format = defaultFormat != Format_None ? defaultFormat : Format_Mono;
1029 
1030  Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : nullptr;
1031  if (g && g->format == format && (fetchMetricsOnly || g->data))
1032  return g;
1033 
1034  if (!g && set && set->isGlyphMissing(glyph))
1035  return &emptyGlyph;
1036 
1037 
1039 
1041 
1042  FT_Vector v;
1043  v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.x.value());
1044  v.y = format == Format_Mono ? 0 : FT_Pos(-subPixelPosition.y.value());
1046 
1047  bool hsubpixel = false;
1048  int vfactor = 1;
1049  int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
1050 
1051  bool transform = matrix.xx != 0x10000
1052  || matrix.yy != 0x10000
1053  || matrix.xy != 0
1054  || matrix.yx != 0;
1055 
1056  if (transform || obliquen || (format != Format_Mono && !isScalableBitmap()))
1057  load_flags |= FT_LOAD_NO_BITMAP;
1058 
1059  FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
1060  if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
1061  load_flags &= ~FT_LOAD_NO_BITMAP;
1062  err = FT_Load_Glyph(face, glyph, load_flags);
1063  }
1064  if (err == FT_Err_Too_Few_Arguments) {
1065  // this is an error in the bytecode interpreter, just try to run without it
1066  load_flags |= FT_LOAD_FORCE_AUTOHINT;
1067  err = FT_Load_Glyph(face, glyph, load_flags);
1068  } else if (err == FT_Err_Execution_Too_Long) {
1069  // This is an error in the bytecode, probably a web font made by someone who
1070  // didn't test bytecode hinting at all so disable for it for all glyphs.
1071  qWarning("load glyph failed due to broken hinting bytecode in font, switching to auto hinting");
1073  load_flags |= FT_LOAD_FORCE_AUTOHINT;
1074  err = FT_Load_Glyph(face, glyph, load_flags);
1075  }
1076  if (err != FT_Err_Ok) {
1077  qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1078  if (set)
1079  set->setGlyphMissing(glyph);
1080  return &emptyGlyph;
1081  }
1082 
1083  FT_GlyphSlot slot = face->glyph;
1084 
1085  if (embolden)
1086  FT_GlyphSlot_Embolden(slot);
1087  if (obliquen) {
1088  FT_GlyphSlot_Oblique(slot);
1089 
1090  // While Embolden alters the metrics of the slot, oblique does not, so we need
1091  // to fix this ourselves.
1092  transform = true;
1093  FT_Matrix m;
1094  m.xx = 0x10000;
1095  m.yx = 0x0;
1096  m.xy = 0x6000;
1097  m.yy = 0x10000;
1098 
1100  }
1101 
1102  GlyphInfo info;
1103  info.linearAdvance = slot->linearHoriAdvance >> 10;
1104  info.xOff = TRUNC(ROUND(slot->advance.x));
1105  info.yOff = 0;
1106 
1107  if ((set && set->outline_drawing && !disableOutlineDrawing) || fetchMetricsOnly) {
1108  int left = slot->metrics.horiBearingX;
1109  int right = slot->metrics.horiBearingX + slot->metrics.width;
1110  int top = slot->metrics.horiBearingY;
1111  int bottom = slot->metrics.horiBearingY - slot->metrics.height;
1112 
1113  if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP)
1114  transformBoundingBox(&left, &top, &right, &bottom, &matrix);
1115 
1116  left = FLOOR(left);
1117  right = CEIL(right);
1118  bottom = FLOOR(bottom);
1119  top = CEIL(top);
1120 
1121  info.x = TRUNC(left);
1122  info.y = TRUNC(top);
1123  info.width = TRUNC(right - left);
1124  info.height = TRUNC(top - bottom);
1125 
1126  // If any of the metrics are too large to fit, don't cache them
1127  // Also, avoid integer overflow when linearAdvance is to large to fit in a signed short
1128  if (areMetricsTooLarge(info))
1129  return nullptr;
1130 
1131  g = new Glyph;
1132  g->data = nullptr;
1133  g->linearAdvance = info.linearAdvance;
1134  g->width = info.width;
1135  g->height = info.height;
1136  g->x = info.x;
1137  g->y = info.y;
1138  g->advance = info.xOff;
1139  g->format = format;
1140 
1141  if (set)
1142  set->setGlyph(glyph, subPixelPosition, g);
1143 
1144  return g;
1145  }
1146 
1147  int glyph_buffer_size = 0;
1148  std::unique_ptr<uchar[]> glyph_buffer;
1150  switch (format) {
1151  case Format_Mono:
1152  renderMode = FT_RENDER_MODE_MONO;
1153  break;
1154  case Format_A32:
1155  if (!hsubpixel && vfactor == 1) {
1156  qWarning("Format_A32 requested, but subpixel layout is unknown.");
1157  return nullptr;
1158  }
1159 
1160  renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
1161  break;
1162  case Format_A8:
1163  case Format_ARGB:
1164  break;
1165  default:
1166  Q_UNREACHABLE();
1167  }
1169 
1170  err = FT_Render_Glyph(slot, renderMode);
1171  if (err != FT_Err_Ok)
1172  qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1173 
1175 
1176  info.height = slot->bitmap.rows;
1177  info.width = slot->bitmap.width;
1178  info.x = slot->bitmap_left;
1179  info.y = slot->bitmap_top;
1180  if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
1181  info.width = info.width / 3;
1182  if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
1183  info.height = info.height / vfactor;
1184 
1185  int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1186  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1187 
1188  glyph_buffer_size = info.height * pitch;
1189  glyph_buffer.reset(new uchar[glyph_buffer_size]);
1190 
1191  if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
1192  uchar *src = slot->bitmap.buffer;
1193  uchar *dst = glyph_buffer.get();
1194  int h = slot->bitmap.rows;
1195  // Some fonts return bitmaps even when we requested something else:
1196  if (format == Format_Mono) {
1197  int bytes = ((info.width + 7) & ~7) >> 3;
1198  while (h--) {
1199  memcpy (dst, src, bytes);
1200  dst += pitch;
1201  src += slot->bitmap.pitch;
1202  }
1203  } else if (format == Format_A8) {
1204  while (h--) {
1205  for (int x = 0; x < int{info.width}; x++)
1206  dst[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1207  dst += pitch;
1208  src += slot->bitmap.pitch;
1209  }
1210  } else {
1211  while (h--) {
1212  uint *dd = reinterpret_cast<uint *>(dst);
1213  for (int x = 0; x < int{info.width}; x++)
1214  dd[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffffff : 0x00000000);
1215  dst += pitch;
1216  src += slot->bitmap.pitch;
1217  }
1218  }
1219  } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) {
1221  uchar *src = slot->bitmap.buffer;
1222  uchar *dst = glyph_buffer.get();
1223  int h = slot->bitmap.rows;
1224  while (h--) {
1225 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
1226  const quint32 *srcPixel = (const quint32 *)src;
1227  quint32 *dstPixel = (quint32 *)dst;
1228  for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) {
1229  const quint32 pixel = *srcPixel;
1230  *dstPixel = qbswap(pixel);
1231  }
1232 #else
1233  memcpy(dst, src, slot->bitmap.width * 4);
1234 #endif
1235  dst += slot->bitmap.pitch;
1236  src += slot->bitmap.pitch;
1237  }
1238  info.linearAdvance = info.xOff = slot->bitmap.width;
1239  } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
1241  uchar *src = slot->bitmap.buffer;
1242  uchar *dst = glyph_buffer.get();
1243  int h = slot->bitmap.rows;
1244  int bytes = info.width;
1245  while (h--) {
1246  memcpy (dst, src, bytes);
1247  dst += pitch;
1248  src += slot->bitmap.pitch;
1249  }
1250  } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
1252  convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.get(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB);
1253  } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
1255  convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.get(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB);
1256  } else {
1257  qWarning("QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode);
1258  return nullptr;
1259  }
1260 
1261  if (!g) {
1262  g = new Glyph;
1263  g->data = nullptr;
1264  }
1265 
1266  g->linearAdvance = info.linearAdvance;
1267  g->width = info.width;
1268  g->height = info.height;
1269  g->x = info.x;
1270  g->y = info.y;
1271  g->advance = info.xOff;
1272  g->format = format;
1273  delete [] g->data;
1274  g->data = glyph_buffer.release();
1275 
1276  if (set)
1277  set->setGlyph(glyph, subPixelPosition, g);
1278 
1279  return g;
1280 }
1281 
1283 {
1284  return face_id;
1285 }
1286 
1288 {
1290  if (p.postscriptName.isEmpty()) {
1292  }
1293 
1294  return freetype->properties();
1295 }
1296 
1298 {
1300  return freetype->face->units_per_EM;
1301  else
1302  return freetype->face->size->metrics.y_ppem;
1303 }
1304 
1306 {
1307  return ft_getSfntTable(freetype->face, tag, buffer, length);
1308 }
1309 
1311 {
1312  int s = 0;
1314  s = SynthesizedItalic;
1316  s |= SynthesizedBold;
1317  if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1318  s |= SynthesizedStretch;
1319  return s;
1320 }
1321 
1323 {
1324  m_ascent = QFixed::fromFixed(metrics.ascender);
1325  m_descent = QFixed::fromFixed(-metrics.descender);
1326  m_leading = QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1327 
1329 
1330  if (scalableBitmapScaleFactor != 1) {
1331  m_ascent *= scalableBitmapScaleFactor;
1332  m_descent *= scalableBitmapScaleFactor;
1333  m_leading *= scalableBitmapScaleFactor;
1334  }
1335 }
1336 
1338 {
1340  if (os2 && os2->version >= 2) {
1341  lockFace();
1343  unlockFace();
1344  return answer;
1345  }
1346  return calculatedCapHeight();
1347 }
1348 
1350 {
1352  if (os2 && os2->sxHeight) {
1353  lockFace();
1354  QFixed answer = QFixed(os2->sxHeight * freetype->face->size->metrics.y_ppem) / emSquareSize();
1355  unlockFace();
1356  return answer;
1357  }
1358 
1359  return QFontEngine::xHeight();
1360 }
1361 
1363 {
1365  if (os2 && os2->xAvgCharWidth) {
1366  lockFace();
1368  unlockFace();
1369  return answer;
1370  }
1371 
1373 }
1374 
1376 {
1377  QFixed max_advance = QFixed::fromFixed(metrics.max_advance);
1378  if (scalableBitmapScaleFactor != 1)
1379  max_advance *= scalableBitmapScaleFactor;
1380  return max_advance.toReal();
1381 }
1382 
1384 {
1385  return line_thickness;
1386 }
1387 
1389 {
1390  return underline_position;
1391 }
1392 
1393 void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
1394 {
1395  if (!kerning_pairs_loaded) {
1396  kerning_pairs_loaded = true;
1397  lockFace();
1398  if (freetype->face->size->metrics.x_ppem != 0) {
1399  QFixed scalingFactor = emSquareSize() / QFixed(freetype->face->size->metrics.x_ppem);
1400  unlockFace();
1401  const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1402  } else {
1403  unlockFace();
1404  }
1405  }
1406 
1407  if (shouldUseDesignMetrics(flags))
1408  flags |= DesignMetrics;
1409  else
1410  flags &= ~DesignMetrics;
1411 
1413 }
1414 
1415 static inline FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1416 {
1417  FT_Matrix m;
1418 
1419  m.xx = FT_Fixed(matrix.m11() * 65536);
1420  m.xy = FT_Fixed(-matrix.m21() * 65536);
1421  m.yx = FT_Fixed(-matrix.m12() * 65536);
1422  m.yy = FT_Fixed(matrix.m22() * 65536);
1423 
1424  return m;
1425 }
1426 
1427 QFontEngineFT::QGlyphSet *QFontEngineFT::TransformedGlyphSets::findSet(const QTransform &matrix, const QFontDef &fontDef)
1428 {
1429  FT_Matrix m = QTransformToFTMatrix(matrix);
1430 
1431  int i = 0;
1432  for (; i < nSets; ++i) {
1433  QGlyphSet *g = sets[i];
1434  if (!g)
1435  break;
1436  if (g->transformationMatrix.xx == m.xx
1437  && g->transformationMatrix.xy == m.xy
1438  && g->transformationMatrix.yx == m.yx
1439  && g->transformationMatrix.yy == m.yy) {
1440 
1441  // found a match, move it to the front
1442  moveToFront(i);
1443  return g;
1444  }
1445  }
1446 
1447  // don't cache more than nSets transformations
1448  if (i == nSets)
1449  // reuse the last set
1450  --i;
1451  moveToFront(nSets - 1);
1452  if (!sets[0])
1453  sets[0] = new QGlyphSet;
1454  QGlyphSet *gs = sets[0];
1455  gs->clear();
1456  gs->transformationMatrix = m;
1457  gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
1458  Q_ASSERT(gs != nullptr);
1459 
1460  return gs;
1461 }
1462 
1463 void QFontEngineFT::TransformedGlyphSets::moveToFront(int i)
1464 {
1465  QGlyphSet *g = sets[i];
1466  while (i > 0) {
1467  sets[i] = sets[i - 1];
1468  --i;
1469  }
1470  sets[0] = g;
1471 }
1472 
1473 
1475 {
1476  if (matrix.type() > QTransform::TxShear || !cacheEnabled)
1477  return nullptr;
1478 
1479  // FT_Set_Transform only supports scalable fonts
1480  if (!FT_IS_SCALABLE(freetype->face))
1481  return matrix.type() <= QTransform::TxTranslate ? &defaultGlyphSet : nullptr;
1482 
1483  return transformedGlyphSets.findSet(matrix, fontDef);
1484 }
1485 
1487 {
1489  FT_Set_Transform(face, nullptr, nullptr);
1491 
1492  int left = face->glyph->metrics.horiBearingX;
1493  int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1494  int top = face->glyph->metrics.horiBearingY;
1495  int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1496 
1497  QFixedPoint p;
1498  p.x = 0;
1499  p.y = 0;
1500 
1501  metrics->width = QFixed::fromFixed(right-left);
1502  metrics->height = QFixed::fromFixed(top-bottom);
1504  metrics->y = QFixed::fromFixed(-top);
1505  metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1506 
1507  if (!FT_IS_SCALABLE(freetype->face))
1509  else
1510  QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1511 
1512  FT_Set_Transform(face, &freetype->matrix, nullptr);
1513  unlockFace();
1514 }
1515 
1517 {
1518  return transform.type() <= QTransform::TxRotate;
1519 }
1520 
1521 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1522 {
1523  if (!glyphs.numGlyphs)
1524  return;
1525 
1526  if (FT_IS_SCALABLE(freetype->face)) {
1528  } else {
1529  QVarLengthArray<QFixedPoint> positions;
1530  QVarLengthArray<glyph_t> positioned_glyphs;
1532  matrix.translate(x, y);
1533  getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1534 
1536  for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1537  FT_UInt glyph = positioned_glyphs[gl];
1539  QFreetypeFace::addBitmapToPath(face->glyph, positions[gl], path);
1540  }
1541  unlockFace();
1542  }
1543 }
1544 
1546  QPainterPath *path, QTextItem::RenderFlags)
1547 {
1549 
1550  for (int gl = 0; gl < numGlyphs; gl++) {
1551  FT_UInt glyph = glyphs[gl];
1552 
1554 
1555  FT_GlyphSlot g = face->glyph;
1556  if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1557  continue;
1558  if (embolden)
1560  if (obliquen)
1562  QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1563  }
1564  unlockFace();
1565 }
1566 
1568 {
1569  glyph_t glyph = ucs4 < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[ucs4] : 0;
1570  if (glyph == 0) {
1572  glyph = FT_Get_Char_Index(face, ucs4);
1573  if (glyph == 0) {
1574  // Certain fonts don't have no-break space and tab,
1575  // while we usually want to render them as space
1576  if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) {
1578  } else if (freetype->symbol_map) {
1579  // Symbol fonts can have more than one CMAPs, FreeType should take the
1580  // correct one for us by default, so we always try FT_Get_Char_Index
1581  // first. If it didn't work (returns 0), we will explicitly set the
1582  // CMAP to symbol font one and try again. symbol_map is not always the
1583  // correct one because in certain fonts like Wingdings symbol_map only
1584  // contains PUA codepoints instead of the common ones.
1586  glyph = FT_Get_Char_Index(face, ucs4);
1588  if (!glyph && symbol && ucs4 < 0x100)
1589  glyph = FT_Get_Char_Index(face, ucs4 + 0xf000);
1590  }
1591  }
1592  if (ucs4 < QFreetypeFace::cmapCacheSize)
1593  freetype->cmapCache[ucs4] = glyph;
1594  }
1595 
1596  return glyph;
1597 }
1598 
1599 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1600  QFontEngine::ShaperFlags flags) const
1601 {
1602  Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
1603  if (*nglyphs < len) {
1604  *nglyphs = len;
1605  return false;
1606  }
1607 
1608  int glyph_pos = 0;
1609  if (freetype->symbol_map) {
1612  while (it.hasNext()) {
1613  uint uc = it.next();
1614  glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1615  if ( !glyphs->glyphs[glyph_pos] ) {
1616  // Symbol fonts can have more than one CMAPs, FreeType should take the
1617  // correct one for us by default, so we always try FT_Get_Char_Index
1618  // first. If it didn't work (returns 0), we will explicitly set the
1619  // CMAP to symbol font one and try again. symbol_map is not always the
1620  // correct one because in certain fonts like Wingdings symbol_map only
1621  // contains PUA codepoints instead of the common ones.
1622  glyph_t glyph = FT_Get_Char_Index(face, uc);
1623  // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1624  // while we usually want to render them as space
1625  if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1626  uc = 0x20;
1627  glyph = FT_Get_Char_Index(face, uc);
1628  }
1629  if (!glyph) {
1631  glyph = FT_Get_Char_Index(face, uc);
1633  if (!glyph && symbol && uc < 0x100)
1634  glyph = FT_Get_Char_Index(face, uc + 0xf000);
1635  }
1636  glyphs->glyphs[glyph_pos] = glyph;
1638  freetype->cmapCache[uc] = glyph;
1639  }
1640  ++glyph_pos;
1641  }
1642  } else {
1645  while (it.hasNext()) {
1646  uint uc = it.next();
1647  glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1648  if (!glyphs->glyphs[glyph_pos]) {
1649  {
1650  redo:
1651  glyph_t glyph = FT_Get_Char_Index(face, uc);
1652  if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1653  uc = 0x20;
1654  goto redo;
1655  }
1656  glyphs->glyphs[glyph_pos] = glyph;
1658  freetype->cmapCache[uc] = glyph;
1659  }
1660  }
1661  ++glyph_pos;
1662  }
1663  }
1664 
1665  *nglyphs = glyph_pos;
1666  glyphs->numGlyphs = glyph_pos;
1667 
1668  if (!(flags & GlyphIndicesOnly))
1669  recalcAdvances(glyphs, flags);
1670 
1671  return true;
1672 }
1673 
1674 bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const
1675 {
1676  if (!FT_IS_SCALABLE(freetype->face))
1677  return false;
1678 
1680 }
1681 
1682 QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const
1683 {
1684  return m * scalableBitmapScaleFactor;
1685 }
1686 
1687 glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const
1688 {
1689  QTransform trans;
1690  trans.setMatrix(t.m11(), t.m12(), t.m13(),
1691  t.m21(), t.m22(), t.m23(),
1692  0, 0, t.m33());
1693  const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
1694  trans.scale(scaleFactor, scaleFactor);
1695 
1696  QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal());
1697  QPointF offset(m.xoff.toReal(), m.yoff.toReal());
1698 
1699  rect = trans.mapRect(rect);
1700  offset = trans.map(offset);
1701 
1703  metrics.x = QFixed::fromReal(rect.x());
1704  metrics.y = QFixed::fromReal(rect.y());
1705  metrics.width = QFixed::fromReal(rect.width());
1706  metrics.height = QFixed::fromReal(rect.height());
1707  metrics.xoff = QFixed::fromReal(offset.x());
1708  metrics.yoff = QFixed::fromReal(offset.y());
1709  return metrics;
1710 }
1711 
1712 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1713 {
1714  FT_Face face = nullptr;
1715  bool design = shouldUseDesignMetrics(flags);
1716  for (int i = 0; i < glyphs->numGlyphs; i++) {
1717  Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : nullptr;
1718  // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1719  GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1720  if (g && g->format == acceptableFormat) {
1721  glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1722  } else {
1723  if (!face)
1724  face = lockFace();
1725  g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
1726  glyphs->glyphs[i],
1727  QFixedPoint(),
1728  Format_None,
1729  true);
1730  if (g)
1731  glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1732  else
1733  glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1734  : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1735  if (!cacheEnabled && g != &emptyGlyph)
1736  delete g;
1737  }
1738 
1739  if (scalableBitmapScaleFactor != 1)
1740  glyphs->advances[i] *= scalableBitmapScaleFactor;
1741  }
1742  if (face)
1743  unlockFace();
1744 }
1745 
1747 {
1748  FT_Face face = nullptr;
1749 
1750  glyph_metrics_t overall;
1751  // initialize with line height, we get the same behaviour on all platforms
1752  if (!isScalableBitmap()) {
1753  overall.y = -ascent();
1754  overall.height = ascent() + descent();
1755  } else {
1756  overall.y = QFixed::fromFixed(-metrics.ascender);
1757  overall.height = QFixed::fromFixed(metrics.ascender - metrics.descender);
1758  }
1759 
1760  QFixed ymax = 0;
1761  QFixed xmax = 0;
1762  for (int i = 0; i < glyphs.numGlyphs; i++) {
1763  // If shaping has found this should be ignored, ignore it.
1764  if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint)
1765  continue;
1766  Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : nullptr;
1767  if (!g) {
1768  if (!face)
1769  face = lockFace();
1770  g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
1771  glyphs.glyphs[i],
1772  QFixedPoint(),
1773  Format_None,
1774  true);
1775  }
1776  if (g) {
1777  QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1778  QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1779  overall.x = qMin(overall.x, x);
1780  overall.y = qMin(overall.y, y);
1781  xmax = qMax(xmax, x.ceil() + g->width);
1782  ymax = qMax(ymax, y.ceil() + g->height);
1783  if (!cacheEnabled && g != &emptyGlyph)
1784  delete g;
1785  } else {
1786  int left = FLOOR(face->glyph->metrics.horiBearingX);
1787  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1788  int top = CEIL(face->glyph->metrics.horiBearingY);
1789  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1790 
1791  QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1792  QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1793  overall.x = qMin(overall.x, x);
1794  overall.y = qMin(overall.y, y);
1795  xmax = qMax(xmax, x + TRUNC(right - left));
1796  ymax = qMax(ymax, y + TRUNC(top - bottom));
1797  }
1798  overall.xoff += glyphs.effectiveAdvance(i);
1799  }
1800  overall.height = qMax(overall.height, ymax - overall.y);
1801  overall.width = xmax - overall.x;
1802 
1803  if (face)
1804  unlockFace();
1805 
1806  if (isScalableBitmap())
1807  overall = scaledBitmapMetrics(overall, QTransform());
1808  return overall;
1809 }
1810 
1812 {
1813  FT_Face face = nullptr;
1814  glyph_metrics_t overall;
1815  Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : nullptr;
1816  if (!g) {
1817  face = lockFace();
1818  g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
1819  glyph,
1820  QFixedPoint(),
1821  Format_None,
1822  true);
1823  }
1824  if (g) {
1825  overall.x = g->x;
1826  overall.y = -g->y;
1827  overall.width = g->width;
1828  overall.height = g->height;
1829  overall.xoff = g->advance;
1830  if (!cacheEnabled && g != &emptyGlyph)
1831  delete g;
1832  } else {
1833  int left = FLOOR(face->glyph->metrics.horiBearingX);
1834  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1835  int top = CEIL(face->glyph->metrics.horiBearingY);
1836  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1837 
1838  overall.width = TRUNC(right-left);
1839  overall.height = TRUNC(top-bottom);
1840  overall.x = TRUNC(left);
1841  overall.y = -TRUNC(top);
1842  overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1843  }
1844  if (face)
1845  unlockFace();
1846 
1847  if (isScalableBitmap())
1848  overall = scaledBitmapMetrics(overall, QTransform());
1849  return overall;
1850 }
1851 
1853 {
1855 }
1856 
1858  const QFixedPoint &subPixelPosition,
1859  const QTransform &matrix,
1861 {
1862  // When rendering glyphs into a cache via the alphaMap* functions, we disable
1863  // outline drawing. To ensure the bounding box matches the rendered glyph, we
1864  // need to do the same here.
1865  Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true, true);
1866 
1867  glyph_metrics_t overall;
1868  if (g) {
1869  overall.x = g->x;
1870  overall.y = -g->y;
1871  overall.width = g->width;
1872  overall.height = g->height;
1873  overall.xoff = g->advance;
1874  if (!cacheEnabled && g != &emptyGlyph)
1875  delete g;
1876  } else {
1877  FT_Face face = lockFace();
1878  int left = FLOOR(face->glyph->metrics.horiBearingX);
1879  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1880  int top = CEIL(face->glyph->metrics.horiBearingY);
1881  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1882 
1883  overall.width = TRUNC(right-left);
1884  overall.height = TRUNC(top-bottom);
1885  overall.x = TRUNC(left);
1886  overall.y = -TRUNC(top);
1887  overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1888  unlockFace();
1889  }
1890 
1891  if (isScalableBitmap())
1892  overall = scaledBitmapMetrics(overall, matrix);
1893  return overall;
1894 }
1895 
1896 static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat)
1897 {
1898  if (glyph == nullptr || glyph->height == 0 || glyph->width == 0)
1899  return QImage();
1900 
1902  int bytesPerLine = -1;
1903  switch (glyphFormat) {
1906  bytesPerLine = ((glyph->width + 31) & ~31) >> 3;
1907  break;
1910  bytesPerLine = (glyph->width + 3) & ~3;
1911  break;
1914  bytesPerLine = glyph->width * 4;
1915  break;
1916  default:
1917  Q_UNREACHABLE();
1918  };
1919 
1920  QImage img(static_cast<const uchar *>(glyph->data), glyph->width, glyph->height, bytesPerLine, format);
1921  if (format == QImage::Format_Mono)
1922  img.setColor(1, QColor(Qt::white).rgba()); // Expands color table to 2 items; item 0 set to transparent.
1923  return img;
1924 }
1925 
1927  const QFixedPoint &subPixelPosition,
1928  QFontEngine::GlyphFormat neededFormat,
1929  const QTransform &t)
1930 {
1932 
1933  if (isBitmapFont())
1934  neededFormat = Format_Mono;
1935  else if (neededFormat == Format_None && defaultFormat != Format_None)
1936  neededFormat = defaultFormat;
1937  else if (neededFormat == Format_None)
1938  neededFormat = Format_A8;
1939 
1940  Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);
1941  if (!glyph || !glyph->width || !glyph->height)
1942  return nullptr;
1943 
1944  return glyph;
1945 }
1946 
1947 static inline bool is2dRotation(const QTransform &t)
1948 {
1949  return qFuzzyCompare(t.m11(), t.m22()) && qFuzzyCompare(t.m12(), -t.m21())
1950  && qFuzzyCompare(t.m11()*t.m22() - t.m12()*t.m21(), qreal(1.0));
1951 }
1952 
1954  const QFixedPoint &subPixelPosition,
1956  const QTransform &t,
1957  bool fetchBoundingBox,
1958  bool disableOutlineDrawing)
1959 {
1960  QGlyphSet *glyphSet = loadGlyphSet(t);
1961  if (glyphSet != nullptr && glyphSet->outline_drawing && !disableOutlineDrawing && !fetchBoundingBox)
1962  return nullptr;
1963 
1964  Glyph *glyph = glyphSet != nullptr ? glyphSet->getGlyph(g, subPixelPosition) : nullptr;
1965  if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) {
1966  QScopedValueRollback<HintStyle> saved_default_hint_style(default_hint_style);
1967  if (t.type() >= QTransform::TxScale && !is2dRotation(t))
1968  default_hint_style = HintNone; // disable hinting if the glyphs are transformed
1969 
1970  lockFace();
1971  FT_Matrix m = this->matrix;
1972  FT_Matrix ftMatrix = glyphSet != nullptr ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
1973  FT_Matrix_Multiply(&ftMatrix, &m);
1974  freetype->matrix = m;
1975  glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false, disableOutlineDrawing);
1976  unlockFace();
1977  }
1978 
1979  return glyph;
1980 }
1981 
1983 {
1984  return alphaMapForGlyph(g, subPixelPosition, QTransform());
1985 }
1986 
1988  const QFixedPoint &subPixelPosition,
1989  const QTransform &t)
1990 {
1991  const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono;
1992 
1993  Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
1994 
1995  QImage img = alphaMapFromGlyphData(glyph, neededFormat);
1996  img = img.copy();
1997 
1998  if (!cacheEnabled && glyph != &emptyGlyph)
1999  delete glyph;
2000 
2001  return img;
2002 }
2003 
2005  const QFixedPoint &subPixelPosition,
2006  const QTransform &t)
2007 {
2008  if (t.type() > QTransform::TxRotate)
2009  return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
2010 
2011  const GlyphFormat neededFormat = Format_A32;
2012 
2013  Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
2014 
2015  QImage img = alphaMapFromGlyphData(glyph, neededFormat);
2016  img = img.copy();
2017 
2018  if (!cacheEnabled && glyph != &emptyGlyph)
2019  delete glyph;
2020 
2021  if (!img.isNull())
2022  return img;
2023 
2024  return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
2025 }
2026 
2028  const QFixedPoint &subPixelPosition,
2029  const QTransform &t,
2030  const QColor &color)
2031 {
2032  Q_UNUSED(color);
2033 
2034  Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t);
2035  if (glyph == nullptr)
2036  return QImage();
2037 
2038  QImage img;
2039  if (defaultFormat == GlyphFormat::Format_ARGB)
2040  img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_ARGB32_Premultiplied).copy();
2041  else if (defaultFormat == GlyphFormat::Format_Mono)
2042  img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy();
2043 
2044  if (!img.isNull() && (!t.isIdentity() || scalableBitmapScaleFactor != 1)) {
2045  QTransform trans(t);
2046  const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
2047  trans.scale(scaleFactor, scaleFactor);
2048  img = img.transformed(trans, Qt::SmoothTransformation);
2049  }
2050 
2051  if (!cacheEnabled && glyph != &emptyGlyph)
2052  delete glyph;
2053 
2054  return img;
2055 }
2056 
2058 {
2059  defaultGlyphSet.removeGlyphFromCache(glyph, QFixedPoint());
2060 }
2061 
2063 {
2064  int count = 0;
2065  FT_Face face = lockFace();
2066  if (face) {
2067  count = face->num_glyphs;
2068  unlockFace();
2069  }
2070  return count;
2071 }
2072 
2074 {
2075  freetype->lock();
2077  if (scale == Unscaled) {
2078  if (FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0) == 0) {
2079  freetype->xsize = face->units_per_EM << 6;
2080  freetype->ysize = face->units_per_EM << 6;
2081  }
2082  } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
2083  FT_Set_Char_Size(face, xsize, ysize, 0, 0);
2084  freetype->xsize = xsize;
2085  freetype->ysize = ysize;
2086  }
2087  if (freetype->matrix.xx != matrix.xx ||
2088  freetype->matrix.yy != matrix.yy ||
2089  freetype->matrix.xy != matrix.xy ||
2090  freetype->matrix.yx != matrix.yx) {
2091  freetype->matrix = matrix;
2092  FT_Set_Transform(face, &freetype->matrix, nullptr);
2093  }
2094 
2095  return face;
2096 }
2097 
2099 {
2100  freetype->unlock();
2101 }
2102 
2104 {
2105  return freetype->face;
2106 }
2107 
2108 
2110  : outline_drawing(false)
2111 {
2112  transformationMatrix.xx = 0x10000;
2113  transformationMatrix.yy = 0x10000;
2116  memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2117  fast_glyph_count = 0;
2118 }
2119 
2121 {
2122  clear();
2123 }
2124 
2126 {
2127  if (fast_glyph_count > 0) {
2128  for (int i = 0; i < 256; ++i) {
2129  if (fast_glyph_data[i]) {
2130  delete fast_glyph_data[i];
2131  fast_glyph_data[i] = nullptr;
2132  }
2133  }
2134  fast_glyph_count = 0;
2135  }
2136  qDeleteAll(glyph_data);
2137  glyph_data.clear();
2138 }
2139 
2141  const QFixedPoint &subPixelPosition)
2142 {
2143  if (useFastGlyphData(index, subPixelPosition)) {
2144  if (fast_glyph_data[index]) {
2145  delete fast_glyph_data[index];
2146  fast_glyph_data[index] = nullptr;
2147  if (fast_glyph_count > 0)
2148  --fast_glyph_count;
2149  }
2150  } else {
2151  delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2152  }
2153 }
2154 
2156  const QFixedPoint &subPixelPosition,
2157  Glyph *glyph)
2158 {
2159  if (useFastGlyphData(index, subPixelPosition)) {
2160  if (!fast_glyph_data[index])
2161  ++fast_glyph_count;
2162  fast_glyph_data[index] = glyph;
2163  } else {
2164  glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2165  }
2166 }
2167 
2168 int QFontEngineFT::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
2169 {
2170  lockFace();
2171  bool hsubpixel = true;
2172  int vfactor = 1;
2173  int load_flags = loadFlags(nullptr, Format_A8, flags, hsubpixel, vfactor);
2174  int result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2175  unlockFace();
2176  return result;
2177 }
2178 
2180 {
2181  if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2182  return false;
2183 
2184  // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2185  // will be using it
2186  freetype->ref.ref();
2187 
2190  antialias = fe->antialias;
2191  transform = fe->transform;
2192  embolden = fe->embolden;
2193  obliquen = fe->obliquen;
2194  subpixelType = fe->subpixelType;
2197 
2198  return true;
2199 }
2200 
2202 {
2203  QFontDef fontDef(this->fontDef);
2204  fontDef.pixelSize = pixelSize;
2205  QFontEngineFT *fe = new QFontEngineFT(fontDef);
2206  if (!fe->initFromFontEngine(this)) {
2207  delete fe;
2208  return nullptr;
2209  } else {
2210  return fe;
2211  }
2212 }
2213 
2215 {
2216  return non_locked_face();
2217 }
2218 
2220 
2221 #endif // QT_NO_FREETYPE
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
FT_UInt idx
Definition: cffcmap.c:135
FT_Error error
Definition: cffdrivr.c:657
FT_Library library
Definition: cffdrivr.c:660
bool ref() noexcept
Definition: qbasicatomic.h:101
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
const char * constData() const noexcept
Definition: qbytearray.h:144
int toInt(bool *ok=nullptr, int base=10) const
bool startsWith(QByteArrayView bv) const
Definition: qbytearray.h:192
bool isEmpty() const noexcept
Definition: qbytearray.h:129
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
@ Nbsp
Definition: qchar.h:93
@ Tabulation
Definition: qchar.h:88
@ Space
Definition: qchar.h:92
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool open(OpenMode flags) override
Definition: qfile.cpp:897
static QString decodeName(const QByteArray &localFileName)
Definition: qfile.h:163
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
template< typename Enum > size_t qHash(QFlags< Enum > flags, size_t seed=0) noexcept
template< typename Enum > bool operator==(Enum lhs, QFlags< Enum > rhs)
void reset() noexcept
void * get() const noexcept
bool expectsGammaCorrectedBlending() const override
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
Glyph * loadGlyph(uint glyph, const QFixedPoint &subPixelPosition, GlyphFormat format=Format_None, bool fetchMetricsOnly=false, bool disableOutlineDrawing=false) const
void setDefaultHintStyle(HintStyle style) override
HintStyle default_hint_style
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format) override
int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) override
bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override
void initializeHeightMetrics() const override
QGlyphSet * loadGlyphSet(const QTransform &matrix)
QFixed underlinePosition() const override
QFixed lineThickness() const override
QFixed emSquareSize() const override
bool initFromFontEngine(const QFontEngineFT *fontEngine)
QFreetypeFace * freetype
QFontEngine * cloneWithSize(qreal pixelSize) const override
void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override
QImage alphaMapForGlyph(glyph_t g) override
QFontEngineFT(const QFontDef &fd)
bool isScalableBitmap() const
QFixed xHeight() const override
FT_Face non_locked_face() const
bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat=Format_None, const QByteArray &fontData=QByteArray())
void removeGlyphFromCache(glyph_t glyph) override
qreal maxCharWidth() const override
void doKerning(QGlyphLayout *, ShaperFlags) const override
void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference)
Qt::HANDLE handle() const override
QFontEngine::Properties properties() const override
QFontEngine::FaceId faceId() const override
Glyph * loadGlyphFor(glyph_t g, const QFixedPoint &subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox=false, bool disableOutlineDrawing=false)
int glyphCount() const override
static QFontEngineFT * create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData=QByteArray())
bool isBitmapFont() const
Glyph * glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t) override
glyph_t glyphIndex(uint ucs4) const override
void unlockFace() const
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
int synthesized() const override
QFixed capHeight() const override
QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override
QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color) override
virtual ~QFontEngineFT()
SubpixelAntialiasingType subpixelType
QFixed averageCharWidth() const override
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override
bool supportsTransformation(const QTransform &transform) const override
FT_Face lockFace(Scaling scale=Scaled) const
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override
virtual QFixed descent() const
void loadKerningPairs(QFixed scalingFactor)
QFixed calculatedCapHeight() const
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
int m_subPixelPositionCount
QFixed m_ascent
QFontDef fontDef
virtual QFixed ascent() const
struct QFontEngine::FaceData faceData
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t)
virtual QFixed averageCharWidth() const
virtual void initializeHeightMetrics() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual void doKerning(QGlyphLayout *, ShaperFlags) const
QFixed m_leading
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
GlyphFormat glyphFormat
virtual QFixed leading() const
void * harfbuzzFace() const
virtual QFixed xHeight() const
QFixed m_descent
HintingPreference
Definition: qfont.h:88
@ PreferNoHinting
Definition: qfont.h:90
@ PreferFullHinting
Definition: qfont.h:92
@ PreferVerticalHinting
Definition: qfont.h:91
@ PreferDefaultHinting
Definition: qfont.h:89
@ Unstretched
Definition: qfont.h:122
@ NoSubpixelAntialias
Definition: qfont.h:82
@ NoAntialias
Definition: qfont.h:81
@ Bold
Definition: qfont.h:103
@ StyleItalic
Definition: qfont.h:111
@ StyleNormal
Definition: qfont.h:110
int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
static int getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName)
FT_CharMap symbol_map
FT_CharMap unicode_map
static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path)
int fsType() const
static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
bool isScalableBitmap() const
glyph_t cmapCache[cmapCacheSize]
static QFreetypeFace * getFace(const QFontEngine::FaceId &face_id, const QByteArray &fontData=QByteArray())
void release(const QFontEngine::FaceId &face_id)
QFontEngine::Properties properties() const
void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor)
bool getSfntTable(uint tag, uchar *buffer, uint *length) const
QScreen * primaryScreen
the primary (or default) screen of the application.
const_iterator cbegin() const noexcept
Definition: qhash.h:1157
const_iterator constFind(const Key &key) const noexcept
Definition: qhash.h:1224
const_iterator constEnd() const noexcept
Definition: qhash.h:1162
iterator erase(const_iterator it)
Definition: qhash.h:1172
T value(const Key &key) const noexcept
Definition: qhash.h:997
const_iterator cend() const noexcept
Definition: qhash.h:1161
template< typename... T > size_t qHashMulti(size_t seed, const T &...args)
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Definition: qhash.h:904
bool isEmpty() const noexcept
Definition: qhash.h:881
iterator insert(const Key &key, const T &value)
Definition: qhash.h:1228
QByteArray readAll()
Definition: qiodevice.cpp:1268
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
QImage copy(const QRect &rect=QRect()) const
Definition: qimage.cpp:1197
Format
Definition: qimage.h:77
@ Format_Alpha8
Definition: qimage.h:101
@ Format_RGB32
Definition: qimage.h:82
@ Format_Invalid
Definition: qimage.h:78
@ Format_Mono
Definition: qimage.h:79
@ Format_ARGB32_Premultiplied
Definition: qimage.h:84
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
bool qFuzzyCompare(const QMatrix4x4 &m1, const QMatrix4x4 &m2)
Definition: qmatrix4x4.cpp:774
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
virtual SubpixelAntialiasingType subpixelAntialiasingTypeHint() 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 QScopedValueRollback class resets a variable to its previous value on destruction.
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition: qscreen.h:68
QPlatformScreen * handle() const
Definition: qscreen.cpp:177
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
static QString fromUtf8(QByteArrayView utf8)
Definition: qstring.cpp:5632
QByteArray toUtf8() const &
Definition: qstring.h:749
The QThreadStorage class provides per-thread data storage.
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
QTransform & scale(qreal sx, qreal sy)
Definition: qtransform.cpp:460
QPoint map(const QPoint &p) const
void setMatrix(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33)
QTransform & translate(qreal dx, qreal dy)
Definition: qtransform.cpp:392
QRect mapRect(const QRect &) const
static QUuid createUuid()
Definition: quuid.cpp:936
QByteArray toByteArray(StringFormat mode=WithBraces) const
Definition: quuid.cpp:624
QHash< QFontEngine::FaceId, QFreetypeFace * > faces
QHash< FaceStyle, int > faceIndices
FT_Library library
float factor
b clear()
QString str
[2]
qDeleteAll(list.begin(), list.end())
double e
rect
[4]
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:796
#define FT_LOAD_NO_BITMAP
Definition: freetype.h:3025
FT_Set_Transform(FT_Face face, FT_Matrix *matrix, FT_Vector *delta)
Definition: ftobjs.c:689
#define FT_STYLE_FLAG_ITALIC
Definition: freetype.h:1475
#define FT_LOAD_TARGET_MONO
Definition: freetype.h:3139
FT_New_Face(FT_Library library, const char *filepathname, FT_Long face_index, FT_Face *aface)
Definition: ftobjs.c:1468
#define FT_IS_SFNT(face)
Definition: freetype.h:1290
#define FT_LOAD_TARGET_NORMAL
Definition: freetype.h:3137
#define FT_FACE_FLAG_SCALABLE
Definition: freetype.h:1197
FT_Done_Face(FT_Face face)
Definition: ftobjs.c:2783
enum FT_Render_Mode_ FT_Render_Mode
#define FT_LOAD_NO_HINTING
Definition: freetype.h:3023
FT_Get_Char_Index(FT_Face face, FT_ULong charcode)
Definition: ftobjs.c:3731
#define FT_LOAD_FORCE_AUTOHINT
Definition: freetype.h:3027
FT_Select_Size(FT_Face face, FT_Int strike_index)
Definition: ftobjs.c:3202
#define FT_IS_SCALABLE(face)
Definition: freetype.h:1271
#define FT_LOAD_DEFAULT
Definition: freetype.h:3021
#define FT_IS_FIXED_WIDTH(face)
Definition: freetype.h:1305
FT_Get_Postscript_Name(FT_Face face)
Definition: ftobjs.c:4147
struct FT_FaceRec_ * FT_Face
Definition: freetype.h:483
FT_Set_Charmap(FT_Face face, FT_CharMap charmap)
Definition: ftobjs.c:3564
#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
Definition: freetype.h:3030
FT_Vector_Transform(FT_Vector *vector, const FT_Matrix *matrix)
Definition: ftoutln.c:683
FT_Render_Glyph(FT_GlyphSlot slot, FT_Render_Mode render_mode)
Definition: ftobjs.c:4796
#define FT_HAS_COLOR(face)
Definition: freetype.h:1449
FT_Done_FreeType(FT_Library library)
Definition: ftinit.c:235
@ FT_RENDER_MODE_MONO
Definition: freetype.h:3251
@ FT_RENDER_MODE_NORMAL
Definition: freetype.h:3249
@ FT_RENDER_MODE_LIGHT
Definition: freetype.h:3250
@ FT_RENDER_MODE_LCD_V
Definition: freetype.h:3253
@ FT_RENDER_MODE_LCD
Definition: freetype.h:3252
#define FT_STYLE_FLAG_BOLD
Definition: freetype.h:1476
#define FT_LOAD_TARGET_LIGHT
Definition: freetype.h:3138
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:415
FT_Set_Char_Size(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution)
Definition: ftobjs.c:3331
FT_New_Memory_Face(FT_Library library, const FT_Byte *file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface)
Definition: ftobjs.c:1493
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:508
#define FT_LOAD_COLOR
Definition: freetype.h:3037
FT_Init_FreeType(FT_Library *alibrary)
Definition: ftinit.c:199
return FT_Err_Ok
Definition: ftbbox.c:526
FT_BEGIN_HEADER FT_Get_Font_Format(FT_Face face)
Definition: ftfntfmt.c:27
FT_Matrix_Multiply(const FT_Matrix *a, FT_Matrix *b)
Definition: ftcalc.c:660
@ FT_PIXEL_MODE_LCD_V
Definition: ftimage.h:188
@ FT_PIXEL_MODE_MONO
Definition: ftimage.h:183
@ FT_PIXEL_MODE_GRAY
Definition: ftimage.h:184
@ FT_PIXEL_MODE_LCD
Definition: ftimage.h:187
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:57
@ FT_LCD_FILTER_DEFAULT
Definition: ftlcdfil.h:163
@ FT_LCD_FILTER_NONE
Definition: ftlcdfil.h:162
FT_Library_SetLcdFilter(FT_Library library, FT_LcdFilter filter)
Definition: ftlcdfil.c:407
FT_BEGIN_HEADER enum FT_LcdFilter_ FT_LcdFilter
FT_Property_Get(FT_Library library, const FT_String *module_name, const FT_String *property_name, void *value)
Definition: ftobjs.c:5219
FT_Property_Set(FT_Library library, const FT_String *module_name, const FT_String *property_name, const void *value)
Definition: ftobjs.c:5202
FT_BEGIN_HEADER FT_GlyphSlot_Embolden(FT_GlyphSlot slot)
Definition: ftsynth.c:89
FT_GlyphSlot_Oblique(FT_GlyphSlot slot)
Definition: ftsynth.c:47
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
unsigned long FT_ULong
Definition: fttypes.h:253
unsigned char FT_Byte
Definition: fttypes.h:154
signed long FT_Fixed
Definition: fttypes.h:287
int FT_Error
Definition: fttypes.h:299
unsigned int FT_UInt
Definition: fttypes.h:231
backing_store_ptr info
[4]
Definition: jmemsys.h:161
QTextStream & hex(QTextStream &stream)
@ SmoothTransformation
Definition: qnamespace.h:1351
@ white
Definition: qnamespace.h:62
void * HANDLE
Definition: qnamespace.h:1561
@ CaseInsensitive
Definition: qnamespace.h:1283
def cm(ctx, *output)
Definition: qfloat16.h:381
void
Definition: png.h:1080
png_structrp int png_fixed_point red
Definition: png.h:1081
int qstrncmp(const char *str1, const char *str2, size_t len)
#define Q_UNREACHABLE()
QList< QString > QStringList
Definition: qcontainerfwd.h:64
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
constexpr T qbswap(T source)
Definition: qendian.h:135
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
#define FLOOR(x)
#define TRUNC(x)
#define CEIL(x)
FT_Library qt_getFreetype()
#define GLYPH2PATH_DEBUG
QByteArray qt_fontdata_from_index(int)
#define QT_MAX_CACHED_GLYPH_SIZE
QtFreetypeData * qt_getFreetypeData()
#define ROUND(x)
@ Err_Invalid_SubTable
Definition: qfontengine_p.h:81
@ Err_Ok
Definition: qfontengine_p.h:77
unsigned int quint32
Definition: qglobal.h:288
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
size_t quintptr
Definition: qglobal.h:310
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
unsigned int uint
Definition: qglobal.h:334
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLenum GLsizeiptr const void GLsizei faceIndex
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint index
[2]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLenum const void GLbitfield GLsizei numGlyphs
GLenum face
GLfloat GLfloat f
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum src
GLenum GLuint buffer
GLint GLsizei width
GLuint color
[2]
GLint left
GLenum GLenum dst
GLint GLint bottom
GLuint GLfloat x0
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLuint64 GLenum GLint fd
GLint ref
GLfloat n
GLint GLsizei GLsizei GLenum format
GLenum GLsizeiptr const void * fontData
GLuint GLfloat GLfloat y0
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
Definition: qopenglext.h:11564
GLbyte GLbyte blue
Definition: qopenglext.h:385
const GLubyte * c
Definition: qopenglext.h:12701
GLint void * img
Definition: qopenglext.h:233
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
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLbyte green
Definition: qopenglext.h:385
GLenum GLenum GLenum GLenum GLenum scale
Definition: qopenglext.h:10817
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
unsigned int glyph_t
Q_UNUSED(salary)
[21]
HB_EXTERN hb_font_get_glyph_func_t void * user_data
QScreen * screen
[1]
Definition: main.cpp:76
QFuture< QSet< QChar > > set
[10]
QList< int > vector
[14]
QFile file
[0]
QObject::connect nullptr
QStringList::Iterator it
unsigned int width
Definition: ftimage.h:263
unsigned char * buffer
Definition: ftimage.h:265
unsigned char pixel_mode
Definition: ftimage.h:267
unsigned int rows
Definition: ftimage.h:262
int pitch
Definition: ftimage.h:264
FT_Size size
Definition: freetype.h:1066
FT_UShort units_per_EM
Definition: freetype.h:1054
FT_Long style_flags
Definition: freetype.h:1034
FT_Vector advance
Definition: freetype.h:1882
FT_Int bitmap_top
Definition: freetype.h:1888
FT_Library library
Definition: freetype.h:1873
FT_Int bitmap_left
Definition: freetype.h:1887
FT_Bitmap bitmap
Definition: freetype.h:1886
FT_Fixed linearHoriAdvance
Definition: freetype.h:1880
FT_Glyph_Metrics metrics
Definition: freetype.h:1879
FT_Glyph_Format format
Definition: freetype.h:1884
FT_Fixed xx
Definition: fttypes.h:392
FT_Fixed yx
Definition: fttypes.h:393
FT_Fixed yy
Definition: fttypes.h:393
FT_Fixed xy
Definition: fttypes.h:392
FT_Fixed y_scale
Definition: freetype.h:1601
FT_UShort x_ppem
Definition: freetype.h:1597
FT_UShort y_ppem
Definition: freetype.h:1598
FT_Size_Metrics metrics
Definition: freetype.h:1636
FT_Pos x
Definition: ftimage.h:77
constexpr int value() const
Definition: qfixed_p.h:74
constexpr static QFixed fromReal(qreal r)
Definition: qfixed_p.h:71
constexpr QFixed round() const
Definition: qfixed_p.h:81
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
constexpr QPointF toPointF() const
Definition: qfixed_p.h:195
QFixed x
Definition: qfixed_p.h:191
uint hintingPreference
Definition: qfont_p.h:102
uint stretch
Definition: qfont_p.h:100
uint style
Definition: qfont_p.h:101
uint styleStrategy
Definition: qfont_p.h:99
qreal pixelSize
Definition: qfont_p.h:96
uint weight
Definition: qfont_p.h:105
QStringList families
Definition: qfont_p.h:90
QString styleName
Definition: qfont_p.h:91
qt_get_font_table_func_t get_font_table
signed char format
unsigned short height
unsigned short width
void setGlyph(glyph_t index, const QFixedPoint &spp, Glyph *glyph)
void removeGlyphFromCache(glyph_t index, const QFixedPoint &subPixelPosition)
Glyph * getGlyph(glyph_t index, const QFixedPoint &subPixelPositionX=QFixedPoint()) const
QFixed effectiveAdvance(int item) const
QGlyphAttributes * attributes
glyph_t * glyphs
QFixedPoint * offsets
QFixed * advances
FaceStyle(QString faceFileName, QString styleName)
FT_UShort version
Definition: tttables.h:377
FT_Short sxHeight
Definition: tttables.h:419
FT_Short sCapHeight
Definition: tttables.h:420
FT_UShort fsType
Definition: tttables.h:381
FT_Short xAvgCharWidth
Definition: tttables.h:378
FT_Get_PS_Font_Info(FT_Face face, PS_FontInfo afont_info)
FT_BEGIN_HEADER struct PS_FontInfoRec_ PS_FontInfoRec
FT_Get_Sfnt_Table(FT_Face face, FT_Sfnt_Tag tag)
Definition: ftobjs.c:4176
FT_Load_Sfnt_Table(FT_Face face, FT_ULong tag, FT_Long offset, FT_Byte *buffer, FT_ULong *length)
Definition: ftobjs.c:4197
#define ft_sfnt_os2
Definition: tttables.h:638
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154