1/****************************************************************************
2**
3** Copyright (C) 2016 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
52#ifndef QT_NO_FREETYPE
53
54#include "qfile.h"
55#include "qfileinfo.h"
56#include <qscopedvaluerollback.h>
57#include "qthreadstorage.h"
58#include <qmath.h>
59#include <qendian.h>
60
61#include <ft2build.h>
62#include FT_FREETYPE_H
63#include FT_OUTLINE_H
64#include FT_SYNTHESIS_H
65#include FT_TRUETYPE_TABLES_H
66#include FT_TYPE1_TABLES_H
67#include FT_GLYPH_H
68#include FT_MODULE_H
69#include FT_LCD_FILTER_H
70
71#if defined(FT_CONFIG_OPTIONS_H)
72#include FT_CONFIG_OPTIONS_H
73#endif
74
75#if defined(FT_FONT_FORMATS_H)
76#include FT_FONT_FORMATS_H
77#endif
78
79#ifdef QT_LINUXBASE
80#include FT_ERRORS_H
81#endif
82
83#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
84# define QT_MAX_CACHED_GLYPH_SIZE 64
85#endif
86
87QT_BEGIN_NAMESPACE
88
89#define FLOOR(x) ((x) & -64)
90#define CEIL(x) (((x)+63) & -64)
91#define TRUNC(x) ((x) >> 6)
92#define ROUND(x) (((x)+32) & -64)
93
94static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
95{
96 FT_Face face = (FT_Face)user_data;
97
98 bool result = false;
99 if (FT_IS_SFNT(face)) {
100 FT_ULong len = *length;
101 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
102 *length = len;
103 Q_ASSERT(!result || int(*length) > 0);
104 }
105
106 return result;
107}
108
109static QFontEngineFT::Glyph emptyGlyph = {0, 0, 0, 0, 0, 0, 0, 0};
110
111static const QFontEngine::HintStyle ftInitialDefaultHintStyle =
112#ifdef Q_OS_WIN
113 QFontEngineFT::HintFull;
114#else
115 QFontEngineFT::HintNone;
116#endif
117
118// -------------------------- Freetype support ------------------------------
119
120class QtFreetypeData
121{
122public:
123 QtFreetypeData()
124 : library(0)
125 { }
126 ~QtFreetypeData();
127
128 FT_Library library;
129 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
130};
131
132QtFreetypeData::~QtFreetypeData()
133{
134 for (QHash<QFontEngine::FaceId, QFreetypeFace *>::ConstIterator iter = faces.cbegin(); iter != faces.cend(); ++iter)
135 iter.value()->cleanup();
136 faces.clear();
137 FT_Done_FreeType(library);
138 library = 0;
139}
140
141Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
142
143QtFreetypeData *qt_getFreetypeData()
144{
145 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
146 if (!freetypeData)
147 freetypeData = new QtFreetypeData;
148 if (!freetypeData->library) {
149 FT_Init_FreeType(&freetypeData->library);
150#if defined(FT_FONT_FORMATS_H)
151 // Freetype defaults to disabling stem-darkening on CFF, we re-enable it.
152 FT_Bool no_darkening = false;
153 FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening);
154#endif
155 }
156 return freetypeData;
157}
158
159FT_Library qt_getFreetype()
160{
161 QtFreetypeData *freetypeData = qt_getFreetypeData();
162 Q_ASSERT(freetypeData->library);
163 return freetypeData->library;
164}
165
166int QFreetypeFace::fsType() const
167{
168 int fsType = 0;
169 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
170 if (os2)
171 fsType = os2->fsType;
172 return fsType;
173}
174
175int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
176{
177 if (int error = FT_Load_Glyph(face, glyph, flags))
178 return error;
179
180 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
181 return Err_Invalid_SubTable;
182
183 *nPoints = face->glyph->outline.n_points;
184 if (!(*nPoints))
185 return Err_Ok;
186
187 if (point > *nPoints)
188 return Err_Invalid_SubTable;
189
190 *xpos = QFixed::fromFixed(face->glyph->outline.points[point].x);
191 *ypos = QFixed::fromFixed(face->glyph->outline.points[point].y);
192
193 return Err_Ok;
194}
195
196bool QFreetypeFace::isScalableBitmap() const
197{
198#ifdef FT_HAS_COLOR
199 return !FT_IS_SCALABLE(face) && FT_HAS_COLOR(face);
200#else
201 return false;
202#endif
203}
204
205extern QByteArray qt_fontdata_from_index(int);
206
207/*
208 * One font file can contain more than one font (bold/italic for example)
209 * find the right one and return it.
210 *
211 * Returns the freetype face or 0 in case of an empty file or any other problems
212 * (like not being able to open the file)
213 */
214QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
215 const QByteArray &fontData)
216{
217 if (face_id.filename.isEmpty() && fontData.isEmpty())
218 return 0;
219
220 QtFreetypeData *freetypeData = qt_getFreetypeData();
221
222 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
223 if (freetype) {
224 freetype->ref.ref();
225 } else {
226 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
227 FT_Face face;
228 if (!face_id.filename.isEmpty()) {
229 QString fileName = QFile::decodeName(face_id.filename);
230 if (face_id.filename.startsWith(":qmemoryfonts/")) {
231 // from qfontdatabase.cpp
232 QByteArray idx = face_id.filename;
233 idx.remove(0, 14); // remove ':qmemoryfonts/'
234 bool ok = false;
235 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
236 if (!ok)
237 newFreetype->fontData = QByteArray();
238 } else if (!QFileInfo(fileName).isNativePath()) {
239 QFile file(fileName);
240 if (!file.open(QIODevice::ReadOnly)) {
241 return 0;
242 }
243 newFreetype->fontData = file.readAll();
244 }
245 } else {
246 newFreetype->fontData = fontData;
247 }
248 if (!newFreetype->fontData.isEmpty()) {
249 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
250 return 0;
251 }
252 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
253 return 0;
254 }
255 newFreetype->face = face;
256
257 newFreetype->ref.storeRelaxed(1);
258 newFreetype->xsize = 0;
259 newFreetype->ysize = 0;
260 newFreetype->matrix.xx = 0x10000;
261 newFreetype->matrix.yy = 0x10000;
262 newFreetype->matrix.xy = 0;
263 newFreetype->matrix.yx = 0;
264 newFreetype->unicode_map = 0;
265 newFreetype->symbol_map = 0;
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, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0);
292
293 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
294 QT_TRY {
295 freetypeData->faces.insert(face_id, newFreetype.data());
296 } QT_CATCH(...) {
297 newFreetype.take()->release(face_id);
298 // we could return null in principle instead of throwing
299 QT_RETHROW;
300 }
301 freetype = newFreetype.take();
302 }
303 return freetype;
304}
305
306void QFreetypeFace::cleanup()
307{
308 hbFace.reset();
309 FT_Done_Face(face);
310 face = 0;
311}
312
313void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
314{
315 if (!ref.deref()) {
316 if (face) {
317 QtFreetypeData *freetypeData = qt_getFreetypeData();
318
319 cleanup();
320
321 auto it = freetypeData->faces.constFind(face_id);
322 if (it != freetypeData->faces.constEnd())
323 freetypeData->faces.erase(it);
324
325 if (freetypeData->faces.isEmpty()) {
326 FT_Done_FreeType(freetypeData->library);
327 freetypeData->library = 0;
328 }
329 }
330
331 delete this;
332 }
333}
334
335
336void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor)
337{
338 *ysize = qRound(fontDef.pixelSize * 64);
339 *xsize = *ysize * fontDef.stretch / 100;
340 *scalableBitmapScaleFactor = 1;
341 *outline_drawing = false;
342
343 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
344 int best = 0;
345 if (!isScalableBitmap()) {
346 /*
347 * Bitmap only faces must match exactly, so find the closest
348 * one (height dominant search)
349 */
350 for (int i = 1; i < face->num_fixed_sizes; i++) {
351 if (qAbs(*ysize - face->available_sizes[i].y_ppem) <
352 qAbs(*ysize - face->available_sizes[best].y_ppem) ||
353 (qAbs(*ysize - face->available_sizes[i].y_ppem) ==
354 qAbs(*ysize - face->available_sizes[best].y_ppem) &&
355 qAbs(*xsize - face->available_sizes[i].x_ppem) <
356 qAbs(*xsize - face->available_sizes[best].x_ppem))) {
357 best = i;
358 }
359 }
360 } else {
361 // Select the shortest bitmap strike whose height is larger than the desired height
362 for (int i = 1; i < face->num_fixed_sizes; i++) {
363 if (face->available_sizes[i].y_ppem < *ysize) {
364 if (face->available_sizes[i].y_ppem > face->available_sizes[best].y_ppem)
365 best = i;
366 } else if (face->available_sizes[best].y_ppem < *ysize) {
367 best = i;
368 } else if (face->available_sizes[i].y_ppem < face->available_sizes[best].y_ppem) {
369 best = i;
370 }
371 }
372 }
373
374 // According to freetype documentation we must use FT_Select_Size
375 // to make sure we can select the desired bitmap strike index
376 if (FT_Select_Size(face, best) == 0) {
377 if (isScalableBitmap())
378 *scalableBitmapScaleFactor = QFixed::fromReal((qreal)fontDef.pixelSize / face->available_sizes[best].height);
379 *xsize = face->available_sizes[best].x_ppem;
380 *ysize = face->available_sizes[best].y_ppem;
381 } else {
382 *xsize = *ysize = 0;
383 }
384 } else {
385 *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
386 }
387}
388
389QFontEngine::Properties QFreetypeFace::properties() const
390{
391 QFontEngine::Properties p;
392 p.postscriptName = FT_Get_Postscript_Name(face);
393 PS_FontInfoRec font_info;
394 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
395 p.copyright = font_info.notice;
396 if (FT_IS_SCALABLE(face)) {
397 p.ascent = face->ascender;
398 p.descent = -face->descender;
399 p.leading = face->height - face->ascender + face->descender;
400 p.emSquare = face->units_per_EM;
401 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
402 face->bbox.xMax - face->bbox.xMin,
403 face->bbox.yMax - face->bbox.yMin);
404 } else {
405 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
406 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
407 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
408 p.emSquare = face->size->metrics.y_ppem;
409// p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
410 p.boundingBox = QRectF(0, -p.ascent.toReal(),
411 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
412 }
413 p.italicAngle = 0;
414 p.capHeight = p.ascent;
415 p.lineWidth = face->underline_thickness;
416
417 return p;
418}
419
420bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
421{
422 return ft_getSfntTable(face, tag, buffer, length);
423}
424
425/* Some fonts (such as MingLiu rely on hinting to scale different
426 components to their correct sizes. While this is really broken (it
427 should be done in the component glyph itself, not the hinter) we
428 will have to live with it.
429
430 This means we can not use FT_LOAD_NO_HINTING to get the glyph
431 outline. All we can do is to load the unscaled glyph and scale it
432 down manually when required.
433*/
434static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
435{
436 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
437 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
438 FT_Vector *p = g->outline.points;
439 const FT_Vector *e = p + g->outline.n_points;
440 while (p < e) {
441 p->x = FT_MulFix(p->x, x_scale);
442 p->y = FT_MulFix(p->y, y_scale);
443 ++p;
444 }
445}
446
447#define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO // qDebug
448void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
449{
450 const qreal factor = 1/64.;
451 scaleOutline(face, g, x_scale, y_scale);
452
453 QPointF cp = point.toPointF();
454
455 // convert the outline to a painter path
456 int i = 0;
457 for (int j = 0; j < g->outline.n_contours; ++j) {
458 int last_point = g->outline.contours[j];
459 GLYPH2PATH_DEBUG() << "contour:" << i << "to" << last_point;
460 QPointF start = QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
461 if (!(g->outline.tags[i] & 1)) { // start point is not on curve:
462 if (!(g->outline.tags[last_point] & 1)) { // end point is not on curve:
463 GLYPH2PATH_DEBUG() << " start and end point are not on curve";
464 start = (QPointF(g->outline.points[last_point].x*factor,
465 -g->outline.points[last_point].y*factor) + start) / 2.0;
466 } else {
467 GLYPH2PATH_DEBUG() << " end point is on curve, start is not";
468 start = QPointF(g->outline.points[last_point].x*factor,
469 -g->outline.points[last_point].y*factor);
470 }
471 --i; // to use original start point as control point below
472 }
473 start += cp;
474 GLYPH2PATH_DEBUG() << " start at" << start;
475
476 path->moveTo(start);
477 QPointF c[4];
478 c[0] = start;
479 int n = 1;
480 while (i < last_point) {
481 ++i;
482 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
483 GLYPH2PATH_DEBUG() << " " << i << c[n] << "tag =" << (int)g->outline.tags[i]
484 << ": on curve =" << (bool)(g->outline.tags[i] & 1);
485 ++n;
486 switch (g->outline.tags[i] & 3) {
487 case 2:
488 // cubic bezier element
489 if (n < 4)
490 continue;
491 c[3] = (c[3] + c[2])/2;
492 --i;
493 break;
494 case 0:
495 // quadratic bezier element
496 if (n < 3)
497 continue;
498 c[3] = (c[1] + c[2])/2;
499 c[2] = (2*c[1] + c[3])/3;
500 c[1] = (2*c[1] + c[0])/3;
501 --i;
502 break;
503 case 1:
504 case 3:
505 if (n == 2) {
506 GLYPH2PATH_DEBUG() << " lineTo" << c[1];
507 path->lineTo(c[1]);
508 c[0] = c[1];
509 n = 1;
510 continue;
511 } else if (n == 3) {
512 c[3] = c[2];
513 c[2] = (2*c[1] + c[3])/3;
514 c[1] = (2*c[1] + c[0])/3;
515 }
516 break;
517 }
518 GLYPH2PATH_DEBUG() << " cubicTo" << c[1] << c[2] << c[3];
519 path->cubicTo(c[1], c[2], c[3]);
520 c[0] = c[3];
521 n = 1;
522 }
523
524 if (n == 1) {
525 GLYPH2PATH_DEBUG() << " closeSubpath";
526 path->closeSubpath();
527 } else {
528 c[3] = start;
529 if (n == 2) {
530 c[2] = (2*c[1] + c[3])/3;
531 c[1] = (2*c[1] + c[0])/3;
532 }
533 GLYPH2PATH_DEBUG() << " close cubicTo" << c[1] << c[2] << c[3];
534 path->cubicTo(c[1], c[2], c[3]);
535 }
536 ++i;
537 }
538}
539
540extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
541
542void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path)
543{
544 if (slot->format != FT_GLYPH_FORMAT_BITMAP
545 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
546 return;
547
548 QPointF cp = point.toPointF();
549 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
550 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
551}
552
553QFontEngineFT::Glyph::~Glyph()
554{
555 delete [] data;
556}
557
558static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
559{
560 const int offs = bgr ? -1 : 1;
561 const int w = width * 3;
562 while (height--) {
563 uint *dd = dst;
564 for (int x = 0; x < w; x += 3) {
565 uchar red = src[x + 1 - offs];
566 uchar green = src[x + 1];
567 uchar blue = src[x + 1 + offs];
568 *dd++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue;
569 }
570 dst += width;
571 src += src_pitch;
572 }
573}
574
575static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
576{
577 const int offs = bgr ? -src_pitch : src_pitch;
578 while (height--) {
579 for (int x = 0; x < width; x++) {
580 uchar red = src[x + src_pitch - offs];
581 uchar green = src[x + src_pitch];
582 uchar blue = src[x + src_pitch + offs];
583 *dst++ = (0XFFU << 24) | (red << 16) | (green << 8) | blue;
584 }
585 src += 3*src_pitch;
586 }
587}
588
589static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint()
590{
591 static int type = -1;
592 if (type == -1) {
593 if (QScreen *screen = QGuiApplication::primaryScreen())
594 type = screen->handle()->subpixelAntialiasingTypeHint();
595 }
596 return static_cast<QFontEngine::SubpixelAntialiasingType>(type);
597}
598
599QFontEngineFT *QFontEngineFT::create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData)
600{
601 QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef));
602
603 QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
604 const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
605
606 if (antialias) {
607 QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
608 if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
609 format = QFontEngineFT::Format_A8;
610 engine->subpixelType = QFontEngine::Subpixel_None;
611 } else {
612 format = QFontEngineFT::Format_A32;
613 engine->subpixelType = subpixelType;
614 }
615 }
616
617 if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
618 qWarning("QFontEngineFT: Failed to create FreeType font engine");
619 return nullptr;
620 }
621
622 engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
623 return engine.take();
624}
625
626namespace {
627 class QFontEngineFTRawData: public QFontEngineFT
628 {
629 public:
630 QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef)
631 {
632 }
633
634 void updateFamilyNameAndStyle()
635 {
636 fontDef.family = QString::fromLatin1(freetype->face->family_name);
637
638 if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
639 fontDef.style = QFont::StyleItalic;
640
641 if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
642 fontDef.weight = QFont::Bold;
643 }
644
645 bool initFromData(const QByteArray &fontData)
646 {
647 FaceId faceId;
648 faceId.filename = "";
649 faceId.index = 0;
650 faceId.uuid = QUuid::createUuid().toByteArray();
651
652 return init(faceId, true, Format_None, fontData);
653 }
654 };
655}
656
657QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
658{
659 QFontDef fontDef;
660 fontDef.pixelSize = pixelSize;
661 fontDef.stretch = QFont::Unstretched;
662 fontDef.hintingPreference = hintingPreference;
663
664 QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
665 if (!fe->initFromData(fontData)) {
666 delete fe;
667 return 0;
668 }
669
670 fe->updateFamilyNameAndStyle();
671 fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
672
673 return fe;
674}
675
676QFontEngineFT::QFontEngineFT(const QFontDef &fd)
677 : QFontEngine(Freetype)
678{
679 fontDef = fd;
680 matrix.xx = 0x10000;
681 matrix.yy = 0x10000;
682 matrix.xy = 0;
683 matrix.yx = 0;
684 cache_cost = 100 * 1024;
685 kerning_pairs_loaded = false;
686 transform = false;
687 embolden = false;
688 obliquen = false;
689 antialias = true;
690 freetype = 0;
691 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
692 default_hint_style = ftInitialDefaultHintStyle;
693 subpixelType = Subpixel_None;
694 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
695 defaultFormat = Format_None;
696 embeddedbitmap = false;
697 const QByteArray env = qgetenv("QT_NO_FT_CACHE");
698 cacheEnabled = env.isEmpty() || env.toInt() == 0;
699 m_subPixelPositionCount = 4;
700 forceAutoHint = false;
701 stemDarkeningDriver = false;
702}
703
704QFontEngineFT::~QFontEngineFT()
705{
706 if (freetype)
707 freetype->release(face_id);
708}
709
710bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
711 const QByteArray &fontData)
712{
713 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
714}
715
716static void dont_delete(void*) {}
717
718bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
719 QFreetypeFace *freetypeFace)
720{
721 freetype = freetypeFace;
722 if (!freetype) {
723 xsize = 0;
724 ysize = 0;
725 return false;
726 }
727 defaultFormat = format;
728 this->antialias = antialias;
729
730 if (!antialias)
731 glyphFormat = QFontEngine::Format_Mono;
732 else
733 glyphFormat = defaultFormat;
734
735 face_id = faceId;
736
737 symbol = freetype->symbol_map != 0;
738 PS_FontInfoRec psrec;
739 // don't assume that type1 fonts are symbol fonts by default
740 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
741 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
742 }
743
744 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing, &scalableBitmapScaleFactor);
745
746 FT_Face face = lockFace();
747
748 if (FT_IS_SCALABLE(face)) {
749 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
750 if (fake_oblique)
751 obliquen = true;
752 FT_Set_Transform(face, &matrix, 0);
753 freetype->matrix = matrix;
754 // fake bold
755 if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) {
756 if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
757 if (os2->usWeightClass < 750)
758 embolden = true;
759 }
760 }
761 // underline metrics
762 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
763 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
764 } else {
765 // ad hoc algorithm
766 int score = fontDef.weight * fontDef.pixelSize;
767 line_thickness = score / 700;
768 // looks better with thicker line for small pointsizes
769 if (line_thickness < 2 && score >= 1050)
770 line_thickness = 2;
771 underline_position = ((line_thickness * 2) + 3) / 6;
772
773 if (isScalableBitmap()) {
774 glyphFormat = defaultFormat = GlyphFormat::Format_ARGB;
775 cacheEnabled = false;
776 }
777 }
778 if (line_thickness < 1)
779 line_thickness = 1;
780
781 metrics = face->size->metrics;
782
783 /*
784 TrueType fonts with embedded bitmaps may have a bitmap font specific
785 ascent/descent in the EBLC table. There is no direct public API
786 to extract those values. The only way we've found is to trick freetype
787 into thinking that it's not a scalable font in FT_SelectSize so that
788 the metrics are retrieved from the bitmap strikes.
789 */
790 if (FT_IS_SCALABLE(face)) {
791 for (int i = 0; i < face->num_fixed_sizes; ++i) {
792 if (xsize == face->available_sizes[i].x_ppem && ysize == face->available_sizes[i].y_ppem) {
793 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
794
795 FT_Select_Size(face, i);
796 if (face->size->metrics.ascender + face->size->metrics.descender > 0) {
797 FT_Pos leading = metrics.height - metrics.ascender + metrics.descender;
798 metrics.ascender = face->size->metrics.ascender;
799 metrics.descender = face->size->metrics.descender;
800 if (metrics.descender > 0
801 && QString::fromUtf8(face->family_name) == QLatin1String("Courier New")) {
802 metrics.descender *= -1;
803 }
804 metrics.height = metrics.ascender - metrics.descender + leading;
805 }
806 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
807
808 face->face_flags |= FT_FACE_FLAG_SCALABLE;
809 break;
810 }
811 }
812 }
813#if defined(FT_FONT_FORMATS_H)
814 const char *fmt = FT_Get_Font_Format(face);
815 if (fmt && qstrncmp(fmt, "CFF", 4) == 0) {
816 FT_Bool no_stem_darkening = true;
817 FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening);
818 if (err == FT_Err_Ok)
819 stemDarkeningDriver = !no_stem_darkening;
820 else
821 stemDarkeningDriver = false;
822 }
823#endif
824
825 fontDef.styleName = QString::fromUtf8(face->style_name);
826
827 if (!freetype->hbFace) {
828 faceData.user_data = face;
829 faceData.get_font_table = ft_getSfntTable;
830 (void)harfbuzzFace(); // populates face_
831 freetype->hbFace = std::move(face_);
832 } else {
833 Q_ASSERT(!face_);
834 }
835 // we share the HB face in QFreeTypeFace, so do not let ~QFontEngine() destroy it
836 face_ = Holder(freetype->hbFace.get(), dont_delete);
837
838 unlockFace();
839
840 fsType = freetype->fsType();
841 return true;
842}
843
844void QFontEngineFT::setQtDefaultHintStyle(QFont::HintingPreference hintingPreference)
845{
846 switch (hintingPreference) {
847 case QFont::PreferNoHinting:
848 setDefaultHintStyle(HintNone);
849 break;
850 case QFont::PreferFullHinting:
851 setDefaultHintStyle(HintFull);
852 break;
853 case QFont::PreferVerticalHinting:
854 setDefaultHintStyle(HintLight);
855 break;
856 case QFont::PreferDefaultHinting:
857 setDefaultHintStyle(ftInitialDefaultHintStyle);
858 break;
859 }
860}
861
862void QFontEngineFT::setDefaultHintStyle(HintStyle style)
863{
864 default_hint_style = style;
865}
866
867bool QFontEngineFT::expectsGammaCorrectedBlending() const
868{
869 return stemDarkeningDriver;
870}
871
872int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
873 bool &hsubpixel, int &vfactor) const
874{
875 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
876 int load_target = default_hint_style == HintLight
877 ? FT_LOAD_TARGET_LIGHT
878 : FT_LOAD_TARGET_NORMAL;
879
880 if (format == Format_Mono) {
881 load_target = FT_LOAD_TARGET_MONO;
882 } else if (format == Format_A32) {
883 if (subpixelType == Subpixel_RGB || subpixelType == Subpixel_BGR)
884 hsubpixel = true;
885 else if (subpixelType == Subpixel_VRGB || subpixelType == Subpixel_VBGR)
886 vfactor = 3;
887 } else if (format == Format_ARGB) {
888#ifdef FT_LOAD_COLOR
889 load_flags |= FT_LOAD_COLOR;
890#endif
891 }
892
893 if (set && set->outline_drawing)
894 load_flags |= FT_LOAD_NO_BITMAP;
895
896 if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
897 load_flags |= FT_LOAD_NO_HINTING;
898 else
899 load_flags |= load_target;
900
901 if (forceAutoHint)
902 load_flags |= FT_LOAD_FORCE_AUTOHINT;
903
904 return load_flags;
905}
906
907static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info)
908{
909 // false if exceeds QFontEngineFT::Glyph metrics
910 return info.width > 0xFF || info.height > 0xFF;
911}
912
913static inline void transformBoundingBox(int *left, int *top, int *right, int *bottom, FT_Matrix *matrix)
914{
915 int l, r, t, b;
916 FT_Vector vector;
917 vector.x = *left;
918 vector.y = *top;
919 FT_Vector_Transform(&vector, matrix);
920 l = r = vector.x;
921 t = b = vector.y;
922 vector.x = *right;
923 vector.y = *top;
924 FT_Vector_Transform(&vector, matrix);
925 if (l > vector.x) l = vector.x;
926 if (r < vector.x) r = vector.x;
927 if (t < vector.y) t = vector.y;
928 if (b > vector.y) b = vector.y;
929 vector.x = *right;
930 vector.y = *bottom;
931 FT_Vector_Transform(&vector, matrix);
932 if (l > vector.x) l = vector.x;
933 if (r < vector.x) r = vector.x;
934 if (t < vector.y) t = vector.y;
935 if (b > vector.y) b = vector.y;
936 vector.x = *left;
937 vector.y = *bottom;
938 FT_Vector_Transform(&vector, matrix);
939 if (l > vector.x) l = vector.x;
940 if (r < vector.x) r = vector.x;
941 if (t < vector.y) t = vector.y;
942 if (b > vector.y) b = vector.y;
943 *left = l;
944 *right = r;
945 *top = t;
946 *bottom = b;
947}
948
949QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
950 QFixed subPixelPosition,
951 GlyphFormat format,
952 bool fetchMetricsOnly,
953 bool disableOutlineDrawing) const
954{
955// Q_ASSERT(freetype->lock == 1);
956
957 if (format == Format_None)
958 format = defaultFormat != Format_None ? defaultFormat : Format_Mono;
959 Q_ASSERT(format != Format_None);
960
961 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
962 if (g && g->format == format && (fetchMetricsOnly || g->data))
963 return g;
964
965 if (!g && set && set->isGlyphMissing(glyph))
966 return &emptyGlyph;
967
968
969 FT_Face face = freetype->face;
970
971 FT_Matrix matrix = freetype->matrix;
972
973 FT_Vector v;
974 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.value());
975 v.y = 0;
976 FT_Set_Transform(face, &matrix, &v);
977
978 bool hsubpixel = false;
979 int vfactor = 1;
980 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
981
982 bool transform = matrix.xx != 0x10000
983 || matrix.yy != 0x10000
984 || matrix.xy != 0
985 || matrix.yx != 0;
986
987 if (transform || obliquen || (format != Format_Mono && !isScalableBitmap()))
988 load_flags |= FT_LOAD_NO_BITMAP;
989
990 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
991 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
992 load_flags &= ~FT_LOAD_NO_BITMAP;
993 err = FT_Load_Glyph(face, glyph, load_flags);
994 }
995 if (err == FT_Err_Too_Few_Arguments) {
996 // this is an error in the bytecode interpreter, just try to run without it
997 load_flags |= FT_LOAD_FORCE_AUTOHINT;
998 err = FT_Load_Glyph(face, glyph, load_flags);
999 } else if (err == FT_Err_Execution_Too_Long) {
1000 // This is an error in the bytecode, probably a web font made by someone who
1001 // didn't test bytecode hinting at all so disable for it for all glyphs.
1002 qWarning("load glyph failed due to broken hinting bytecode in font, switching to auto hinting");
1003 default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
1004 load_flags |= FT_LOAD_FORCE_AUTOHINT;
1005 err = FT_Load_Glyph(face, glyph, load_flags);
1006 }
1007 if (err != FT_Err_Ok) {
1008 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1009 if (set)
1010 set->setGlyphMissing(glyph);
1011 return &emptyGlyph;
1012 }
1013
1014 FT_GlyphSlot slot = face->glyph;
1015
1016 if (embolden)
1017 FT_GlyphSlot_Embolden(slot);
1018 if (obliquen) {
1019 FT_GlyphSlot_Oblique(slot);
1020
1021 // While Embolden alters the metrics of the slot, oblique does not, so we need
1022 // to fix this ourselves.
1023 transform = true;
1024 FT_Matrix m;
1025 m.xx = 0x10000;
1026 m.yx = 0x0;
1027 m.xy = 0x6000;
1028 m.yy = 0x10000;
1029
1030 FT_Matrix_Multiply(&m, &matrix);
1031 }
1032
1033 GlyphInfo info;
1034 info.linearAdvance = slot->linearHoriAdvance >> 10;
1035 info.xOff = TRUNC(ROUND(slot->advance.x));
1036 info.yOff = 0;
1037
1038 if ((set && set->outline_drawing && !disableOutlineDrawing) || fetchMetricsOnly) {
1039 int left = slot->metrics.horiBearingX;
1040 int right = slot->metrics.horiBearingX + slot->metrics.width;
1041 int top = slot->metrics.horiBearingY;
1042 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
1043
1044 if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP)
1045 transformBoundingBox(&left, &top, &right, &bottom, &matrix);
1046
1047 left = FLOOR(left);
1048 right = CEIL(right);
1049 bottom = FLOOR(bottom);
1050 top = CEIL(top);
1051
1052 info.x = TRUNC(left);
1053 info.y = TRUNC(top);
1054 info.width = TRUNC(right - left);
1055 info.height = TRUNC(top - bottom);
1056
1057 // If any of the metrics are too large to fit, don't cache them
1058 if (areMetricsTooLarge(info))
1059 return 0;
1060
1061 g = new Glyph;
1062 g->data = 0;
1063 g->linearAdvance = info.linearAdvance;
1064 g->width = info.width;
1065 g->height = info.height;
1066 g->x = info.x;
1067 g->y = info.y;
1068 g->advance = info.xOff;
1069 g->format = format;
1070
1071 if (set)
1072 set->setGlyph(glyph, subPixelPosition, g);
1073
1074 return g;
1075 }
1076
1077 int glyph_buffer_size = 0;
1078 QScopedArrayPointer<uchar> glyph_buffer;
1079 FT_Render_Mode renderMode = (default_hint_style == HintLight) ? FT_RENDER_MODE_LIGHT : FT_RENDER_MODE_NORMAL;
1080 switch (format) {
1081 case Format_Mono:
1082 renderMode = FT_RENDER_MODE_MONO;
1083 break;
1084 case Format_A32:
1085 Q_ASSERT(hsubpixel || vfactor != 1);
1086 renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
1087 break;
1088 case Format_A8:
1089 case Format_ARGB:
1090 break;
1091 default:
1092 Q_UNREACHABLE();
1093 }
1094 FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType);
1095
1096 err = FT_Render_Glyph(slot, renderMode);
1097 if (err != FT_Err_Ok)
1098 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1099
1100 FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE);
1101
1102 info.height = slot->bitmap.rows;
1103 info.width = slot->bitmap.width;
1104 info.x = slot->bitmap_left;
1105 info.y = slot->bitmap_top;
1106 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
1107 info.width = info.width / 3;
1108 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
1109 info.height = info.height / vfactor;
1110
1111 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1112 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1113
1114 glyph_buffer_size = info.height * pitch;
1115 glyph_buffer.reset(new uchar[glyph_buffer_size]);
1116
1117 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
1118 Q_ASSERT(format == Format_Mono);
1119 uchar *src = slot->bitmap.buffer;
1120 uchar *dst = glyph_buffer.data();
1121 int h = slot->bitmap.rows;
1122
1123 int bytes = ((info.width + 7) & ~7) >> 3;
1124 while (h--) {
1125 memcpy (dst, src, bytes);
1126 dst += pitch;
1127 src += slot->bitmap.pitch;
1128 }
1129 } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) {
1130 Q_ASSERT(format == Format_ARGB);
1131 uchar *src = slot->bitmap.buffer;
1132 uchar *dst = glyph_buffer.data();
1133 int h = slot->bitmap.rows;
1134 while (h--) {
1135#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1136 const quint32 *srcPixel = (const quint32 *)src;
1137 quint32 *dstPixel = (quint32 *)dst;
1138 for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) {
1139 const quint32 pixel = *srcPixel;
1140 *dstPixel = qbswap(pixel);
1141 }
1142#else
1143 memcpy(dst, src, slot->bitmap.width * 4);
1144#endif
1145 dst += slot->bitmap.pitch;
1146 src += slot->bitmap.pitch;
1147 }
1148 info.linearAdvance = info.xOff = slot->bitmap.width;
1149 } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
1150 Q_ASSERT(format == Format_A8);
1151 uchar *src = slot->bitmap.buffer;
1152 uchar *dst = glyph_buffer.data();
1153 int h = slot->bitmap.rows;
1154 int bytes = info.width;
1155 while (h--) {
1156 memcpy (dst, src, bytes);
1157 dst += pitch;
1158 src += slot->bitmap.pitch;
1159 }
1160 } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
1161 Q_ASSERT(format == Format_A32);
1162 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB);
1163 } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
1164 Q_ASSERT(format == Format_A32);
1165 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB);
1166 } else {
1167 qWarning("QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode);
1168 return 0;
1169 }
1170
1171 if (!g) {
1172 g = new Glyph;
1173 g->data = 0;
1174 }
1175
1176 g->linearAdvance = info.linearAdvance;
1177 g->width = info.width;
1178 g->height = info.height;
1179 g->x = info.x;
1180 g->y = info.y;
1181 g->advance = info.xOff;
1182 g->format = format;
1183 delete [] g->data;
1184 g->data = glyph_buffer.take();
1185
1186 if (set)
1187 set->setGlyph(glyph, subPixelPosition, g);
1188
1189 return g;
1190}
1191
1192QFontEngine::FaceId QFontEngineFT::faceId() const
1193{
1194 return face_id;
1195}
1196
1197QFontEngine::Properties QFontEngineFT::properties() const
1198{
1199 Properties p = freetype->properties();
1200 if (p.postscriptName.isEmpty()) {
1201 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1202 }
1203
1204 return freetype->properties();
1205}
1206
1207QFixed QFontEngineFT::emSquareSize() const
1208{
1209 if (FT_IS_SCALABLE(freetype->face))
1210 return freetype->face->units_per_EM;
1211 else
1212 return freetype->face->size->metrics.y_ppem;
1213}
1214
1215bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1216{
1217 return ft_getSfntTable(freetype->face, tag, buffer, length);
1218}
1219
1220int QFontEngineFT::synthesized() const
1221{
1222 int s = 0;
1223 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1224 s = SynthesizedItalic;
1225 if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1226 s |= SynthesizedBold;
1227 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1228 s |= SynthesizedStretch;
1229 return s;
1230}
1231
1232QFixed QFontEngineFT::ascent() const
1233{
1234 QFixed v = QFixed::fromFixed(metrics.ascender);
1235 if (scalableBitmapScaleFactor != 1)
1236 v *= scalableBitmapScaleFactor;
1237 return v;
1238}
1239
1240QFixed QFontEngineFT::capHeight() const
1241{
1242 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1243 if (os2 && os2->version >= 2) {
1244 lockFace();
1245 QFixed answer = QFixed::fromFixed(FT_MulFix(os2->sCapHeight, freetype->face->size->metrics.y_scale));
1246 unlockFace();
1247 return answer;
1248 }
1249 return calculatedCapHeight();
1250}
1251
1252QFixed QFontEngineFT::descent() const
1253{
1254 QFixed v = QFixed::fromFixed(-metrics.descender);
1255 if (scalableBitmapScaleFactor != 1)
1256 v *= scalableBitmapScaleFactor;
1257 return v;
1258}
1259
1260QFixed QFontEngineFT::leading() const
1261{
1262 QFixed v = QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1263 if (scalableBitmapScaleFactor != 1)
1264 v *= scalableBitmapScaleFactor;
1265 return v;
1266}
1267
1268QFixed QFontEngineFT::xHeight() const
1269{
1270 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1271 if (os2 && os2->sxHeight) {
1272 lockFace();
1273 QFixed answer = QFixed(os2->sxHeight * freetype->face->size->metrics.y_ppem) / emSquareSize();
1274 unlockFace();
1275 return answer;
1276 }
1277
1278 return QFontEngine::xHeight();
1279}
1280
1281QFixed QFontEngineFT::averageCharWidth() const
1282{
1283 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1284 if (os2 && os2->xAvgCharWidth) {
1285 lockFace();
1286 QFixed answer = QFixed(os2->xAvgCharWidth * freetype->face->size->metrics.x_ppem) / emSquareSize();
1287 unlockFace();
1288 return answer;
1289 }
1290
1291 return QFontEngine::averageCharWidth();
1292}
1293
1294qreal QFontEngineFT::maxCharWidth() const
1295{
1296 QFixed max_advance = QFixed::fromFixed(metrics.max_advance);
1297 if (scalableBitmapScaleFactor != 1)
1298 max_advance *= scalableBitmapScaleFactor;
1299 return max_advance.toReal();
1300}
1301
1302QFixed QFontEngineFT::lineThickness() const
1303{
1304 return line_thickness;
1305}
1306
1307QFixed QFontEngineFT::underlinePosition() const
1308{
1309 return underline_position;
1310}
1311
1312void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
1313{
1314 if (!kerning_pairs_loaded) {
1315 kerning_pairs_loaded = true;
1316 lockFace();
1317 if (freetype->face->size->metrics.x_ppem != 0) {
1318 QFixed scalingFactor = emSquareSize() / QFixed(freetype->face->size->metrics.x_ppem);
1319 unlockFace();
1320 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1321 } else {
1322 unlockFace();
1323 }
1324 }
1325
1326 if (shouldUseDesignMetrics(flags) && !(fontDef.styleStrategy & QFont::ForceIntegerMetrics))
1327 flags |= DesignMetrics;
1328 else
1329 flags &= ~DesignMetrics;
1330
1331 QFontEngine::doKerning(g, flags);
1332}
1333
1334static inline FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1335{
1336 FT_Matrix m;
1337
1338 m.xx = FT_Fixed(matrix.m11() * 65536);
1339 m.xy = FT_Fixed(-matrix.m21() * 65536);
1340 m.yx = FT_Fixed(-matrix.m12() * 65536);
1341 m.yy = FT_Fixed(matrix.m22() * 65536);
1342
1343 return m;
1344}
1345
1346QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix)
1347{
1348 if (matrix.type() > QTransform::TxShear || !cacheEnabled)
1349 return 0;
1350
1351 // FT_Set_Transform only supports scalable fonts
1352 if (!FT_IS_SCALABLE(freetype->face))
1353 return matrix.type() <= QTransform::TxTranslate ? &defaultGlyphSet : nullptr;
1354
1355 FT_Matrix m = QTransformToFTMatrix(matrix);
1356
1357 QGlyphSet *gs = 0;
1358
1359 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1360 const QGlyphSet &g = transformedGlyphSets.at(i);
1361 if (g.transformationMatrix.xx == m.xx
1362 && g.transformationMatrix.xy == m.xy
1363 && g.transformationMatrix.yx == m.yx
1364 && g.transformationMatrix.yy == m.yy) {
1365
1366 // found a match, move it to the front
1367 transformedGlyphSets.move(i, 0);
1368 gs = &transformedGlyphSets[0];
1369 break;
1370 }
1371 }
1372
1373 if (!gs) {
1374 // don't cache more than 10 transformations
1375 if (transformedGlyphSets.count() >= 10) {
1376 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1377 } else {
1378 transformedGlyphSets.prepend(QGlyphSet());
1379 }
1380 gs = &transformedGlyphSets[0];
1381 gs->clear();
1382 gs->transformationMatrix = m;
1383 gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
1384 }
1385 Q_ASSERT(gs != 0);
1386
1387 return gs;
1388}
1389
1390void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1391{
1392 FT_Face face = lockFace(Unscaled);
1393 FT_Set_Transform(face, 0, 0);
1394 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1395
1396 int left = face->glyph->metrics.horiBearingX;
1397 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1398 int top = face->glyph->metrics.horiBearingY;
1399 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1400
1401 QFixedPoint p;
1402 p.x = 0;
1403 p.y = 0;
1404
1405 metrics->width = QFixed::fromFixed(right-left);
1406 metrics->height = QFixed::fromFixed(top-bottom);
1407 metrics->x = QFixed::fromFixed(left);
1408 metrics->y = QFixed::fromFixed(-top);
1409 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1410
1411 if (!FT_IS_SCALABLE(freetype->face))
1412 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1413 else
1414 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1415
1416 FT_Set_Transform(face, &freetype->matrix, 0);
1417 unlockFace();
1418}
1419
1420bool QFontEngineFT::supportsTransformation(const QTransform &transform) const
1421{
1422 return transform.type() <= QTransform::TxRotate;
1423}
1424
1425void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1426{
1427 if (!glyphs.numGlyphs)
1428 return;
1429
1430 if (FT_IS_SCALABLE(freetype->face)) {
1431 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1432 } else {
1433 QVarLengthArray<QFixedPoint> positions;
1434 QVarLengthArray<glyph_t> positioned_glyphs;
1435 QTransform matrix;
1436 matrix.translate(x, y);
1437 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1438
1439 FT_Face face = lockFace(Unscaled);
1440 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1441 FT_UInt glyph = positioned_glyphs[gl];
1442 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1443 QFreetypeFace::addBitmapToPath(face->glyph, positions[gl], path);
1444 }
1445 unlockFace();
1446 }
1447}
1448
1449void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1450 QPainterPath *path, QTextItem::RenderFlags)
1451{
1452 FT_Face face = lockFace(Unscaled);
1453
1454 for (int gl = 0; gl < numGlyphs; gl++) {
1455 FT_UInt glyph = glyphs[gl];
1456
1457 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1458
1459 FT_GlyphSlot g = face->glyph;
1460 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1461 continue;
1462 if (embolden)
1463 FT_GlyphSlot_Embolden(g);
1464 if (obliquen)
1465 FT_GlyphSlot_Oblique(g);
1466 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1467 }
1468 unlockFace();
1469}
1470
1471glyph_t QFontEngineFT::glyphIndex(uint ucs4) const
1472{
1473 glyph_t glyph = ucs4 < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[ucs4] : 0;
1474 if (glyph == 0) {
1475 FT_Face face = freetype->face;
1476 glyph = FT_Get_Char_Index(face, ucs4);
1477 if (glyph == 0) {
1478 // Certain fonts don't have no-break space and tab,
1479 // while we usually want to render them as space
1480 if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) {
1481 glyph = FT_Get_Char_Index(face, QChar::Space);
1482 } else if (freetype->symbol_map) {
1483 // Symbol fonts can have more than one CMAPs, FreeType should take the
1484 // correct one for us by default, so we always try FT_Get_Char_Index
1485 // first. If it didn't work (returns 0), we will explicitly set the
1486 // CMAP to symbol font one and try again. symbol_map is not always the
1487 // correct one because in certain fonts like Wingdings symbol_map only
1488 // contains PUA codepoints instead of the common ones.
1489 FT_Set_Charmap(face, freetype->symbol_map);
1490 glyph = FT_Get_Char_Index(face, ucs4);
1491 FT_Set_Charmap(face, freetype->unicode_map);
1492 }
1493 }
1494 if (ucs4 < QFreetypeFace::cmapCacheSize)
1495 freetype->cmapCache[ucs4] = glyph;
1496 }
1497
1498 return glyph;
1499}
1500
1501bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1502 QFontEngine::ShaperFlags flags) const
1503{
1504 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
1505 if (*nglyphs < len) {
1506 *nglyphs = len;
1507 return false;
1508 }
1509
1510 int glyph_pos = 0;
1511 if (freetype->symbol_map) {
1512 FT_Face face = freetype->face;
1513 QStringIterator it(str, str + len);
1514 while (it.hasNext()) {
1515 uint uc = it.next();
1516 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1517 if ( !glyphs->glyphs[glyph_pos] ) {
1518 // Symbol fonts can have more than one CMAPs, FreeType should take the
1519 // correct one for us by default, so we always try FT_Get_Char_Index
1520 // first. If it didn't work (returns 0), we will explicitly set the
1521 // CMAP to symbol font one and try again. symbol_map is not always the
1522 // correct one because in certain fonts like Wingdings symbol_map only
1523 // contains PUA codepoints instead of the common ones.
1524 glyph_t glyph = FT_Get_Char_Index(face, uc);
1525 // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1526 // while we usually want to render them as space
1527 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1528 uc = 0x20;
1529 glyph = FT_Get_Char_Index(face, uc);
1530 }
1531 if (!glyph) {
1532 FT_Set_Charmap(face, freetype->symbol_map);
1533 glyph = FT_Get_Char_Index(face, uc);
1534 FT_Set_Charmap(face, freetype->unicode_map);
1535 }
1536 glyphs->glyphs[glyph_pos] = glyph;
1537 if (uc < QFreetypeFace::cmapCacheSize)
1538 freetype->cmapCache[uc] = glyph;
1539 }
1540 ++glyph_pos;
1541 }
1542 } else {
1543 FT_Face face = freetype->face;
1544 QStringIterator it(str, str + len);
1545 while (it.hasNext()) {
1546 uint uc = it.next();
1547 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1548 if (!glyphs->glyphs[glyph_pos]) {
1549 {
1550 redo:
1551 glyph_t glyph = FT_Get_Char_Index(face, uc);
1552 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1553 uc = 0x20;
1554 goto redo;
1555 }
1556 glyphs->glyphs[glyph_pos] = glyph;
1557 if (uc < QFreetypeFace::cmapCacheSize)
1558 freetype->cmapCache[uc] = glyph;
1559 }
1560 }
1561 ++glyph_pos;
1562 }
1563 }
1564
1565 *nglyphs = glyph_pos;
1566 glyphs->numGlyphs = glyph_pos;
1567
1568 if (!(flags & GlyphIndicesOnly))
1569 recalcAdvances(glyphs, flags);
1570
1571 return true;
1572}
1573
1574bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const
1575{
1576 if (!FT_IS_SCALABLE(freetype->face))
1577 return false;
1578
1579 return default_hint_style == HintNone || default_hint_style == HintLight || (flags & DesignMetrics);
1580}
1581
1582QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const
1583{
1584 return m * scalableBitmapScaleFactor;
1585}
1586
1587glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const
1588{
1589 QTransform trans;
1590 trans.setMatrix(t.m11(), t.m12(), t.m13(),
1591 t.m21(), t.m22(), t.m23(),
1592 0, 0, t.m33());
1593 const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
1594 trans.scale(scaleFactor, scaleFactor);
1595
1596 QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal());
1597 QPointF offset(m.xoff.toReal(), m.yoff.toReal());
1598
1599 rect = trans.mapRect(rect);
1600 offset = trans.map(offset);
1601
1602 glyph_metrics_t metrics;
1603 metrics.x = QFixed::fromReal(rect.x());
1604 metrics.y = QFixed::fromReal(rect.y());
1605 metrics.width = QFixed::fromReal(rect.width());
1606 metrics.height = QFixed::fromReal(rect.height());
1607 metrics.xoff = QFixed::fromReal(offset.x());
1608 metrics.yoff = QFixed::fromReal(offset.y());
1609 return metrics;
1610}
1611
1612void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1613{
1614 FT_Face face = 0;
1615 bool design = shouldUseDesignMetrics(flags);
1616 for (int i = 0; i < glyphs->numGlyphs; i++) {
1617 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1618 // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1619 GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1620 if (g && g->format == acceptableFormat) {
1621 glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1622 } else {
1623 if (!face)
1624 face = lockFace();
1625 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1626 if (g)
1627 glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1628 else
1629 glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1630 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1631 if (!cacheEnabled && g != &emptyGlyph)
1632 delete g;
1633 }
1634
1635 if (scalableBitmapScaleFactor != 1)
1636 glyphs->advances[i] *= scalableBitmapScaleFactor;
1637 }
1638 if (face)
1639 unlockFace();
1640
1641 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
1642 for (int i = 0; i < glyphs->numGlyphs; ++i)
1643 glyphs->advances[i] = glyphs->advances[i].round();
1644 }
1645}
1646
1647glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1648{
1649 FT_Face face = 0;
1650
1651 glyph_metrics_t overall;
1652 // initialize with line height, we get the same behaviour on all platforms
1653 if (!isScalableBitmap()) {
1654 overall.y = -ascent();
1655 overall.height = ascent() + descent();
1656 } else {
1657 overall.y = QFixed::fromFixed(-metrics.ascender);
1658 overall.height = QFixed::fromFixed(metrics.ascender - metrics.descender);
1659 }
1660
1661 QFixed ymax = 0;
1662 QFixed xmax = 0;
1663 for (int i = 0; i < glyphs.numGlyphs; i++) {
1664 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1665 if (!g) {
1666 if (!face)
1667 face = lockFace();
1668 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1669 }
1670 if (g) {
1671 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1672 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1673 overall.x = qMin(overall.x, x);
1674 overall.y = qMin(overall.y, y);
1675 xmax = qMax(xmax, x + g->width);
1676 ymax = qMax(ymax, y + g->height);
1677 overall.xoff += g->advance;
1678 if (!cacheEnabled && g != &emptyGlyph)
1679 delete g;
1680 } else {
1681 int left = FLOOR(face->glyph->metrics.horiBearingX);
1682 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1683 int top = CEIL(face->glyph->metrics.horiBearingY);
1684 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1685
1686 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1687 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1688 overall.x = qMin(overall.x, x);
1689 overall.y = qMin(overall.y, y);
1690 xmax = qMax(xmax, x + TRUNC(right - left));
1691 ymax = qMax(ymax, y + TRUNC(top - bottom));
1692 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1693 }
1694 }
1695 overall.height = qMax(overall.height, ymax - overall.y);
1696 overall.width = xmax - overall.x;
1697
1698 if (face)
1699 unlockFace();
1700
1701 if (isScalableBitmap())
1702 overall = scaledBitmapMetrics(overall, QTransform());
1703 return overall;
1704}
1705
1706glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1707{
1708 FT_Face face = 0;
1709 glyph_metrics_t overall;
1710 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1711 if (!g) {
1712 face = lockFace();
1713 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1714 }
1715 if (g) {
1716 overall.x = g->x;
1717 overall.y = -g->y;
1718 overall.width = g->width;
1719 overall.height = g->height;
1720 overall.xoff = g->advance;
1721 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1722 overall.xoff = overall.xoff.round();
1723 if (!cacheEnabled && g != &emptyGlyph)
1724 delete g;
1725 } else {
1726 int left = FLOOR(face->glyph->metrics.horiBearingX);
1727 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1728 int top = CEIL(face->glyph->metrics.horiBearingY);
1729 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1730
1731 overall.width = TRUNC(right-left);
1732 overall.height = TRUNC(top-bottom);
1733 overall.x = TRUNC(left);
1734 overall.y = -TRUNC(top);
1735 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1736 }
1737 if (face)
1738 unlockFace();
1739
1740 if (isScalableBitmap())
1741 overall = scaledBitmapMetrics(overall, QTransform());
1742 return overall;
1743}
1744
1745glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1746{
1747 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1748}
1749
1750glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1751{
1752 Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true);
1753
1754 glyph_metrics_t overall;
1755 if (g) {
1756 overall.x = g->x;
1757 overall.y = -g->y;
1758 overall.width = g->width;
1759 overall.height = g->height;
1760 overall.xoff = g->advance;
1761 if (!cacheEnabled && g != &emptyGlyph)
1762 delete g;
1763 } else {
1764 FT_Face face = lockFace();
1765 int left = FLOOR(face->glyph->metrics.horiBearingX);
1766 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1767 int top = CEIL(face->glyph->metrics.horiBearingY);
1768 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1769
1770 overall.width = TRUNC(right-left);
1771 overall.height = TRUNC(top-bottom);
1772 overall.x = TRUNC(left);
1773 overall.y = -TRUNC(top);
1774 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1775 unlockFace();
1776 }
1777
1778 if (isScalableBitmap())
1779 overall = scaledBitmapMetrics(overall, matrix);
1780 return overall;
1781}
1782
1783static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat)
1784{
1785 if (glyph == nullptr || glyph->height == 0 || glyph->width == 0)
1786 return QImage();
1787
1788 QImage::Format format = QImage::Format_Invalid;
1789 int bytesPerLine = -1;
1790 switch (glyphFormat) {
1791 case QFontEngine::Format_Mono:
1792 format = QImage::Format_Mono;
1793 bytesPerLine = ((glyph->width + 31) & ~31) >> 3;
1794 break;
1795 case QFontEngine::Format_A8:
1796 format = QImage::Format_Alpha8;
1797 bytesPerLine = (glyph->width + 3) & ~3;
1798 break;
1799 case QFontEngine::Format_A32:
1800 format = QImage::Format_RGB32;
1801 bytesPerLine = glyph->width * 4;
1802 break;
1803 default:
1804 Q_UNREACHABLE();
1805 };
1806
1807 QImage img(static_cast<const uchar *>(glyph->data), glyph->width, glyph->height, bytesPerLine, format);
1808 if (format == QImage::Format_Mono)
1809 img.setColor(1, QColor(Qt::white).rgba()); // Expands color table to 2 items; item 0 set to transparent.
1810 return img;
1811}
1812
1813QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1814 QFontEngine::GlyphFormat neededFormat,
1815 const QTransform &t, QPoint *offset)
1816{
1817 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1818
1819 if (isBitmapFont())
1820 neededFormat = Format_Mono;
1821 else if (neededFormat == Format_None && defaultFormat != Format_None)
1822 neededFormat = defaultFormat;
1823 else if (neededFormat == Format_None)
1824 neededFormat = Format_A8;
1825
1826 Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);
1827
1828 if (offset != 0 && glyph != 0)
1829 *offset = QPoint(glyph->x, -glyph->y);
1830
1831 currentlyLockedAlphaMap = alphaMapFromGlyphData(glyph, neededFormat);
1832
1833 const bool glyphHasGeometry = glyph != nullptr && glyph->height != 0 && glyph->width != 0;
1834 if (!cacheEnabled && glyph != &emptyGlyph) {
1835 currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy();
1836 delete glyph;
1837 }
1838
1839 if (!glyphHasGeometry)
1840 return nullptr;
1841
1842 if (currentlyLockedAlphaMap.isNull())
1843 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t, offset);
1844
1845 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1846 data->is_locked = true;
1847
1848 return &currentlyLockedAlphaMap;
1849}
1850
1851void QFontEngineFT::unlockAlphaMapForGlyph()
1852{
1853 QFontEngine::unlockAlphaMapForGlyph();
1854}
1855
1856static inline bool is2dRotation(const QTransform &t)
1857{
1858 return qFuzzyCompare(t.m11(), t.m22()) && qFuzzyCompare(t.m12(), -t.m21())
1859 && qFuzzyCompare(t.m11()*t.m22() - t.m12()*t.m21(), qreal(1.0));
1860}
1861
1862QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
1863 QFixed subPixelPosition,
1864 GlyphFormat format,
1865 const QTransform &t,
1866 bool fetchBoundingBox,
1867 bool disableOutlineDrawing)
1868{
1869 QGlyphSet *glyphSet = loadGlyphSet(t);
1870 if (glyphSet != 0 && glyphSet->outline_drawing && !disableOutlineDrawing && !fetchBoundingBox)
1871 return 0;
1872
1873 Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0;
1874 if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) {
1875 QScopedValueRollback<HintStyle> saved_default_hint_style(default_hint_style);
1876 if (t.type() >= QTransform::TxScale && !is2dRotation(t))
1877 default_hint_style = HintNone; // disable hinting if the glyphs are transformed
1878
1879 lockFace();
1880 FT_Matrix m = this->matrix;
1881 FT_Matrix ftMatrix = glyphSet != 0 ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
1882 FT_Matrix_Multiply(&ftMatrix, &m);
1883 freetype->matrix = m;
1884 glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false, disableOutlineDrawing);
1885 unlockFace();
1886 }
1887
1888 return glyph;
1889}
1890
1891QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1892{
1893 return alphaMapForGlyph(g, subPixelPosition, QTransform());
1894}
1895
1896QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1897{
1898 const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono;
1899
1900 Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
1901
1902 QImage img = alphaMapFromGlyphData(glyph, neededFormat);
1903 img = img.copy();
1904
1905 if (!cacheEnabled && glyph != &emptyGlyph)
1906 delete glyph;
1907
1908 return img;
1909}
1910
1911QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1912{
1913 if (t.type() > QTransform::TxRotate)
1914 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1915
1916 const GlyphFormat neededFormat = Format_A32;
1917
1918 Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
1919
1920 QImage img = alphaMapFromGlyphData(glyph, neededFormat);
1921 img = img.copy();
1922
1923 if (!cacheEnabled && glyph != &emptyGlyph)
1924 delete glyph;
1925
1926 if (!img.isNull())
1927 return img;
1928
1929 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1930}
1931
1932QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t, const QColor &color)
1933{
1934 Q_UNUSED(color);
1935
1936 Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t);
1937 if (glyph == nullptr)
1938 return QImage();
1939
1940 QImage img;
1941 if (defaultFormat == GlyphFormat::Format_ARGB)
1942 img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_ARGB32_Premultiplied).copy();
1943 else if (defaultFormat == GlyphFormat::Format_Mono)
1944 img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy();
1945
1946 if (!img.isNull() && (!t.isIdentity() || scalableBitmapScaleFactor != 1)) {
1947 QTransform trans(t);
1948 const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
1949 trans.scale(scaleFactor, scaleFactor);
1950 img = img.transformed(trans, Qt::SmoothTransformation);
1951 }
1952
1953 if (!cacheEnabled && glyph != &emptyGlyph)
1954 delete glyph;
1955
1956 return img;
1957}
1958
1959void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1960{
1961 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1962}
1963
1964int QFontEngineFT::glyphCount() const
1965{
1966 int count = 0;
1967 FT_Face face = lockFace();
1968 if (face) {
1969 count = face->num_glyphs;
1970 unlockFace();
1971 }
1972 return count;
1973}
1974
1975FT_Face QFontEngineFT::lockFace(Scaling scale) const
1976{
1977 freetype->lock();
1978 FT_Face face = freetype->face;
1979 if (scale == Unscaled) {
1980 if (FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0) == 0) {
1981 freetype->xsize = face->units_per_EM << 6;
1982 freetype->ysize = face->units_per_EM << 6;
1983 }
1984 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1985 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1986 freetype->xsize = xsize;
1987 freetype->ysize = ysize;
1988 }
1989 if (freetype->matrix.xx != matrix.xx ||
1990 freetype->matrix.yy != matrix.yy ||
1991 freetype->matrix.xy != matrix.xy ||
1992 freetype->matrix.yx != matrix.yx) {
1993 freetype->matrix = matrix;
1994 FT_Set_Transform(face, &freetype->matrix, 0);
1995 }
1996
1997 return face;
1998}
1999
2000void QFontEngineFT::unlockFace() const
2001{
2002 freetype->unlock();
2003}
2004
2005FT_Face QFontEngineFT::non_locked_face() const
2006{
2007 return freetype->face;
2008}
2009
2010
2011QFontEngineFT::QGlyphSet::QGlyphSet()
2012 : outline_drawing(false)
2013{
2014 transformationMatrix.xx = 0x10000;
2015 transformationMatrix.yy = 0x10000;
2016 transformationMatrix.xy = 0;
2017 transformationMatrix.yx = 0;
2018 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2019 fast_glyph_count = 0;
2020}
2021
2022QFontEngineFT::QGlyphSet::~QGlyphSet()
2023{
2024 clear();
2025}
2026
2027void QFontEngineFT::QGlyphSet::clear()
2028{
2029 if (fast_glyph_count > 0) {
2030 for (int i = 0; i < 256; ++i) {
2031 if (fast_glyph_data[i]) {
2032 delete fast_glyph_data[i];
2033 fast_glyph_data[i] = 0;
2034 }
2035 }
2036 fast_glyph_count = 0;
2037 }
2038 qDeleteAll(glyph_data);
2039 glyph_data.clear();
2040}
2041
2042void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2043{
2044 if (useFastGlyphData(index, subPixelPosition)) {
2045 if (fast_glyph_data[index]) {
2046 delete fast_glyph_data[index];
2047 fast_glyph_data[index] = 0;
2048 if (fast_glyph_count > 0)
2049 --fast_glyph_count;
2050 }
2051 } else {
2052 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2053 }
2054}
2055
2056void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2057{
2058 if (useFastGlyphData(index, subPixelPosition)) {
2059 if (!fast_glyph_data[index])
2060 ++fast_glyph_count;
2061 fast_glyph_data[index] = glyph;
2062 } else {
2063 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2064 }
2065}
2066
2067int QFontEngineFT::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
2068{
2069 lockFace();
2070 bool hsubpixel = true;
2071 int vfactor = 1;
2072 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2073 int result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2074 unlockFace();
2075 return result;
2076}
2077
2078bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2079{
2080 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2081 return false;
2082
2083 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2084 // will be using it
2085 freetype->ref.ref();
2086
2087 default_load_flags = fe->default_load_flags;
2088 default_hint_style = fe->default_hint_style;
2089 antialias = fe->antialias;
2090 transform = fe->transform;
2091 embolden = fe->embolden;
2092 obliquen = fe->obliquen;
2093 subpixelType = fe->subpixelType;
2094 lcdFilterType = fe->lcdFilterType;
2095 embeddedbitmap = fe->embeddedbitmap;
2096
2097 return true;
2098}
2099
2100QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2101{
2102 QFontDef fontDef(this->fontDef);
2103 fontDef.pixelSize = pixelSize;
2104 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2105 if (!fe->initFromFontEngine(this)) {
2106 delete fe;
2107 return 0;
2108 } else {
2109 return fe;
2110 }
2111}
2112
2113Qt::HANDLE QFontEngineFT::handle() const
2114{
2115 return non_locked_face();
2116}
2117
2118QT_END_NAMESPACE
2119
2120#endif // QT_NO_FREETYPE
2121