Qt 4.8
qfontengine_ft.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdir.h"
43 #include "qmetatype.h"
44 #include "qtextstream.h"
45 #include "qvariant.h"
46 #include "qfontengine_ft_p.h"
47 
48 #ifndef QT_NO_FREETYPE
49 
50 #include "qfile.h"
51 #include "qabstractfileengine.h"
52 #include "qthreadstorage.h"
53 #include <qmath.h>
54 #include <private/qharfbuzz_p.h>
55 
56 #include "qfontengine_ft_p.h"
57 #include <ft2build.h>
58 #include FT_FREETYPE_H
59 #include FT_OUTLINE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
63 #include FT_GLYPH_H
64 
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
67 #endif
68 
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
71 #endif
72 
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
75 #endif
76 
77 #ifdef QT_LINUXBASE
78 #include FT_ERRORS_H
79 #endif
80 
81 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
82 # define QT_MAX_CACHED_GLYPH_SIZE 64
83 #endif
84 
86 
87 /*
88  * Freetype 2.1.7 and earlier used width/height
89  * for matching sizes in the BDF and PCF loaders.
90  * This has been fixed for 2.1.8.
91  */
92 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
93 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
94 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
95 #else
96 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
97 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
98 #endif
99 
100 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
101 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
102 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
103 #else
104 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
105 #endif
106 
107 #define FLOOR(x) ((x) & -64)
108 #define CEIL(x) (((x)+63) & -64)
109 #define TRUNC(x) ((x) >> 6)
110 #define ROUND(x) (((x)+32) & -64)
111 
112 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
113 {
114 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
115  FT_Face face = (FT_Face)font;
116  FT_ULong ftlen = *length;
117  FT_Error error = 0;
118 
119  if ( !FT_IS_SFNT(face) )
120  return HB_Err_Invalid_Argument;
121 
122  error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
123  *length = ftlen;
124  return (HB_Error)error;
125 #else
126  return HB_Err_Invalid_Argument;
127 #endif
128 }
129 
130 // -------------------------- Freetype support ------------------------------
131 
133 {
134 public:
136  : library(0)
137  { }
138 
139  FT_Library library;
141 };
142 
143 #ifdef QT_NO_THREAD
144 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
145 
147 {
148  return theFreetypeData();
149 }
150 #else
152 
154 {
155  QtFreetypeData *&freetypeData = theFreetypeData()->localData();
156  if (!freetypeData)
157  freetypeData = new QtFreetypeData;
158  return freetypeData;
159 }
160 #endif
161 
162 FT_Library qt_getFreetype()
163 {
164  QtFreetypeData *freetypeData = qt_getFreetypeData();
165  if (!freetypeData->library)
166  FT_Init_FreeType(&freetypeData->library);
167  return freetypeData->library;
168 }
169 
171 {
172  int fsType = 0;
173  TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
174  if (os2)
175  fsType = os2->fsType;
176  return fsType;
177 }
178 
179 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
180 {
181  if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
182  return error;
183 
184  if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
185  return HB_Err_Invalid_SubTable;
186 
187  *nPoints = face->glyph->outline.n_points;
188  if (!(*nPoints))
189  return HB_Err_Ok;
190 
191  if (point > *nPoints)
192  return HB_Err_Invalid_SubTable;
193 
194  *xpos = face->glyph->outline.points[point].x;
195  *ypos = face->glyph->outline.points[point].y;
196 
197  return HB_Err_Ok;
198 }
199 
200 /*
201  * One font file can contain more than one font (bold/italic for example)
202  * find the right one and return it.
203  *
204  * Returns the freetype face or 0 in case of an empty file or any other problems
205  * (like not being able to open the file)
206  */
208  const QByteArray &fontData)
209 {
210  if (face_id.filename.isEmpty() && fontData.isEmpty())
211  return 0;
212 
213  QtFreetypeData *freetypeData = qt_getFreetypeData();
214  if (!freetypeData->library)
215  FT_Init_FreeType(&freetypeData->library);
216 
217  QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
218  if (freetype) {
219  freetype->ref.ref();
220  } else {
222  FT_Face face;
223  if (!face_id.filename.isEmpty()) {
224  QFile file(QString::fromUtf8(face_id.filename));
225  if (face_id.filename.startsWith(":qmemoryfonts/")) {
226  // from qfontdatabase.cpp
228  QByteArray idx = face_id.filename;
229  idx.remove(0, 14); // remove ':qmemoryfonts/'
230  bool ok = false;
231  newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
232  if (!ok)
233  newFreetype->fontData = QByteArray();
235  if (!file.open(QIODevice::ReadOnly)) {
236  return 0;
237  }
238  newFreetype->fontData = file.readAll();
239  }
240  } else {
241  newFreetype->fontData = fontData;
242  }
243  if (!newFreetype->fontData.isEmpty()) {
244  if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
245  return 0;
246  }
247  } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
248  return 0;
249  }
250  newFreetype->face = face;
251 
252  newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
253  Q_CHECK_PTR(newFreetype->hbFace);
254  newFreetype->ref = 1;
255  newFreetype->xsize = 0;
256  newFreetype->ysize = 0;
257  newFreetype->matrix.xx = 0x10000;
258  newFreetype->matrix.yy = 0x10000;
259  newFreetype->matrix.xy = 0;
260  newFreetype->matrix.yx = 0;
261  newFreetype->unicode_map = 0;
262  newFreetype->symbol_map = 0;
263 #ifndef QT_NO_FONTCONFIG
264  newFreetype->charset = 0;
265 #endif
266 
267  memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
268 
269  for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
270  FT_CharMap cm = newFreetype->face->charmaps[i];
271  switch(cm->encoding) {
272  case FT_ENCODING_UNICODE:
273  newFreetype->unicode_map = cm;
274  break;
275  case FT_ENCODING_APPLE_ROMAN:
276  case FT_ENCODING_ADOBE_LATIN_1:
277  if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
278  newFreetype->unicode_map = cm;
279  break;
280  case FT_ENCODING_ADOBE_CUSTOM:
281  case FT_ENCODING_MS_SYMBOL:
282  if (!newFreetype->symbol_map)
283  newFreetype->symbol_map = cm;
284  break;
285  default:
286  break;
287  }
288  }
289 
290  if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
291  FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
292 # if 0
293  FcChar8 *name;
294  FcPatternGetString(pattern, FC_FAMILY, 0, &name);
295  qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
296  newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
297  newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
298  newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
299 
300  for (int i = 0; i < 256; i += 8)
301  qDebug(" %x: %d %d %d %d %d %d %d %d", i,
302  FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
303  FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
304  FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
305  FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
306 #endif
307 
308  FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
309  QT_TRY {
310  freetypeData->faces.insert(face_id, newFreetype.data());
311  } QT_CATCH(...) {
312  newFreetype.take()->release(face_id);
313  // we could return null in principle instead of throwing
314  QT_RETHROW;
315  }
316  freetype = newFreetype.take();
317  }
318  return freetype;
319 }
320 
322 {
323  QtFreetypeData *freetypeData = qt_getFreetypeData();
324  if (!ref.deref()) {
325  qHBFreeFace(hbFace);
326  FT_Done_Face(face);
327 #ifndef QT_NO_FONTCONFIG
328  if (charset)
329  FcCharSetDestroy(charset);
330 #endif
331  if(freetypeData->faces.contains(face_id))
332  freetypeData->faces.take(face_id);
333  delete this;
334  }
335  if (freetypeData->faces.isEmpty()) {
336  FT_Done_FreeType(freetypeData->library);
337  freetypeData->library = 0;
338  }
339 }
340 
341 
342 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
343 {
344  *ysize = qRound(fontDef.pixelSize * 64);
345  *xsize = *ysize * fontDef.stretch / 100;
346  *outline_drawing = false;
347 
348  /*
349  * Bitmap only faces must match exactly, so find the closest
350  * one (height dominant search)
351  */
352  if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
353  int best = 0;
354  for (int i = 1; i < face->num_fixed_sizes; i++) {
355  if (qAbs(*ysize - Y_SIZE(face,i)) <
356  qAbs (*ysize - Y_SIZE(face, best)) ||
357  (qAbs (*ysize - Y_SIZE(face, i)) ==
358  qAbs (*ysize - Y_SIZE(face, best)) &&
359  qAbs (*xsize - X_SIZE(face, i)) <
360  qAbs (*xsize - X_SIZE(face, best)))) {
361  best = i;
362  }
363  }
364  if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
365  *xsize = X_SIZE(face, best);
366  *ysize = Y_SIZE(face, best);
367  } else {
368  int err = 1;
369  if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
370  // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
371  err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
372  if (err && face->num_fixed_sizes == 1)
373  err = 0; //even more of a workaround...
374  }
375 
376  if (err)
377  *xsize = *ysize = 0;
378  }
379  } else {
380  *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
381  }
382 }
383 
385 {
387  p.postscriptName = FT_Get_Postscript_Name(face);
388  PS_FontInfoRec font_info;
389  if (FT_Get_PS_Font_Info(face, &font_info) == 0)
390  p.copyright = font_info.notice;
391  if (FT_IS_SCALABLE(face)) {
392  p.ascent = face->ascender;
393  p.descent = -face->descender;
394  p.leading = face->height - face->ascender + face->descender;
395  p.emSquare = face->units_per_EM;
396  p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
397  face->bbox.xMax - face->bbox.xMin,
398  face->bbox.yMax - face->bbox.yMin);
399  } else {
400  p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
401  p.descent = QFixed::fromFixed(-face->size->metrics.descender);
402  p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
403  p.emSquare = face->size->metrics.y_ppem;
404 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
405  p.boundingBox = QRectF(0, -p.ascent.toReal(),
406  face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
407  }
408  p.italicAngle = 0;
409  p.capHeight = p.ascent;
410  p.lineWidth = face->underline_thickness;
411  return p;
412 }
413 
414 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
415 {
416  bool result = false;
417 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
418  if (FT_IS_SFNT(face)) {
419  FT_ULong len = *length;
420  result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
421  *length = len;
422  }
423 #endif
424  return result;
425 }
426 
427 /* Some fonts (such as MingLiu rely on hinting to scale different
428  components to their correct sizes. While this is really broken (it
429  should be done in the component glyph itself, not the hinter) we
430  will have to live with it.
431 
432  This means we can not use FT_LOAD_NO_HINTING to get the glyph
433  outline. All we can do is to load the unscaled glyph and scale it
434  down manually when required.
435 */
436 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
437 {
438  x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
439  y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
440  FT_Vector *p = g->outline.points;
441  const FT_Vector *e = p + g->outline.n_points;
442  while (p < e) {
443  p->x = FT_MulFix(p->x, x_scale);
444  p->y = FT_MulFix(p->y, y_scale);
445  ++p;
446  }
447 }
448 
449 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
450 {
451  const qreal factor = 1/64.;
452  scaleOutline(face, g, x_scale, y_scale);
453 
454  QPointF cp = point.toPointF();
455 
456  // convert the outline to a painter path
457  int i = 0;
458  for (int j = 0; j < g->outline.n_contours; ++j) {
459  int last_point = g->outline.contours[j];
460  QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
461  if(!(g->outline.tags[i] & 1)) {
462  start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
463  start /= 2;
464  }
465 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
466 // qDebug("first point at %f %f", start.x(), start.y());
467  path->moveTo(start);
468 
469  QPointF c[4];
470  c[0] = start;
471  int n = 1;
472  while (i < last_point) {
473  ++i;
474  c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
475 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
476  ++n;
477  switch (g->outline.tags[i] & 3) {
478  case 2:
479  // cubic bezier element
480  if (n < 4)
481  continue;
482  c[3] = (c[3] + c[2])/2;
483  --i;
484  break;
485  case 0:
486  // quadratic bezier element
487  if (n < 3)
488  continue;
489  c[3] = (c[1] + c[2])/2;
490  c[2] = (2*c[1] + c[3])/3;
491  c[1] = (2*c[1] + c[0])/3;
492  --i;
493  break;
494  case 1:
495  case 3:
496  if (n == 2) {
497 // qDebug() << "lineTo" << c[1];
498  path->lineTo(c[1]);
499  c[0] = c[1];
500  n = 1;
501  continue;
502  } else if (n == 3) {
503  c[3] = c[2];
504  c[2] = (2*c[1] + c[3])/3;
505  c[1] = (2*c[1] + c[0])/3;
506  }
507  break;
508  }
509 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
510  path->cubicTo(c[1], c[2], c[3]);
511  c[0] = c[3];
512  n = 1;
513  }
514  if (n == 1) {
515 // qDebug() << "closeSubpath";
516  path->closeSubpath();
517  } else {
518  c[3] = start;
519  if (n == 2) {
520  c[2] = (2*c[1] + c[3])/3;
521  c[1] = (2*c[1] + c[0])/3;
522  }
523 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
524  path->cubicTo(c[1], c[2], c[3]);
525  }
526  ++i;
527  }
528 }
529 
530 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
531 
532 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
533 {
534  if (slot->format != FT_GLYPH_FORMAT_BITMAP
535  || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
536  return;
537 
538  QPointF cp = point.toPointF();
539  qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
540  slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
541 }
542 
544 {
545  delete [] data;
546 }
547 
548 static const uint subpixel_filter[3][3] = {
549  { 180, 60, 16 },
550  { 38, 180, 38 },
551  { 16, 60, 180 }
552 };
553 
554 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
555 {
556  uint res;
557  if (legacyFilter) {
558  uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
559  uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
560  uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
561  res = (mid << 24) + (high << 16) + (mid << 8) + low;
562  } else {
563  uint alpha = green;
564  res = (alpha << 24) + (red << 16) + (green << 8) + blue;
565  }
566  return res;
567 }
568 
569 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
570 {
571  int h = height;
572  const int offs = bgr ? -1 : 1;
573  const int w = width * 3;
574  while (h--) {
575  uint *dd = dst;
576  for (int x = 0; x < w; x += 3) {
577  uint red = src[x+1-offs];
578  uint green = src[x+1];
579  uint blue = src[x+1+offs];
580  *dd = filterPixel(red, green, blue, legacyFilter);
581  ++dd;
582  }
583  dst += width;
584  src += src_pitch;
585  }
586 }
587 
588 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
589 {
590  int h = height;
591  const int offs = bgr ? -src_pitch : src_pitch;
592  while (h--) {
593  for (int x = 0; x < width; x++) {
594  uint red = src[x+src_pitch-offs];
595  uint green = src[x+src_pitch];
596  uint blue = src[x+src_pitch+offs];
597  dst[x] = filterPixel(red, green, blue, legacyFilter);
598  }
599  dst += width;
600  src += 3*src_pitch;
601  }
602 }
603 
604 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
605 {
606  // convolute the bitmap with a triangle filter to get rid of color fringes
607  // If we take account for a gamma value of 2, we end up with
608  // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
609  // as this nicely sums up to 16 :)
610  int h = height;
611  while (h--) {
612  dst[0] = dst[1] = 0;
613  //
614  for (int x = 2; x < width - 2; ++x) {
615  uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
616  dst[x] = (uchar) (sum >> 4);
617  }
618  dst[width - 2] = dst[width - 1] = 0;
619  src += pitch;
620  dst += pitch;
621  }
622 }
623 
625 {
626  fontDef = fd;
627  matrix.xx = 0x10000;
628  matrix.yy = 0x10000;
629  matrix.xy = 0;
630  matrix.yx = 0;
631  cache_cost = 100;
632  kerning_pairs_loaded = false;
633  transform = false;
634  embolden = false;
635  antialias = true;
636  freetype = 0;
637  default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
638  default_hint_style = HintNone;
639  subpixelType = Subpixel_None;
640  lcdFilterType = 0;
641 #if defined(FT_LCD_FILTER_H)
642  lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
643 #endif
644  defaultFormat = Format_None;
645  canUploadGlyphsToServer = false;
646  embeddedbitmap = false;
647 }
648 
650 {
651  if (freetype)
652  freetype->release(face_id);
653  hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
654 }
655 
657 {
658  freeServerGlyphSet(defaultGlyphSet.id);
659  for (int i = 0; i < transformedGlyphSets.count(); ++i)
660  freeServerGlyphSet(transformedGlyphSets.at(i).id);
661 }
662 
663 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
664  const QByteArray &fontData)
665 {
666  return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
667 }
668 
669 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
670  QFreetypeFace *freetypeFace)
671 {
672  freetype = freetypeFace;
673  if (!freetype) {
674  xsize = 0;
675  ysize = 0;
676  return false;
677  }
678  defaultFormat = format;
679  this->antialias = antialias;
680 
681  if (!antialias)
683  else if (format == Format_A8)
684  glyphFormat = QFontEngineGlyphCache::Raster_A8;
685  else if (format == Format_A32)
687 
688  face_id = faceId;
689 
690  symbol = freetype->symbol_map != 0;
691  PS_FontInfoRec psrec;
692  // don't assume that type1 fonts are symbol fonts by default
693  if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
694  symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
695  }
696  // #####
697  freetype->hbFace->isSymbolFont = symbol;
698 
699  lbearing = rbearing = SHRT_MIN;
700  freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
701 
702  FT_Face face = lockFace();
703 
704  if (FT_IS_SCALABLE(face)) {
705  bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
706  if (fake_oblique)
707  matrix.xy = 0x10000*3/10;
708  FT_Set_Transform(face, &matrix, 0);
709  freetype->matrix = matrix;
710  if (fake_oblique)
711  transform = true;
712  // fake bold
713  if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
714  embolden = true;
715  // underline metrics
716  line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
717  underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
718  } else {
719  // copied from QFontEngineQPF
720  // ad hoc algorithm
721  int score = fontDef.weight * fontDef.pixelSize;
722  line_thickness = score / 700;
723  // looks better with thicker line for small pointsizes
724  if (line_thickness < 2 && score >= 1050)
725  line_thickness = 2;
726  underline_position = ((line_thickness * 2) + 3) / 6;
727  }
728  if (line_thickness < 1)
729  line_thickness = 1;
730 
731  hbFont.x_ppem = face->size->metrics.x_ppem;
732  hbFont.y_ppem = face->size->metrics.y_ppem;
733  hbFont.x_scale = face->size->metrics.x_scale;
734  hbFont.y_scale = face->size->metrics.y_scale;
735 
736  hbFace = freetype->hbFace;
737 
738  metrics = face->size->metrics;
739 
740 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
741  /*
742  TrueType fonts with embedded bitmaps may have a bitmap font specific
743  ascent/descent in the EBLC table. There is no direct public API
744  to extract those values. The only way we've found is to trick freetype
745  into thinking that it's not a scalable font in FT_SelectSize so that
746  the metrics are retrieved from the bitmap strikes.
747  */
748  if (FT_IS_SCALABLE(face)) {
749  for (int i = 0; i < face->num_fixed_sizes; ++i) {
750  if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
751  face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
752 
753  FT_Select_Size(face, i);
754  metrics.ascender = face->size->metrics.ascender;
755  metrics.descender = face->size->metrics.descender;
756  FT_Set_Char_Size(face, xsize, ysize, 0, 0);
757 
758  face->face_flags |= FT_FACE_FLAG_SCALABLE;
759  break;
760  }
761  }
762  }
763 #endif
764 
765  fontDef.styleName = QString::fromUtf8(face->style_name);
766 
767  unlockFace();
768 
769  fsType = freetype->fsType();
770  defaultGlyphSet.id = allocateServerGlyphSet();
771  return true;
772 }
773 
775 {
776  default_hint_style = style;
777 }
778 
780  bool &hsubpixel, int &vfactor) const
781 {
782  int load_flags = FT_LOAD_DEFAULT | default_load_flags;
783  int load_target = default_hint_style == HintLight
784  ? FT_LOAD_TARGET_LIGHT
785  : FT_LOAD_TARGET_NORMAL;
786 
787  if (format == Format_Mono) {
788  load_target = FT_LOAD_TARGET_MONO;
789  } else if (format == Format_A32) {
790  if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
791  if (default_hint_style == HintFull)
792  load_target = FT_LOAD_TARGET_LCD;
793  hsubpixel = true;
794  } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
795  if (default_hint_style == HintFull)
796  load_target = FT_LOAD_TARGET_LCD_V;
797  vfactor = 3;
798  }
799  }
800 
801  if (set && set->outline_drawing)
802  load_flags = FT_LOAD_NO_BITMAP;
803 
804  if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
805  load_flags |= FT_LOAD_NO_HINTING;
806  else
807  load_flags |= load_target;
808 
809  return load_flags;
810 }
811 
813  QFixed subPixelPosition,
815  bool fetchMetricsOnly) const
816 {
817 // Q_ASSERT(freetype->lock == 1);
818 
819  bool uploadToServer = false;
820  if (format == Format_None) {
821  if (defaultFormat != Format_None) {
822  format = defaultFormat;
823  if (canUploadGlyphsToServer)
824  uploadToServer = true;
825  } else {
826  format = Format_Mono;
827  }
828  }
829 
830  Glyph *g = set->getGlyph(glyph, subPixelPosition);
831  if (g && g->format == format) {
832  if (uploadToServer && !g->uploadedToServer) {
833  set->setGlyph(glyph, subPixelPosition, 0);
834  delete g;
835  g = 0;
836  } else {
837  return g;
838  }
839  }
840 
842 
843  Q_ASSERT(format != Format_None);
844  bool hsubpixel = false;
845  int vfactor = 1;
846  int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
847 
848 #ifndef Q_WS_QWS
849  if (format != Format_Mono && !embeddedbitmap)
850  load_flags |= FT_LOAD_NO_BITMAP;
851 #endif
852 
853  FT_Matrix matrix = freetype->matrix;
854  bool transform = matrix.xx != 0x10000
855  || matrix.yy != 0x10000
856  || matrix.xy != 0
857  || matrix.yx != 0;
858 
859  if (transform)
860  load_flags |= FT_LOAD_NO_BITMAP;
861 
862  FT_Face face = freetype->face;
863 
864  FT_Vector v;
865  v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
866  v.y = 0;
867  FT_Set_Transform(face, &freetype->matrix, &v);
868 
869  FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
870  if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
871  load_flags &= ~FT_LOAD_NO_BITMAP;
872  err = FT_Load_Glyph(face, glyph, load_flags);
873  }
874  if (err == FT_Err_Too_Few_Arguments) {
875  // this is an error in the bytecode interpreter, just try to run without it
876  load_flags |= FT_LOAD_FORCE_AUTOHINT;
877  err = FT_Load_Glyph(face, glyph, load_flags);
878  }
879  if (err != FT_Err_Ok)
880  qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
881 
882  if (set->outline_drawing && fetchMetricsOnly)
883  return 0;
884 
885  FT_GlyphSlot slot = face->glyph;
886  if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
887  FT_Library library = qt_getFreetype();
888 
889  info.xOff = TRUNC(ROUND(slot->advance.x));
890  info.yOff = 0;
891 
892  uchar *glyph_buffer = 0;
893  int glyph_buffer_size = 0;
894 #if defined(QT_USE_FREETYPE_LCDFILTER)
895  bool useFreetypeRenderGlyph = false;
896  if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
897  err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
898  if (err == FT_Err_Ok)
899  useFreetypeRenderGlyph = true;
900  }
901 
902  if (useFreetypeRenderGlyph) {
903  err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
904 
905  if (err != FT_Err_Ok)
906  qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
907 
908  FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
909 
910  info.height = slot->bitmap.rows / vfactor;
911  info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
912  info.x = -slot->bitmap_left;
913  info.y = slot->bitmap_top;
914 
915  glyph_buffer_size = info.width * info.height * 4;
916  glyph_buffer = new uchar[glyph_buffer_size];
917 
918  if (hsubpixel)
919  convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
920  else if (vfactor != 1)
921  convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
922  } else
923 #endif
924  {
925  int left = slot->metrics.horiBearingX;
926  int right = slot->metrics.horiBearingX + slot->metrics.width;
927  int top = slot->metrics.horiBearingY;
928  int bottom = slot->metrics.horiBearingY - slot->metrics.height;
929  if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
930  int l, r, t, b;
931  FT_Vector vector;
932  vector.x = left;
933  vector.y = top;
934  FT_Vector_Transform(&vector, &matrix);
935  l = r = vector.x;
936  t = b = vector.y;
937  vector.x = right;
938  vector.y = top;
939  FT_Vector_Transform(&vector, &matrix);
940  if (l > vector.x) l = vector.x;
941  if (r < vector.x) r = vector.x;
942  if (t < vector.y) t = vector.y;
943  if (b > vector.y) b = vector.y;
944  vector.x = right;
945  vector.y = bottom;
946  FT_Vector_Transform(&vector, &matrix);
947  if (l > vector.x) l = vector.x;
948  if (r < vector.x) r = vector.x;
949  if (t < vector.y) t = vector.y;
950  if (b > vector.y) b = vector.y;
951  vector.x = left;
952  vector.y = bottom;
953  FT_Vector_Transform(&vector, &matrix);
954  if (l > vector.x) l = vector.x;
955  if (r < vector.x) r = vector.x;
956  if (t < vector.y) t = vector.y;
957  if (b > vector.y) b = vector.y;
958  left = l;
959  right = r;
960  top = t;
961  bottom = b;
962  }
963  left = FLOOR(left);
964  right = CEIL(right);
965  bottom = FLOOR(bottom);
966  top = CEIL(top);
967 
968  int hpixels = TRUNC(right - left);
969  // subpixel position requires one more pixel
970  if (subPixelPosition > 0 && format != Format_Mono)
971  hpixels++;
972 
973  if (hsubpixel)
974  hpixels = hpixels*3 + 8;
975  info.width = hpixels;
976  info.height = TRUNC(top - bottom);
977  info.x = -TRUNC(left);
978  info.y = TRUNC(top);
979  if (hsubpixel) {
980  info.width /= 3;
981  info.x += 1;
982  }
983 
984  bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
985  || ((uchar)(info.width) != info.width)
986  || ((uchar)(info.height) != info.height)
987  || ((signed char)(info.x) != info.x)
988  || ((signed char)(info.y) != info.y)
989  || ((signed char)(info.xOff) != info.xOff));
990 
991  if (large_glyph) {
992  delete [] glyph_buffer;
993  return 0;
994  }
995 
996  int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
997  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
998  glyph_buffer_size = pitch * info.height;
999  glyph_buffer = new uchar[glyph_buffer_size];
1000 
1001  if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1002  FT_Bitmap bitmap;
1003  bitmap.rows = info.height*vfactor;
1004  bitmap.width = hpixels;
1005  bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1006  if (!hsubpixel && vfactor == 1)
1007  bitmap.buffer = glyph_buffer;
1008  else
1009  bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1010  memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1011  bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1012  FT_Matrix matrix;
1013  matrix.xx = (hsubpixel ? 3 : 1) << 16;
1014  matrix.yy = vfactor << 16;
1015  matrix.yx = matrix.xy = 0;
1016 
1017  FT_Outline_Transform(&slot->outline, &matrix);
1018  FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1019  FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1020  if (hsubpixel) {
1021  Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1022  Q_ASSERT(antialias);
1023  uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1024  bool useLegacyLcdFilter = false;
1025 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1026  useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1027 #endif
1028  uchar *buffer = bitmap.buffer;
1029  if (!useLegacyLcdFilter) {
1030  convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1031  buffer = convoluted;
1032  }
1033  convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1034  delete [] convoluted;
1035  } else if (vfactor != 1) {
1036  convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1037  }
1038 
1039  if (bitmap.buffer != glyph_buffer)
1040  delete [] bitmap.buffer;
1041  } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1042  Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1043  uchar *src = slot->bitmap.buffer;
1044  uchar *dst = glyph_buffer;
1045  int h = slot->bitmap.rows;
1046  if (format == Format_Mono) {
1047  int bytes = ((info.width + 7) & ~7) >> 3;
1048  while (h--) {
1049  memcpy (dst, src, bytes);
1050  dst += pitch;
1051  src += slot->bitmap.pitch;
1052  }
1053  } else {
1054  if (hsubpixel) {
1055  while (h--) {
1056  uint *dd = (uint *)dst;
1057  *dd++ = 0;
1058  for (int x = 0; x < slot->bitmap.width; x++) {
1059  uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1060  *dd++ = a;
1061  }
1062  *dd++ = 0;
1063  dst += pitch;
1064  src += slot->bitmap.pitch;
1065  }
1066  } else if (vfactor != 1) {
1067  while (h--) {
1068  uint *dd = (uint *)dst;
1069  for (int x = 0; x < slot->bitmap.width; x++) {
1070  uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1071  *dd++ = a;
1072  }
1073  dst += pitch;
1074  src += slot->bitmap.pitch;
1075  }
1076  } else {
1077  while (h--) {
1078  for (int x = 0; x < slot->bitmap.width; x++) {
1079  unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1080  dst[x] = a;
1081  }
1082  dst += pitch;
1083  src += slot->bitmap.pitch;
1084  }
1085  }
1086  }
1087  } else {
1088  qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1089  delete [] glyph_buffer;
1090  return 0;
1091  }
1092  }
1093 
1094 
1095  if (!g) {
1096  g = new Glyph;
1097  g->uploadedToServer = false;
1098  g->data = 0;
1099  }
1100 
1101  g->linearAdvance = slot->linearHoriAdvance >> 10;
1102  g->width = info.width;
1103  g->height = info.height;
1104  g->x = -info.x;
1105  g->y = info.y;
1106  g->advance = info.xOff;
1107  g->format = format;
1108  delete [] g->data;
1109  g->data = glyph_buffer;
1110 
1111  if (uploadToServer) {
1112  uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1113  }
1114 
1115  set->setGlyph(glyph, subPixelPosition, g);
1116 
1117  return g;
1118 }
1119 
1120 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1121 {
1122  Q_UNUSED(set);
1123  Q_UNUSED(glyphid);
1124  Q_UNUSED(g);
1125  Q_UNUSED(info);
1126  Q_UNUSED(glyphDataSize);
1127  return false;
1128 }
1129 
1131 {
1132  return face_id;
1133 }
1134 
1136 {
1137  Properties p = freetype->properties();
1138  if (p.postscriptName.isEmpty()) {
1140  }
1141 
1142  return freetype->properties();
1143 }
1144 
1146 {
1147  if (FT_IS_SCALABLE(freetype->face))
1148  return freetype->face->units_per_EM;
1149  else
1150  return freetype->face->size->metrics.y_ppem;
1151 }
1152 
1153 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1154 {
1155  return freetype->getSfntTable(tag, buffer, length);
1156 }
1157 
1159 {
1160  int s = 0;
1161  if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1162  s = SynthesizedItalic;
1163  if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1164  s |= SynthesizedBold;
1165  if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1166  s |= SynthesizedStretch;
1167  return s;
1168 }
1169 
1171 {
1172  return QFixed::fromFixed(metrics.ascender);
1173 }
1174 
1176 {
1177  // subtract a pixel to work around QFontMetrics's built-in + 1
1178  return QFixed::fromFixed(-metrics.descender - 64);
1179 }
1180 
1182 {
1183  return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1184 }
1185 
1187 {
1188  TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1189  if (os2 && os2->sxHeight) {
1190  lockFace();
1191  QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1192  unlockFace();
1193  return answer;
1194  }
1195  return QFontEngine::xHeight();
1196 }
1197 
1199 {
1200  TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1201  if (os2 && os2->xAvgCharWidth) {
1202  lockFace();
1203  QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1204  unlockFace();
1205  return answer;
1206  }
1208 }
1209 
1211 {
1212  return metrics.max_advance >> 6;
1213 }
1214 
1215 static const ushort char_table[] = {
1216  40,
1217  67,
1218  70,
1219  75,
1220  86,
1221  88,
1222  89,
1223  91,
1224  102,
1225  114,
1226  124,
1227  127,
1228  205,
1229  645,
1230  884,
1231  922,
1232  1070,
1233  12386
1234 };
1235 
1236 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1237 
1238 
1240 {
1241  if (lbearing == SHRT_MIN)
1242  (void) minRightBearing(); // calculates both
1243  return lbearing.toReal();
1244 }
1245 
1247 {
1248  if (rbearing == SHRT_MIN) {
1249  lbearing = rbearing = 0;
1250  const QChar *ch = (const QChar *)(const void*)char_table;
1252  int ng = char_table_entries;
1253  stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1254  while (--ng) {
1255  if (glyphs.glyphs[ng]) {
1256  glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1257  lbearing = qMin(lbearing, gi.x);
1258  rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1259  }
1260  }
1261  }
1262  return rbearing.toReal();
1263 }
1264 
1266 {
1267  return line_thickness;
1268 }
1269 
1271 {
1272  return underline_position;
1273 }
1274 
1275 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1276 {
1277  if (!kerning_pairs_loaded) {
1278  kerning_pairs_loaded = true;
1279  lockFace();
1280  if (freetype->face->size->metrics.x_ppem != 0) {
1281  QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1282  unlockFace();
1283  const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1284  } else {
1285  unlockFace();
1286  }
1287  }
1288  QFontEngine::doKerning(g, flags);
1289 }
1290 
1292 {
1293  if (matrix.type() > QTransform::TxShear)
1294  return 0;
1295 
1296  // FT_Set_Transform only supports scalable fonts
1297  if (!FT_IS_SCALABLE(freetype->face))
1298  return 0;
1299 
1300  FT_Matrix m;
1301  m.xx = FT_Fixed(matrix.m11() * 65536);
1302  m.xy = FT_Fixed(-matrix.m21() * 65536);
1303  m.yx = FT_Fixed(-matrix.m12() * 65536);
1304  m.yy = FT_Fixed(matrix.m22() * 65536);
1305 
1306  QGlyphSet *gs = 0;
1307 
1308  for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1309  const QGlyphSet &g = transformedGlyphSets.at(i);
1310  if (g.transformationMatrix.xx == m.xx
1311  && g.transformationMatrix.xy == m.xy
1312  && g.transformationMatrix.yx == m.yx
1313  && g.transformationMatrix.yy == m.yy) {
1314 
1315  // found a match, move it to the front
1316  transformedGlyphSets.move(i, 0);
1317  gs = &transformedGlyphSets[0];
1318  break;
1319  }
1320  }
1321 
1322  if (!gs) {
1323  // don't try to load huge fonts
1324  bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1325  if (draw_as_outline)
1326  return 0;
1327 
1328  // don't cache more than 10 transformations
1329  if (transformedGlyphSets.count() >= 10) {
1330  transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1331  freeServerGlyphSet(transformedGlyphSets.at(0).id);
1332  } else {
1333  transformedGlyphSets.prepend(QGlyphSet());
1334  }
1335  gs = &transformedGlyphSets[0];
1336 
1337  gs->clear();
1338 
1339  gs->id = allocateServerGlyphSet();
1340 
1341  gs->transformationMatrix = m;
1342  gs->outline_drawing = draw_as_outline;
1343  }
1344 
1345  return gs;
1346 }
1347 
1349 {
1350  int m_subPixelPositionCount = 4;
1351  if (!supportsSubPixelPositions())
1352  return 0;
1353 
1354  QFixed subPixelPosition;
1355  if (x != 0) {
1356  subPixelPosition = x - x.floor();
1357  QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1358  subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1359  }
1360  return subPixelPosition;
1361 }
1362 
1363 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1364  const QFixedPoint *positions,
1366 {
1367  FT_Face face = 0;
1368 
1369  for (int i = 0; i < num_glyphs; ++i) {
1370  QFixed spp = subPixelPositionForX(positions[i].x);
1371  Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1372  if (glyph == 0 || glyph->format != format) {
1373  if (!face) {
1374  face = lockFace();
1375  FT_Matrix m = matrix;
1376  FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1377  FT_Set_Transform(face, &m, 0);
1378  freetype->matrix = m;
1379  }
1380  if (!loadGlyph(gs, glyphs[i], spp, format)) {
1381  unlockFace();
1382  return false;
1383  }
1384  }
1385  }
1386 
1387  if (face)
1388  unlockFace();
1389 
1390  return true;
1391 }
1392 
1394 {
1395  FT_Face face = lockFace(Unscaled);
1396  FT_Set_Transform(face, 0, 0);
1397  FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1398 
1399  int left = face->glyph->metrics.horiBearingX;
1400  int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1401  int top = face->glyph->metrics.horiBearingY;
1402  int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1403 
1404  QFixedPoint p;
1405  p.x = 0;
1406  p.y = 0;
1407 
1408  metrics->width = QFixed::fromFixed(right-left);
1409  metrics->height = QFixed::fromFixed(top-bottom);
1410  metrics->x = QFixed::fromFixed(left);
1411  metrics->y = QFixed::fromFixed(-top);
1412  metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1413 
1414  if (!FT_IS_SCALABLE(freetype->face))
1415  QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1416  else
1417  QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1418 
1419  FT_Set_Transform(face, &freetype->matrix, 0);
1420  unlockFace();
1421 }
1422 
1423 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1424 {
1425  uint ucs4 = str[i].unicode();
1426  if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1427  ++i;
1428  ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1429  }
1430  return ucs4;
1431 }
1432 
1433 bool QFontEngineFT::canRender(const QChar *string, int len)
1434 {
1435  FT_Face face = freetype->face;
1436 #if 0
1437  if (_cmap != -1) {
1438  lockFace();
1439  for ( int i = 0; i < len; i++ ) {
1440  unsigned int uc = getChar(string, i, len);
1441  if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1442  allExist = false;
1443  break;
1444  }
1445  }
1446  unlockFace();
1447  } else
1448 #endif
1449  {
1450  for ( int i = 0; i < len; i++ ) {
1451  unsigned int uc = getChar(string, i, len);
1452  if (!FT_Get_Char_Index(face, uc))
1453  return false;
1454  }
1455  }
1456  return true;
1457 }
1458 
1459 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1460 {
1461  if (!glyphs.numGlyphs)
1462  return;
1463 
1464  if (FT_IS_SCALABLE(freetype->face)) {
1465  QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1466  } else {
1468  QVarLengthArray<glyph_t> positioned_glyphs;
1469  QTransform matrix;
1470  matrix.translate(x, y);
1471  getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1472 
1473  FT_Face face = lockFace(Unscaled);
1474  for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1475  FT_UInt glyph = positioned_glyphs[gl];
1476  FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1477  freetype->addBitmapToPath(face->glyph, positions[gl], path);
1478  }
1479  unlockFace();
1480  }
1481 }
1482 
1484  QPainterPath *path, QTextItem::RenderFlags)
1485 {
1486  FT_Face face = lockFace(Unscaled);
1487 
1488  for (int gl = 0; gl < numGlyphs; gl++) {
1489  FT_UInt glyph = glyphs[gl];
1490 
1491  FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1492 
1493  FT_GlyphSlot g = face->glyph;
1494  if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1495  continue;
1496  QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1497  }
1498  unlockFace();
1499 }
1500 
1501 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1502  QTextEngine::ShaperFlags flags) const
1503 {
1504  if (*nglyphs < len) {
1505  *nglyphs = len;
1506  return false;
1507  }
1508 
1509 #if !defined(QT_NO_FONTCONFIG)
1510  extern QMutex *qt_fontdatabase_mutex();
1511  QMutex *mtx = 0;
1512 #endif
1513 
1514  bool mirrored = flags & QTextEngine::RightToLeft;
1515  int glyph_pos = 0;
1516  if (freetype->symbol_map) {
1517  FT_Face face = freetype->face;
1518  for ( int i = 0; i < len; ++i ) {
1519  unsigned int uc = getChar(str, i, len);
1520  glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1521  if ( !glyphs->glyphs[glyph_pos] ) {
1522  glyph_t glyph;
1523 #if !defined(QT_NO_FONTCONFIG)
1524  if (!mtx) {
1525  mtx = qt_fontdatabase_mutex();
1526  mtx->lock();
1527  }
1528 
1529  if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1530 #else
1531  if (false) {
1532 #endif
1533  redo0:
1534  glyph = FT_Get_Char_Index(face, uc);
1535  if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1536  uc = 0x20;
1537  goto redo0;
1538  }
1539  } else {
1540  FT_Set_Charmap(face, freetype->symbol_map);
1541  glyph = FT_Get_Char_Index(face, uc);
1542  FT_Set_Charmap(face, freetype->unicode_map);
1543  }
1544  glyphs->glyphs[glyph_pos] = glyph;
1546  freetype->cmapCache[uc] = glyph;
1547  }
1548  ++glyph_pos;
1549  }
1550  } else {
1551  FT_Face face = freetype->face;
1552  for (int i = 0; i < len; ++i) {
1553  unsigned int uc = getChar(str, i, len);
1554  if (mirrored)
1555  uc = QChar::mirroredChar(uc);
1556  glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1557  if (!glyphs->glyphs[glyph_pos]) {
1558 #if !defined(QT_NO_FONTCONFIG)
1559  if (!mtx) {
1560  mtx = qt_fontdatabase_mutex();
1561  mtx->lock();
1562  }
1563 
1564  if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1565 #endif
1566  {
1567  redo:
1568  glyph_t glyph = FT_Get_Char_Index(face, uc);
1569  if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1570  uc = 0x20;
1571  goto redo;
1572  }
1573  glyphs->glyphs[glyph_pos] = glyph;
1575  freetype->cmapCache[uc] = glyph;
1576  }
1577  }
1578  ++glyph_pos;
1579  }
1580  }
1581 
1582  *nglyphs = glyph_pos;
1583  glyphs->numGlyphs = glyph_pos;
1584 
1585 #if !defined(QT_NO_FONTCONFIG)
1586  if (mtx)
1587  mtx->unlock();
1588 #endif
1589 
1590  if (flags & QTextEngine::GlyphIndicesOnly)
1591  return true;
1592 
1593  recalcAdvances(glyphs, flags);
1594 
1595  return true;
1596 }
1597 
1598 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1599 {
1600  FT_Face face = 0;
1601  bool design = (default_hint_style == HintNone ||
1602  default_hint_style == HintLight ||
1603  (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1604  for (int i = 0; i < glyphs->numGlyphs; i++) {
1605  Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1606  if (g) {
1607  glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1608  } else {
1609  if (!face)
1610  face = lockFace();
1611  g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1612  glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1613  : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1614  }
1615  if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1616  glyphs->advances_x[i] = glyphs->advances_x[i].round();
1617  glyphs->advances_y[i] = 0;
1618  }
1619  if (face)
1620  unlockFace();
1621 }
1622 
1624 {
1625 
1626  FT_Face face = 0;
1627 
1628  glyph_metrics_t overall;
1629  // initialize with line height, we get the same behaviour on all platforms
1630  overall.y = -ascent();
1631  overall.height = ascent() + descent() + 1;
1632 
1633  QFixed ymax = 0;
1634  QFixed xmax = 0;
1635  for (int i = 0; i < glyphs.numGlyphs; i++) {
1636  Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1637  if (!g) {
1638  if (!face)
1639  face = lockFace();
1640  g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1641  }
1642  if (g) {
1643  QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1644  QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1645  overall.x = qMin(overall.x, x);
1646  overall.y = qMin(overall.y, y);
1647  xmax = qMax(xmax, x + g->width);
1648  ymax = qMax(ymax, y + g->height);
1649  overall.xoff += qRound(g->advance);
1650  } else {
1651  int left = FLOOR(face->glyph->metrics.horiBearingX);
1652  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1653  int top = CEIL(face->glyph->metrics.horiBearingY);
1654  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1655 
1656  QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1657  QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1658  overall.x = qMin(overall.x, x);
1659  overall.y = qMin(overall.y, y);
1660  xmax = qMax(xmax, x + TRUNC(right - left));
1661  ymax = qMax(ymax, y + TRUNC(top - bottom));
1662  overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1663  }
1664  }
1665  overall.height = qMax(overall.height, ymax - overall.y);
1666  overall.width = xmax - overall.x;
1667 
1668  if (face)
1669  unlockFace();
1670 
1671  return overall;
1672 }
1673 
1675 {
1676  FT_Face face = 0;
1677  glyph_metrics_t overall;
1678  Glyph *g = defaultGlyphSet.getGlyph(glyph);
1679  if (!g) {
1680  face = lockFace();
1681  g = loadGlyph(glyph, 0, Format_None, true);
1682  }
1683  if (g) {
1684  overall.x = g->x;
1685  overall.y = -g->y;
1686  overall.width = g->width;
1687  overall.height = g->height;
1688  overall.xoff = g->advance;
1689  if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1690  overall.xoff = overall.xoff.round();
1691  } else {
1692  int left = FLOOR(face->glyph->metrics.horiBearingX);
1693  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1694  int top = CEIL(face->glyph->metrics.horiBearingY);
1695  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1696 
1697  overall.width = TRUNC(right-left);
1698  overall.height = TRUNC(top-bottom);
1699  overall.x = TRUNC(left);
1700  overall.y = -TRUNC(top);
1701  overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1702  }
1703  if (face)
1704  unlockFace();
1705  return overall;
1706 }
1707 
1709 {
1710  return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1711 }
1712 
1714 {
1715  FT_Face face = 0;
1716  glyph_metrics_t overall;
1717  QGlyphSet *glyphSet = 0;
1718  if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1719  // TODO move everything here to a method of its own to access glyphSets
1720  // to be shared with a new method that will replace loadTransformedGlyphSet()
1721  FT_Matrix m;
1722  m.xx = FT_Fixed(matrix.m11() * 65536);
1723  m.xy = FT_Fixed(-matrix.m21() * 65536);
1724  m.yx = FT_Fixed(-matrix.m12() * 65536);
1725  m.yy = FT_Fixed(matrix.m22() * 65536);
1726  for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1727  const QGlyphSet &g = transformedGlyphSets.at(i);
1728  if (g.transformationMatrix.xx == m.xx
1729  && g.transformationMatrix.xy == m.xy
1730  && g.transformationMatrix.yx == m.yx
1731  && g.transformationMatrix.yy == m.yy) {
1732 
1733  // found a match, move it to the front
1734  transformedGlyphSets.move(i, 0);
1735  glyphSet = &transformedGlyphSets[0];
1736  break;
1737  }
1738  }
1739 
1740  if (!glyphSet) {
1741  // don't cache more than 10 transformations
1742  if (transformedGlyphSets.count() >= 10) {
1743  transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1744  freeServerGlyphSet(transformedGlyphSets.at(0).id);
1745  } else {
1746  transformedGlyphSets.prepend(QGlyphSet());
1747  }
1748  glyphSet = &transformedGlyphSets[0];
1749  glyphSet->clear();
1750  glyphSet->id = allocateServerGlyphSet();
1751  glyphSet->transformationMatrix = m;
1752  }
1753  Q_ASSERT(glyphSet);
1754  } else {
1755  glyphSet = &defaultGlyphSet;
1756  }
1757  Glyph * g = glyphSet->getGlyph(glyph);
1758  if (!g || g->format != format) {
1759  face = lockFace();
1760  FT_Matrix m = this->matrix;
1761  FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1762  freetype->matrix = m;
1763  g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1764  }
1765 
1766  if (g) {
1767  overall.x = g->x;
1768  overall.y = -g->y;
1769  overall.width = g->width;
1770  overall.height = g->height;
1771  overall.xoff = g->advance;
1772  } else {
1773  int left = FLOOR(face->glyph->metrics.horiBearingX);
1774  int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1775  int top = CEIL(face->glyph->metrics.horiBearingY);
1776  int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1777 
1778  overall.width = TRUNC(right-left);
1779  overall.height = TRUNC(top-bottom);
1780  overall.x = TRUNC(left);
1781  overall.y = -TRUNC(top);
1782  overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1783  }
1784  if (face)
1785  unlockFace();
1786  return overall;
1787 }
1788 
1790 {
1791  lockFace();
1792 
1793  GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1794 
1795  Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1796  if (!glyph) {
1797  unlockFace();
1799  }
1800 
1801  const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1802 
1803  QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1804  if (antialias) {
1805  QVector<QRgb> colors(256);
1806  for (int i=0; i<256; ++i)
1807  colors[i] = qRgba(0, 0, 0, i);
1808  img.setColorTable(colors);
1809  } else {
1810  QVector<QRgb> colors(2);
1811  colors[0] = qRgba(0, 0, 0, 0);
1812  colors[1] = qRgba(0, 0, 0, 255);
1813  img.setColorTable(colors);
1814  }
1815  Q_ASSERT(img.bytesPerLine() == pitch);
1816  if (glyph->width) {
1817  for (int y = 0; y < glyph->height; ++y)
1818  memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1819  }
1820  unlockFace();
1821 
1822  return img;
1823 }
1824 
1825 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1826 {
1827  if (t.type() > QTransform::TxTranslate)
1828  return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1829 
1830  lockFace();
1831 
1832  GlyphFormat glyph_format = Format_A32;
1833 
1834  Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1835  if (!glyph) {
1836  unlockFace();
1837  return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1838  }
1839 
1840  QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1841  memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1842  unlockFace();
1843 
1844  return img;
1845 }
1846 
1848 {
1849  defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1850 }
1851 
1853 {
1854  int count = 0;
1855  FT_Face face = lockFace();
1856  if (face) {
1857  count = face->num_glyphs;
1858  unlockFace();
1859  }
1860  return count;
1861 }
1862 
1864 {
1865  freetype->lock();
1866  FT_Face face = freetype->face;
1867  if (scale == Unscaled) {
1868  FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1869  freetype->xsize = face->units_per_EM << 6;
1870  freetype->ysize = face->units_per_EM << 6;
1871  } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1872  FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1873  freetype->xsize = xsize;
1874  freetype->ysize = ysize;
1875  }
1876  if (freetype->matrix.xx != matrix.xx ||
1877  freetype->matrix.yy != matrix.yy ||
1878  freetype->matrix.xy != matrix.xy ||
1879  freetype->matrix.yx != matrix.yx) {
1880  freetype->matrix = matrix;
1881  FT_Set_Transform(face, &freetype->matrix, 0);
1882  }
1883 
1884  return face;
1885 }
1886 
1888 {
1889  freetype->unlock();
1890 }
1891 
1893 {
1894  return freetype->face;
1895 }
1896 
1897 
1899  : id(0), outline_drawing(false)
1900 {
1901  transformationMatrix.xx = 0x10000;
1902  transformationMatrix.yy = 0x10000;
1903  transformationMatrix.xy = 0;
1904  transformationMatrix.yx = 0;
1905  memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1906  fast_glyph_count = 0;
1907 }
1908 
1910 {
1911  clear();
1912 }
1913 
1915 {
1916  if (fast_glyph_count > 0) {
1917  for (int i = 0; i < 256; ++i) {
1918  if (fast_glyph_data[i]) {
1919  delete fast_glyph_data[i];
1920  fast_glyph_data[i] = 0;
1921  }
1922  }
1923  fast_glyph_count = 0;
1924  }
1926  glyph_data.clear();
1927 }
1928 
1930 {
1931  if (useFastGlyphData(index, subPixelPosition)) {
1932  if (fast_glyph_data[index]) {
1933  delete fast_glyph_data[index];
1934  fast_glyph_data[index] = 0;
1935  if (fast_glyph_count > 0)
1936  --fast_glyph_count;
1937  }
1938  } else {
1939  delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1940  }
1941 }
1942 
1944 {
1945  if (useFastGlyphData(index, subPixelPosition)) {
1946  if (!fast_glyph_data[index])
1947  ++fast_glyph_count;
1948  fast_glyph_data[index] = glyph;
1949  } else {
1950  glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1951  }
1952 }
1953 
1955 {
1956  return 0;
1957 }
1958 
1960 {
1961  Q_UNUSED(id);
1962 }
1963 
1964 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1965 {
1966  lockFace();
1967  bool hsubpixel = true;
1968  int vfactor = 1;
1969  int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1970  HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1971  unlockFace();
1972  return result;
1973 }
1974 
1976 {
1977  if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1978  return false;
1979 
1980  // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1981  // will be using it
1982  freetype->ref.ref();
1983 
1986  antialias = fe->antialias;
1987  transform = fe->transform;
1988  embolden = fe->embolden;
1989  subpixelType = fe->subpixelType;
1993 
1994  return true;
1995 }
1996 
1998 {
1999  QFontDef fontDef;
2000  fontDef.pixelSize = pixelSize;
2001  QFontEngineFT *fe = new QFontEngineFT(fontDef);
2002  if (!fe->initFromFontEngine(this)) {
2003  delete fe;
2004  return 0;
2005  } else {
2006  return fe;
2007  }
2008 }
2009 
2011 
2012 #endif // QT_NO_FREETYPE
static QFreetypeFace * getFace(const QFontEngine::FaceId &face_id, const QByteArray &fontData=QByteArray())
HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
#define X_SIZE(face, i)
virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const
This function should return the set of OR&#39;d flags that are true for the file engine&#39;s file...
SubpixelAntialiasingType subpixelType
static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
virtual QFixed averageCharWidth() const
unsigned int uploadedToServer
QFixed * advances_y
static QFixed fromFixed(int fixed)
Definition: qfixed_p.h:71
void qHBFreeFace(HB_Face face)
Definition: qharfbuzz.cpp:128
Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index)
double qreal
Definition: qglobal.h:1193
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
QFontEngineFT(const QFontDef &fd)
virtual QImage alphaMapForGlyph(glyph_t)
static mach_timebase_info_data_t info
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
static const ushort char_table[]
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void lock()
Locks the mutex.
Definition: qmutex.cpp:151
void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
void setGlyph(glyph_t index, QFixed spp, Glyph *glyph)
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
QFixed * advances_x
T * data() const
Returns the value of the pointer referenced by this object.
ushort unicode() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qchar.h:251
virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
HB_Glyph * glyphs
virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const
static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
#define error(msg)
qreal m21() const
Returns the horizontal shearing factor.
Definition: qtransform.h:249
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
T * take()
Returns the value of the pointer referenced by this object.
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
virtual QAbstractFileEngine * fileEngine() const
Returns the QIOEngine for this QFile object.
Definition: qfile.cpp:1965
qreal m22() const
Returns the vertical scaling factor.
Definition: qtransform.h:253
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)
virtual QImage alphaMapForGlyph(glyph_t g)
long ASN1_INTEGER_get ASN1_INTEGER * a
GlyphFormat defaultFormat
virtual void freeServerGlyphSet(unsigned long id)
static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
bool ref()
Atomically increments the value of this QAtomicInt.
virtual QFontEngine::Properties properties() const
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
Definition: qtransform.cpp:417
bool getSfntTable(uint tag, uchar *buffer, uint *length) const
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it...
Definition: qhash.h:807
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
FT_Library library
static QFixed fromReal(qreal r)
Definition: qfixed_p.h:70
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
TransformationType type() const
Returns the transformation type of this matrix.
bool startsWith(const QByteArray &a) const
Returns true if this byte array starts with byte array ba; otherwise returns false.
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
virtual void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t)
Glyph * getGlyph(glyph_t index, QFixed subPixelPosition=0) const
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
virtual bool canRender(const QChar *string, int len)
bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat=Format_None, const QByteArray &fontData=QByteArray())
HintStyle default_hint_style
#define ROUND(x)
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
Q_CORE_EXPORT void qDebug(const char *,...)
qreal m12() const
Returns the vertical shearing factor.
Definition: qtransform.h:241
#define QT_RETHROW
Definition: qglobal.h:1539
unsigned char uchar
Definition: qglobal.h:994
static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const
virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
QFixed floor() const
Definition: qfixed_p.h:81
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
virtual ~QFontEngineFT()
Q_GUI_EXPORT_INLINE QRgb qRgba(int r, int g, int b, int a)
Definition: qrgb.h:72
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QFixed y
Definition: qfixed_p.h:191
virtual unsigned long allocateServerGlyphSet()
struct FT_FaceRec_ * FT_Face
Definition: qfont.h:50
FcCharSet * charset
#define CEIL(x)
static float pixelSize(const QFontDef &request, int dpi)
Definition: qfont_win.cpp:80
XGlyphInfo GlyphInfo
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
QFixed round() const
Definition: qfixed_p.h:80
static bool init
void unlockFace() const
#define QT_MAX_CACHED_GLYPH_SIZE
const char * name
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
static unsigned int getChar(const QChar *str, int &i, const int len)
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
QChar mirroredChar() const
Returns the mirrored character if this character is a mirrored character; otherwise returns the chara...
Definition: qchar.cpp:1016
static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool=false)
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
bool isEmpty() const
Returns true if the hash contains no items; otherwise returns false.
Definition: qhash.h:297
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const
Q_CORE_EXPORT void qWarning(const char *,...)
virtual QFixed lineThickness() const
static const uint subpixel_filter[3][3]
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
virtual QFixed ascent() const
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
virtual QFontEngine::FaceId faceId() const
void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t)
#define Y_SIZE(face, i)
QtFreetypeData * qt_getFreetypeData()
virtual qreal maxCharWidth() const
bool loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs, const QFixedPoint *positions, GlyphFormat format=Format_Render)
#define QT_CATCH(A)
Definition: qglobal.h:1537
void unlock()
Unlocks the mutex.
Definition: qmutex.cpp:296
qreal pixelSize
Definition: qfont_p.h:90
virtual QFixed xHeight() const
virtual QFixed xHeight() const
virtual qreal minRightBearing() const
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
#define FLOOR(x)
qreal det() const
Returns the matrix&#39;s determinant.
Definition: qtransform.h:233
QFixed x
Definition: qfixed_p.h:190
uchar * bits()
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1946
bool initFromFontEngine(const QFontEngineFT *fontEngine)
HB_Face qHBNewFace(void *font, HB_GetFontTableFunc tableFunc)
Definition: qharfbuzz.cpp:123
#define Q_CHECK_PTR(p)
Definition: qglobal.h:1853
QFontEngine::Properties properties() const
virtual QFixed underlinePosition() const
static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, QFontEngine *fe)
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
QPointF toPointF() const
Definition: qfixed_p.h:194
glyph_t cmapCache[cmapCacheSize]
QHash< GlyphAndSubPixelPosition, Glyph * > glyph_data
#define TRUNC(x)
int fsType() const
void setDefaultHintStyle(HintStyle style)
void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
unsigned short ushort
Definition: qglobal.h:995
QFixed subPixelPositionForX(QFixed x)
void release(const QFontEngine::FaceId &face_id)
virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
int toInt(bool *ok=0, int base=10) const
Returns the byte array converted to an int using base base, which is 10 by default and must be betwee...
virtual QFixed leading() const
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
virtual bool uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
virtual QFixed emSquareSize() const
FT_Face lockFace(Scaling scale=Scaled) const
bool canUploadGlyphsToServer
QFactoryLoader * l
qreal toReal() const
Definition: qfixed_p.h:77
uint stretch
Definition: qfont_p.h:98
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
static uint surrogateToUcs4(ushort high, ushort low)
Converts a UTF16 surrogate pair with the given high and low values to its UCS-4 code point...
Definition: qchar.h:297
virtual int glyphCount() const
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
QMutex * qt_fontdatabase_mutex()
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
quint16 index
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
FT_CharMap symbol_map
QByteArray fontData
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const
static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
QGlyphSet * loadTransformedGlyphSet(const QTransform &matrix)
static const int char_table_entries
virtual QFontEngine * cloneWithSize(qreal pixelSize) const
virtual QFixed descent() const
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
QFreetypeFace * freetype
FT_Face non_locked_face() const
static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
FT_Library qt_getFreetype()
QFontDef fontDef
virtual qreal minLeftBearing() const
QFixedPoint * offsets
void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
The QThreadStorage class provides per-thread data storage.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
qreal qSqrt(qreal v)
Definition: qmath.h:205
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
Glyph * loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format=Format_None, bool fetchMetricsOnly=false) const
#define QT_TRY
Definition: qglobal.h:1536
unsigned int glyph_t
virtual QFixed averageCharWidth() const
QByteArray & remove(int index, int len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
virtual void removeGlyphFromCache(glyph_t glyph)
static uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
qreal m11() const
Returns the horizontal scaling factor.
Definition: qtransform.h:237
QHash< QFontEngine::FaceId, QFreetypeFace * > faces
FT_CharMap unicode_map
static qreal toReal(Register *reg, int type, bool *ok=0)
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
virtual int synthesized() const