1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include "qmetatype.h"
44 #include "qtextstream.h"
46 #include "qfontengine_ft_p.h"
47 #include "private/qimage_p.h"
49 #ifndef QT_NO_FREETYPE
52 #include "qfileinfo.h"
53 #include "qthreadstorage.h"
56 #include "qfontengine_ft_p.h"
58 #include FT_FREETYPE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
81 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
82 # define QT_MAX_CACHED_GLYPH_SIZE 64
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.
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)
96 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
97 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
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)
104 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
107 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
108 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
109 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
110 #define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
112 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
115 #define FLOOR(x) ((x) & -64)
116 #define CEIL(x) (((x)+63) & -64)
117 #define TRUNC(x) ((x) >> 6)
118 #define ROUND(x) (((x)+32) & -64)
120 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
122 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
123 FT_Face face = (FT_Face)font;
124 FT_ULong ftlen = *length;
127 if ( !FT_IS_SFNT(face) )
128 return HB_Err_Invalid_Argument;
130 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
132 return (HB_Error)error;
134 return HB_Err_Invalid_Argument;
138 // -------------------------- Freetype support ------------------------------
148 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
152 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
154 QtFreetypeData *qt_getFreetypeData()
156 return theFreetypeData();
159 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
161 QtFreetypeData *qt_getFreetypeData()
163 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
165 freetypeData = new QtFreetypeData;
170 FT_Library qt_getFreetype()
172 QtFreetypeData *freetypeData = qt_getFreetypeData();
173 if (!freetypeData->library)
174 FT_Init_FreeType(&freetypeData->library);
175 return freetypeData->library;
178 int QFreetypeFace::fsType() const
181 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
183 fsType = os2->fsType;
187 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
189 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
192 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
193 return HB_Err_Invalid_SubTable;
195 *nPoints = face->glyph->outline.n_points;
199 if (point > *nPoints)
200 return HB_Err_Invalid_SubTable;
202 *xpos = face->glyph->outline.points[point].x;
203 *ypos = face->glyph->outline.points[point].y;
208 extern QByteArray qt_fontdata_from_index(int);
211 * One font file can contain more than one font (bold/italic for example)
212 * find the right one and return it.
214 * Returns the freetype face or 0 in case of an empty file or any other problems
215 * (like not being able to open the file)
217 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
218 const QByteArray &fontData)
220 if (face_id.filename.isEmpty() && fontData.isEmpty())
223 QtFreetypeData *freetypeData = qt_getFreetypeData();
224 if (!freetypeData->library)
225 FT_Init_FreeType(&freetypeData->library);
227 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
231 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
233 if (!face_id.filename.isEmpty()) {
234 QString fileName = QString::fromUtf8(face_id.filename);
235 if (face_id.filename.startsWith(":qmemoryfonts/")) {
236 // from qfontdatabase.cpp
237 QByteArray idx = face_id.filename;
238 idx.remove(0, 14); // remove ':qmemoryfonts/'
240 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
242 newFreetype->fontData = QByteArray();
243 } else if (!QFileInfo(fileName).isNativePath()) {
244 QFile file(fileName);
245 if (!file.open(QIODevice::ReadOnly)) {
248 newFreetype->fontData = file.readAll();
251 newFreetype->fontData = fontData;
253 if (!newFreetype->fontData.isEmpty()) {
254 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
257 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
260 newFreetype->face = face;
262 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
263 Q_CHECK_PTR(newFreetype->hbFace);
264 newFreetype->ref.store(1);
265 newFreetype->xsize = 0;
266 newFreetype->ysize = 0;
267 newFreetype->matrix.xx = 0x10000;
268 newFreetype->matrix.yy = 0x10000;
269 newFreetype->matrix.xy = 0;
270 newFreetype->matrix.yx = 0;
271 newFreetype->unicode_map = 0;
272 newFreetype->symbol_map = 0;
274 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
276 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
277 FT_CharMap cm = newFreetype->face->charmaps[i];
278 switch(cm->encoding) {
279 case FT_ENCODING_UNICODE:
280 newFreetype->unicode_map = cm;
282 case FT_ENCODING_APPLE_ROMAN:
283 case FT_ENCODING_ADOBE_LATIN_1:
284 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
285 newFreetype->unicode_map = cm;
287 case FT_ENCODING_ADOBE_CUSTOM:
288 case FT_ENCODING_MS_SYMBOL:
289 if (!newFreetype->symbol_map)
290 newFreetype->symbol_map = cm;
297 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
298 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
300 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
302 freetypeData->faces.insert(face_id, newFreetype.data());
304 newFreetype.take()->release(face_id);
305 // we could return null in principle instead of throwing
308 freetype = newFreetype.take();
313 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
315 QtFreetypeData *freetypeData = qt_getFreetypeData();
319 if(freetypeData->faces.contains(face_id))
320 freetypeData->faces.take(face_id);
323 if (freetypeData->faces.isEmpty()) {
324 FT_Done_FreeType(freetypeData->library);
325 freetypeData->library = 0;
330 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
332 *ysize = qRound(fontDef.pixelSize * 64);
333 *xsize = *ysize * fontDef.stretch / 100;
334 *outline_drawing = false;
337 * Bitmap only faces must match exactly, so find the closest
338 * one (height dominant search)
340 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
342 for (int i = 1; i < face->num_fixed_sizes; i++) {
343 if (qAbs(*ysize - Y_SIZE(face,i)) <
344 qAbs (*ysize - Y_SIZE(face, best)) ||
345 (qAbs (*ysize - Y_SIZE(face, i)) ==
346 qAbs (*ysize - Y_SIZE(face, best)) &&
347 qAbs (*xsize - X_SIZE(face, i)) <
348 qAbs (*xsize - X_SIZE(face, best)))) {
352 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
353 *xsize = X_SIZE(face, best);
354 *ysize = Y_SIZE(face, best);
357 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
358 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
359 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
360 if (err && face->num_fixed_sizes == 1)
361 err = 0; //even more of a workaround...
368 *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
372 QFontEngine::Properties QFreetypeFace::properties() const
374 QFontEngine::Properties p;
375 p.postscriptName = FT_Get_Postscript_Name(face);
376 PS_FontInfoRec font_info;
377 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
378 p.copyright = font_info.notice;
379 if (FT_IS_SCALABLE(face)) {
380 p.ascent = face->ascender;
381 p.descent = -face->descender;
382 p.leading = face->height - face->ascender + face->descender;
383 p.emSquare = face->units_per_EM;
384 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
385 face->bbox.xMax - face->bbox.xMin,
386 face->bbox.yMax - face->bbox.yMin);
388 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
389 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
390 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
391 p.emSquare = face->size->metrics.y_ppem;
392 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
393 p.boundingBox = QRectF(0, -p.ascent.toReal(),
394 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
397 p.capHeight = p.ascent;
398 p.lineWidth = face->underline_thickness;
402 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
405 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
406 if (FT_IS_SFNT(face)) {
407 FT_ULong len = *length;
408 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
415 /* Some fonts (such as MingLiu rely on hinting to scale different
416 components to their correct sizes. While this is really broken (it
417 should be done in the component glyph itself, not the hinter) we
418 will have to live with it.
420 This means we can not use FT_LOAD_NO_HINTING to get the glyph
421 outline. All we can do is to load the unscaled glyph and scale it
422 down manually when required.
424 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
426 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
427 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
428 FT_Vector *p = g->outline.points;
429 const FT_Vector *e = p + g->outline.n_points;
431 p->x = FT_MulFix(p->x, x_scale);
432 p->y = FT_MulFix(p->y, y_scale);
437 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
439 const qreal factor = 1/64.;
440 scaleOutline(face, g, x_scale, y_scale);
442 QPointF cp = point.toPointF();
444 // convert the outline to a painter path
446 for (int j = 0; j < g->outline.n_contours; ++j) {
447 int last_point = g->outline.contours[j];
448 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
449 if(!(g->outline.tags[i] & 1)) {
450 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
453 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
454 // qDebug("first point at %f %f", start.x(), start.y());
460 while (i < last_point) {
462 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
463 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
465 switch (g->outline.tags[i] & 3) {
467 // cubic bezier element
470 c[3] = (c[3] + c[2])/2;
474 // quadratic bezier element
477 c[3] = (c[1] + c[2])/2;
478 c[2] = (2*c[1] + c[3])/3;
479 c[1] = (2*c[1] + c[0])/3;
485 // qDebug() << "lineTo" << c[1];
492 c[2] = (2*c[1] + c[3])/3;
493 c[1] = (2*c[1] + c[0])/3;
497 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
498 path->cubicTo(c[1], c[2], c[3]);
503 // qDebug() << "closeSubpath";
504 path->closeSubpath();
508 c[2] = (2*c[1] + c[3])/3;
509 c[1] = (2*c[1] + c[0])/3;
511 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
512 path->cubicTo(c[1], c[2], c[3]);
518 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
520 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
522 if (slot->format != FT_GLYPH_FORMAT_BITMAP
523 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
526 QPointF cp = point.toPointF();
527 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
528 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
531 QFontEngineFT::Glyph::~Glyph()
536 static const uint subpixel_filter[3][3] = {
542 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
546 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
547 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
548 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
549 res = (mid << 24) + (high << 16) + (mid << 8) + low;
552 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
557 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
560 const int offs = bgr ? -1 : 1;
561 const int w = width * 3;
564 for (int x = 0; x < w; x += 3) {
565 uint red = src[x+1-offs];
566 uint green = src[x+1];
567 uint blue = src[x+1+offs];
568 *dd = filterPixel(red, green, blue, legacyFilter);
576 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
579 const int offs = bgr ? -src_pitch : src_pitch;
581 for (int x = 0; x < width; x++) {
582 uint red = src[x+src_pitch-offs];
583 uint green = src[x+src_pitch];
584 uint blue = src[x+src_pitch+offs];
585 dst[x] = filterPixel(red, green, blue, legacyFilter);
592 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
594 // convolute the bitmap with a triangle filter to get rid of color fringes
595 // If we take account for a gamma value of 2, we end up with
596 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
597 // as this nicely sums up to 16 :)
602 for (int x = 2; x < width - 2; ++x) {
603 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
604 dst[x] = (uchar) (sum >> 4);
606 dst[width - 2] = dst[width - 1] = 0;
612 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
620 kerning_pairs_loaded = false;
626 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
628 default_hint_style = HintNone;
630 default_hint_style = HintFull;
632 subpixelType = Subpixel_None;
634 #if defined(FT_LCD_FILTER_H)
635 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
637 defaultFormat = Format_None;
638 embeddedbitmap = false;
639 cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").toInt() == 0;
640 m_subPixelPositionCount = 4;
643 QFontEngineFT::~QFontEngineFT()
646 freetype->release(face_id);
647 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
650 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
651 const QByteArray &fontData)
653 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
656 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
657 QFreetypeFace *freetypeFace)
659 freetype = freetypeFace;
665 defaultFormat = format;
666 this->antialias = antialias;
669 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
670 else if (format == Format_A8)
671 glyphFormat = QFontEngineGlyphCache::Raster_A8;
672 else if (format == Format_A32)
673 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
677 symbol = freetype->symbol_map != 0;
678 PS_FontInfoRec psrec;
679 // don't assume that type1 fonts are symbol fonts by default
680 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
681 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
684 freetype->hbFace->isSymbolFont = symbol;
686 lbearing = rbearing = SHRT_MIN;
687 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
689 FT_Face face = lockFace();
691 if (FT_IS_SCALABLE(face)) {
692 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
694 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
695 matrix.xy = 0x10000*3/10;
701 FT_Set_Transform(face, &matrix, 0);
702 freetype->matrix = matrix;
704 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
707 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
708 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
710 // copied from QFontEngineQPF
712 int score = fontDef.weight * fontDef.pixelSize;
713 line_thickness = score / 700;
714 // looks better with thicker line for small pointsizes
715 if (line_thickness < 2 && score >= 1050)
717 underline_position = ((line_thickness * 2) + 3) / 6;
719 if (line_thickness < 1)
722 hbFont.x_ppem = face->size->metrics.x_ppem;
723 hbFont.y_ppem = face->size->metrics.y_ppem;
724 hbFont.x_scale = face->size->metrics.x_scale;
725 hbFont.y_scale = face->size->metrics.y_scale;
727 hbFace = freetype->hbFace;
729 metrics = face->size->metrics;
732 TrueType fonts with embedded bitmaps may have a bitmap font specific
733 ascent/descent in the EBLC table. There is no direct public API
734 to extract those values. The only way we've found is to trick freetype
735 into thinking that it's not a scalable font in FT_SelectSize so that
736 the metrics are retrieved from the bitmap strikes.
738 if (FT_IS_SCALABLE(face)) {
739 for (int i = 0; i < face->num_fixed_sizes; ++i) {
740 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
741 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
743 FT_Select_Size(face, i);
744 metrics.ascender = face->size->metrics.ascender;
745 metrics.descender = face->size->metrics.descender;
746 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
748 face->face_flags |= FT_FACE_FLAG_SCALABLE;
754 fontDef.styleName = QString::fromUtf8(face->style_name);
758 fsType = freetype->fsType();
762 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
764 default_hint_style = style;
767 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
768 bool &hsubpixel, int &vfactor) const
770 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
771 int load_target = default_hint_style == HintLight
772 ? FT_LOAD_TARGET_LIGHT
773 : FT_LOAD_TARGET_NORMAL;
775 if (format == Format_Mono) {
776 load_target = FT_LOAD_TARGET_MONO;
777 } else if (format == Format_A32) {
778 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
779 if (default_hint_style == HintFull)
780 load_target = FT_LOAD_TARGET_LCD;
782 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
783 if (default_hint_style == HintFull)
784 load_target = FT_LOAD_TARGET_LCD_V;
789 if (set && set->outline_drawing)
790 load_flags = FT_LOAD_NO_BITMAP;
792 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
793 load_flags |= FT_LOAD_NO_HINTING;
795 load_flags |= load_target;
800 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
801 QFixed subPixelPosition,
803 bool fetchMetricsOnly) const
805 // Q_ASSERT(freetype->lock == 1);
807 if (format == Format_None) {
808 if (defaultFormat != Format_None) {
809 format = defaultFormat;
811 format = Format_Mono;
815 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
816 if (g && g->format == format && (fetchMetricsOnly || g->data))
819 QFontEngineFT::GlyphInfo info;
821 Q_ASSERT(format != Format_None);
822 bool hsubpixel = false;
824 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
826 if (format != Format_Mono && !embeddedbitmap)
827 load_flags |= FT_LOAD_NO_BITMAP;
829 FT_Matrix matrix = freetype->matrix;
830 bool transform = matrix.xx != 0x10000
831 || matrix.yy != 0x10000
836 load_flags |= FT_LOAD_NO_BITMAP;
838 FT_Face face = freetype->face;
841 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
843 FT_Set_Transform(face, &freetype->matrix, &v);
845 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
846 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
847 load_flags &= ~FT_LOAD_NO_BITMAP;
848 err = FT_Load_Glyph(face, glyph, load_flags);
850 if (err == FT_Err_Too_Few_Arguments) {
851 // this is an error in the bytecode interpreter, just try to run without it
852 load_flags |= FT_LOAD_FORCE_AUTOHINT;
853 err = FT_Load_Glyph(face, glyph, load_flags);
855 if (err != FT_Err_Ok)
856 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
858 FT_GlyphSlot slot = face->glyph;
860 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
862 Q_FT_GLYPHSLOT_OBLIQUE(slot);
864 // While Embolden alters the metrics of the slot, oblique does not, so we need
865 // to fix this ourselves.
873 FT_Matrix_Multiply(&m, &matrix);
876 FT_Library library = qt_getFreetype();
878 info.xOff = TRUNC(ROUND(slot->advance.x));
881 if ((set && set->outline_drawing) || fetchMetricsOnly) {
882 // If the advance doesn't fit in signed char, don't cache it
883 if (qAbs(info.xOff) >= 128)
887 g->linearAdvance = slot->linearHoriAdvance >> 10;
888 int left = FLOOR(slot->metrics.horiBearingX);
889 int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
890 int top = CEIL(slot->metrics.horiBearingY);
891 int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
892 g->width = TRUNC(right-left);
893 g->height = TRUNC(top-bottom);
896 g->advance = TRUNC(ROUND(slot->advance.x));
900 set->setGlyph(glyph, subPixelPosition, g);
905 uchar *glyph_buffer = 0;
906 int glyph_buffer_size = 0;
907 #if defined(QT_USE_FREETYPE_LCDFILTER)
908 bool useFreetypeRenderGlyph = false;
909 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
910 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
911 if (err == FT_Err_Ok)
912 useFreetypeRenderGlyph = true;
915 if (useFreetypeRenderGlyph) {
916 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
918 if (err != FT_Err_Ok)
919 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
921 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
923 info.height = slot->bitmap.rows / vfactor;
924 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
925 info.x = -slot->bitmap_left;
926 info.y = slot->bitmap_top;
928 glyph_buffer_size = info.width * info.height * 4;
929 glyph_buffer = new uchar[glyph_buffer_size];
932 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
933 else if (vfactor != 1)
934 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
938 int left = slot->metrics.horiBearingX;
939 int right = slot->metrics.horiBearingX + slot->metrics.width;
940 int top = slot->metrics.horiBearingY;
941 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
942 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
947 FT_Vector_Transform(&vector, &matrix);
952 FT_Vector_Transform(&vector, &matrix);
953 if (l > vector.x) l = vector.x;
954 if (r < vector.x) r = vector.x;
955 if (t < vector.y) t = vector.y;
956 if (b > vector.y) b = vector.y;
959 FT_Vector_Transform(&vector, &matrix);
960 if (l > vector.x) l = vector.x;
961 if (r < vector.x) r = vector.x;
962 if (t < vector.y) t = vector.y;
963 if (b > vector.y) b = vector.y;
966 FT_Vector_Transform(&vector, &matrix);
967 if (l > vector.x) l = vector.x;
968 if (r < vector.x) r = vector.x;
969 if (t < vector.y) t = vector.y;
970 if (b > vector.y) b = vector.y;
978 bottom = FLOOR(bottom);
981 int hpixels = TRUNC(right - left);
982 // subpixel position requires one more pixel
983 if (subPixelPosition > 0 && format != Format_Mono)
987 hpixels = hpixels*3 + 8;
988 info.width = hpixels;
989 info.height = TRUNC(top - bottom);
990 info.x = -TRUNC(left);
997 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
998 || ((uchar)(info.width) != info.width)
999 || ((uchar)(info.height) != info.height)
1000 || ((signed char)(info.x) != info.x)
1001 || ((signed char)(info.y) != info.y)
1002 || ((signed char)(info.xOff) != info.xOff));
1005 delete [] glyph_buffer;
1009 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1010 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1011 glyph_buffer_size = pitch * info.height;
1012 glyph_buffer = new uchar[glyph_buffer_size];
1014 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1016 bitmap.rows = info.height*vfactor;
1017 bitmap.width = hpixels;
1018 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1019 if (!hsubpixel && vfactor == 1)
1020 bitmap.buffer = glyph_buffer;
1022 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1023 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1024 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1026 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1027 matrix.yy = vfactor << 16;
1028 matrix.yx = matrix.xy = 0;
1030 FT_Outline_Transform(&slot->outline, &matrix);
1031 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1032 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1034 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1035 Q_ASSERT(antialias);
1036 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1037 bool useLegacyLcdFilter = false;
1038 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1039 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1041 uchar *buffer = bitmap.buffer;
1042 if (!useLegacyLcdFilter) {
1043 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1044 buffer = convoluted;
1046 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1047 delete [] convoluted;
1048 } else if (vfactor != 1) {
1049 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1052 if (bitmap.buffer != glyph_buffer)
1053 delete [] bitmap.buffer;
1054 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1055 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1056 uchar *src = slot->bitmap.buffer;
1057 uchar *dst = glyph_buffer;
1058 int h = slot->bitmap.rows;
1059 if (format == Format_Mono) {
1060 int bytes = ((info.width + 7) & ~7) >> 3;
1062 memcpy (dst, src, bytes);
1064 src += slot->bitmap.pitch;
1069 uint *dd = (uint *)dst;
1071 for (int x = 0; x < slot->bitmap.width; x++) {
1072 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1077 src += slot->bitmap.pitch;
1079 } else if (vfactor != 1) {
1081 uint *dd = (uint *)dst;
1082 for (int x = 0; x < slot->bitmap.width; x++) {
1083 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1087 src += slot->bitmap.pitch;
1091 for (int x = 0; x < slot->bitmap.width; x++) {
1092 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1096 src += slot->bitmap.pitch;
1101 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1102 delete [] glyph_buffer;
1113 g->linearAdvance = slot->linearHoriAdvance >> 10;
1114 g->width = info.width;
1115 g->height = info.height;
1118 g->advance = info.xOff;
1121 g->data = glyph_buffer;
1124 set->setGlyph(glyph, subPixelPosition, g);
1129 QFontEngine::FaceId QFontEngineFT::faceId() const
1134 QFontEngine::Properties QFontEngineFT::properties() const
1136 Properties p = freetype->properties();
1137 if (p.postscriptName.isEmpty()) {
1138 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1141 return freetype->properties();
1144 QFixed QFontEngineFT::emSquareSize() const
1146 if (FT_IS_SCALABLE(freetype->face))
1147 return freetype->face->units_per_EM;
1149 return freetype->face->size->metrics.y_ppem;
1152 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1154 return freetype->getSfntTable(tag, buffer, length);
1157 int QFontEngineFT::synthesized() const
1160 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1161 s = SynthesizedItalic;
1162 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1163 s |= SynthesizedBold;
1164 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1165 s |= SynthesizedStretch;
1169 QFixed QFontEngineFT::ascent() const
1171 return QFixed::fromFixed(metrics.ascender);
1174 QFixed QFontEngineFT::descent() const
1176 return QFixed::fromFixed(-metrics.descender);
1179 QFixed QFontEngineFT::leading() const
1181 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1184 QFixed QFontEngineFT::xHeight() const
1186 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1187 if (os2 && os2->sxHeight) {
1189 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1193 return QFontEngine::xHeight();
1196 QFixed QFontEngineFT::averageCharWidth() const
1198 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1199 if (os2 && os2->xAvgCharWidth) {
1201 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1205 return QFontEngine::averageCharWidth();
1208 qreal QFontEngineFT::maxCharWidth() const
1210 return metrics.max_advance >> 6;
1213 static const ushort char_table[] = {
1235 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1238 qreal QFontEngineFT::minLeftBearing() const
1240 if (lbearing == SHRT_MIN)
1241 (void) minRightBearing(); // calculates both
1242 return lbearing.toReal();
1245 qreal QFontEngineFT::minRightBearing() const
1247 if (rbearing == SHRT_MIN) {
1248 lbearing = rbearing = 0;
1249 const QChar *ch = (const QChar *)(const void*)char_table;
1250 QGlyphLayoutArray<char_table_entries> glyphs;
1251 int ng = char_table_entries;
1252 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1254 if (glyphs.glyphs[ng]) {
1255 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1256 lbearing = qMin(lbearing, gi.x);
1257 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1261 return rbearing.toReal();
1264 QFixed QFontEngineFT::lineThickness() const
1266 return line_thickness;
1269 QFixed QFontEngineFT::underlinePosition() const
1271 return underline_position;
1274 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1276 if (!kerning_pairs_loaded) {
1277 kerning_pairs_loaded = true;
1279 if (freetype->face->size->metrics.x_ppem != 0) {
1280 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1282 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1287 QFontEngine::doKerning(g, flags);
1290 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1292 if (matrix.type() > QTransform::TxShear)
1295 // FT_Set_Transform only supports scalable fonts
1296 if (!FT_IS_SCALABLE(freetype->face))
1300 m.xx = FT_Fixed(matrix.m11() * 65536);
1301 m.xy = FT_Fixed(-matrix.m21() * 65536);
1302 m.yx = FT_Fixed(-matrix.m12() * 65536);
1303 m.yy = FT_Fixed(matrix.m22() * 65536);
1307 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1308 const QGlyphSet &g = transformedGlyphSets.at(i);
1309 if (g.transformationMatrix.xx == m.xx
1310 && g.transformationMatrix.xy == m.xy
1311 && g.transformationMatrix.yx == m.yx
1312 && g.transformationMatrix.yy == m.yy) {
1314 // found a match, move it to the front
1315 transformedGlyphSets.move(i, 0);
1316 gs = &transformedGlyphSets[0];
1322 // don't try to load huge fonts
1323 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1324 if (draw_as_outline)
1327 // don't cache more than 10 transformations
1328 if (transformedGlyphSets.count() >= 10) {
1329 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1331 transformedGlyphSets.prepend(QGlyphSet());
1333 gs = &transformedGlyphSets[0];
1335 gs->transformationMatrix = m;
1336 gs->outline_drawing = draw_as_outline;
1342 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1343 const QFixedPoint *positions,
1348 for (int i = 0; i < num_glyphs; ++i) {
1349 QFixed spp = subPixelPositionForX(positions[i].x);
1350 Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1351 if (glyph == 0 || glyph->format != format) {
1354 FT_Matrix m = matrix;
1355 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1356 FT_Set_Transform(face, &m, 0);
1357 freetype->matrix = m;
1359 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1372 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1374 FT_Face face = lockFace(Unscaled);
1375 FT_Set_Transform(face, 0, 0);
1376 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1378 int left = face->glyph->metrics.horiBearingX;
1379 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1380 int top = face->glyph->metrics.horiBearingY;
1381 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1387 metrics->width = QFixed::fromFixed(right-left);
1388 metrics->height = QFixed::fromFixed(top-bottom);
1389 metrics->x = QFixed::fromFixed(left);
1390 metrics->y = QFixed::fromFixed(-top);
1391 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1393 if (!FT_IS_SCALABLE(freetype->face))
1394 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1396 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1398 FT_Set_Transform(face, &freetype->matrix, 0);
1402 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1404 uint ucs4 = str[i].unicode();
1405 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1407 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1412 bool QFontEngineFT::canRender(const QChar *string, int len)
1414 FT_Face face = freetype->face;
1416 for ( int i = 0; i < len; i++ ) {
1417 unsigned int uc = getChar(string, i, len);
1418 if (!FT_Get_Char_Index(face, uc))
1425 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1427 if (!glyphs.numGlyphs)
1430 if (FT_IS_SCALABLE(freetype->face)) {
1431 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1433 QVarLengthArray<QFixedPoint> positions;
1434 QVarLengthArray<glyph_t> positioned_glyphs;
1436 matrix.translate(x, y);
1437 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
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 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1449 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1450 QPainterPath *path, QTextItem::RenderFlags)
1452 FT_Face face = lockFace(Unscaled);
1454 for (int gl = 0; gl < numGlyphs; gl++) {
1455 FT_UInt glyph = glyphs[gl];
1457 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1459 FT_GlyphSlot g = face->glyph;
1460 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1462 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1463 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1464 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1469 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1470 QTextEngine::ShaperFlags flags) const
1472 if (*nglyphs < len) {
1477 bool mirrored = flags & QTextEngine::RightToLeft;
1479 if (freetype->symbol_map) {
1480 FT_Face face = freetype->face;
1481 for ( int i = 0; i < len; ++i ) {
1482 unsigned int uc = getChar(str, i, len);
1483 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1484 if ( !glyphs->glyphs[glyph_pos] ) {
1485 // Symbol fonts can have more than one CMAPs, FreeType should take the
1486 // correct one for us by default, so we always try FT_Get_Char_Index
1487 // first. If it didn't work (returns 0), we will explicitly set the
1488 // CMAP to symbol font one and try again. symbol_map is not always the
1489 // correct one because in certain fonts like Wingdings symbol_map only
1490 // contains PUA codepoints instead of the common ones.
1491 glyph_t glyph = FT_Get_Char_Index(face, uc);
1492 // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1493 // while we usually want to render them as space
1494 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1496 glyph = FT_Get_Char_Index(face, uc);
1499 FT_Set_Charmap(face, freetype->symbol_map);
1500 glyph = FT_Get_Char_Index(face, uc);
1501 FT_Set_Charmap(face, freetype->unicode_map);
1503 glyphs->glyphs[glyph_pos] = glyph;
1504 if (uc < QFreetypeFace::cmapCacheSize)
1505 freetype->cmapCache[uc] = glyph;
1510 FT_Face face = freetype->face;
1511 for (int i = 0; i < len; ++i) {
1512 unsigned int uc = getChar(str, i, len);
1514 uc = QChar::mirroredChar(uc);
1515 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1516 if (!glyphs->glyphs[glyph_pos]) {
1519 glyph_t glyph = FT_Get_Char_Index(face, uc);
1520 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1524 glyphs->glyphs[glyph_pos] = glyph;
1525 if (uc < QFreetypeFace::cmapCacheSize)
1526 freetype->cmapCache[uc] = glyph;
1533 *nglyphs = glyph_pos;
1534 glyphs->numGlyphs = glyph_pos;
1536 if (flags & QTextEngine::GlyphIndicesOnly)
1539 recalcAdvances(glyphs, flags);
1544 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1547 bool design = (default_hint_style == HintNone ||
1548 default_hint_style == HintLight ||
1549 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1550 for (int i = 0; i < glyphs->numGlyphs; i++) {
1551 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1552 // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1553 GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1554 if (g && g->format == acceptableFormat) {
1555 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1559 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1560 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1561 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1563 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1564 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1565 glyphs->advances_y[i] = 0;
1571 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1575 glyph_metrics_t overall;
1576 // initialize with line height, we get the same behaviour on all platforms
1577 overall.y = -ascent();
1578 overall.height = ascent() + descent();
1582 for (int i = 0; i < glyphs.numGlyphs; i++) {
1583 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1587 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1590 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1591 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1592 overall.x = qMin(overall.x, x);
1593 overall.y = qMin(overall.y, y);
1594 xmax = qMax(xmax, x + g->width);
1595 ymax = qMax(ymax, y + g->height);
1596 overall.xoff += g->advance;
1598 int left = FLOOR(face->glyph->metrics.horiBearingX);
1599 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1600 int top = CEIL(face->glyph->metrics.horiBearingY);
1601 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1603 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1604 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1605 overall.x = qMin(overall.x, x);
1606 overall.y = qMin(overall.y, y);
1607 xmax = qMax(xmax, x + TRUNC(right - left));
1608 ymax = qMax(ymax, y + TRUNC(top - bottom));
1609 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1612 overall.height = qMax(overall.height, ymax - overall.y);
1613 overall.width = xmax - overall.x;
1621 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1624 glyph_metrics_t overall;
1625 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1628 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1633 overall.width = g->width;
1634 overall.height = g->height;
1635 overall.xoff = g->advance;
1636 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1637 overall.xoff = overall.xoff.round();
1639 int left = FLOOR(face->glyph->metrics.horiBearingX);
1640 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1641 int top = CEIL(face->glyph->metrics.horiBearingY);
1642 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1644 overall.width = TRUNC(right-left);
1645 overall.height = TRUNC(top-bottom);
1646 overall.x = TRUNC(left);
1647 overall.y = -TRUNC(top);
1648 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1655 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1657 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1660 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1664 m.xx = FT_Fixed(matrix.m11() * 65536);
1665 m.xy = FT_Fixed(-matrix.m21() * 65536);
1666 m.yx = FT_Fixed(-matrix.m12() * 65536);
1667 m.yy = FT_Fixed(matrix.m22() * 65536);
1672 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1675 glyph_metrics_t overall;
1676 QGlyphSet *glyphSet = 0;
1677 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1679 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1680 // TODO move everything here to a method of its own to access glyphSets
1681 // to be shared with a new method that will replace loadTransformedGlyphSet()
1682 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1683 const QGlyphSet &g = transformedGlyphSets.at(i);
1684 if (g.transformationMatrix.xx == ftMatrix.xx
1685 && g.transformationMatrix.xy == ftMatrix.xy
1686 && g.transformationMatrix.yx == ftMatrix.yx
1687 && g.transformationMatrix.yy == ftMatrix.yy) {
1689 // found a match, move it to the front
1690 transformedGlyphSets.move(i, 0);
1691 glyphSet = &transformedGlyphSets[0];
1697 // don't cache more than 10 transformations
1698 if (transformedGlyphSets.count() >= 10) {
1699 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1701 transformedGlyphSets.prepend(QGlyphSet());
1703 glyphSet = &transformedGlyphSets[0];
1705 glyphSet->transformationMatrix = ftMatrix;
1709 glyphSet = &defaultGlyphSet;
1712 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1713 if (!g || g->format != format) {
1715 FT_Matrix m = this->matrix;
1716 FT_Matrix_Multiply(&ftMatrix, &m);
1717 freetype->matrix = m;
1718 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1724 overall.width = g->width;
1725 overall.height = g->height;
1726 overall.xoff = g->advance;
1728 int left = FLOOR(face->glyph->metrics.horiBearingX);
1729 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1730 int top = CEIL(face->glyph->metrics.horiBearingY);
1731 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1733 overall.width = TRUNC(right-left);
1734 overall.height = TRUNC(top-bottom);
1735 overall.x = TRUNC(left);
1736 overall.y = -TRUNC(top);
1737 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1744 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1745 QFontEngine::GlyphFormat neededFormat,
1746 const QTransform &t, QPoint *offset)
1748 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1752 neededFormat = Format_Mono;
1753 else if (neededFormat == Format_None && defaultFormat != Format_None)
1754 neededFormat = defaultFormat;
1755 else if (neededFormat == Format_None)
1756 neededFormat = Format_A8;
1758 QImage::Format format;
1759 switch (neededFormat) {
1761 format = QImage::Format_Mono;
1764 format = QImage::Format_Indexed8;
1767 format = QImage::Format_ARGB32;
1771 format = QImage::Format_Invalid;
1774 QFontEngineFT::Glyph *glyph;
1776 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1777 QFontEngine::HintStyle hintStyle = default_hint_style;
1778 if (t.type() >= QTransform::TxScale) {
1779 // disable hinting if the glyphs are transformed
1780 default_hint_style = HintNone;
1782 gset = loadTransformedGlyphSet(t);
1788 FT_Matrix m = matrix;
1789 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1790 FT_Set_Transform(freetype->face, &m, 0);
1791 freetype->matrix = m;
1794 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1796 default_hint_style = hintStyle;
1797 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1800 default_hint_style = hintStyle;
1802 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1804 FT_Matrix m = matrix;
1805 FT_Matrix extra = QTransformToFTMatrix(t);
1806 FT_Matrix_Multiply(&extra, &m);
1807 FT_Set_Transform(freetype->face, &m, 0);
1808 freetype->matrix = m;
1809 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1812 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1818 switch (neededFormat) {
1820 pitch = ((glyph->width + 31) & ~31) >> 3;
1823 pitch = (glyph->width + 3) & ~3;
1826 pitch = glyph->width * 4;
1834 *offset = QPoint(glyph->x, -glyph->y);
1836 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1837 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1839 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1840 data->is_locked = true;
1842 return ¤tlyLockedAlphaMap;
1845 void QFontEngineFT::unlockAlphaMapForGlyph()
1847 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1849 currentlyLockedAlphaMap = QImage();
1852 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1854 return defaultGlyphSet.outline_drawing ? 0 :
1855 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1858 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1862 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1863 if (!glyph || !glyph->data) {
1865 return QFontEngine::alphaMapForGlyph(g);
1868 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1870 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1872 QVector<QRgb> colors(256);
1873 for (int i=0; i<256; ++i)
1874 colors[i] = qRgba(0, 0, 0, i);
1875 img.setColorTable(colors);
1877 QVector<QRgb> colors(2);
1878 colors[0] = qRgba(0, 0, 0, 0);
1879 colors[1] = qRgba(0, 0, 0, 255);
1880 img.setColorTable(colors);
1882 Q_ASSERT(img.bytesPerLine() == pitch);
1884 for (int y = 0; y < glyph->height; ++y)
1885 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1892 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1894 if (t.type() > QTransform::TxTranslate)
1895 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1899 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1900 if (!glyph || !glyph->data) {
1902 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1905 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1906 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1912 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1914 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1917 int QFontEngineFT::glyphCount() const
1920 FT_Face face = lockFace();
1922 count = face->num_glyphs;
1928 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1931 FT_Face face = freetype->face;
1932 if (scale == Unscaled) {
1933 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1934 freetype->xsize = face->units_per_EM << 6;
1935 freetype->ysize = face->units_per_EM << 6;
1936 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1937 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1938 freetype->xsize = xsize;
1939 freetype->ysize = ysize;
1941 if (freetype->matrix.xx != matrix.xx ||
1942 freetype->matrix.yy != matrix.yy ||
1943 freetype->matrix.xy != matrix.xy ||
1944 freetype->matrix.yx != matrix.yx) {
1945 freetype->matrix = matrix;
1946 FT_Set_Transform(face, &freetype->matrix, 0);
1952 void QFontEngineFT::unlockFace() const
1957 FT_Face QFontEngineFT::non_locked_face() const
1959 return freetype->face;
1963 QFontEngineFT::QGlyphSet::QGlyphSet()
1964 : outline_drawing(false)
1966 transformationMatrix.xx = 0x10000;
1967 transformationMatrix.yy = 0x10000;
1968 transformationMatrix.xy = 0;
1969 transformationMatrix.yx = 0;
1970 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1971 fast_glyph_count = 0;
1974 QFontEngineFT::QGlyphSet::~QGlyphSet()
1979 void QFontEngineFT::QGlyphSet::clear()
1981 if (fast_glyph_count > 0) {
1982 for (int i = 0; i < 256; ++i) {
1983 if (fast_glyph_data[i]) {
1984 delete fast_glyph_data[i];
1985 fast_glyph_data[i] = 0;
1988 fast_glyph_count = 0;
1990 qDeleteAll(glyph_data);
1994 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1996 if (useFastGlyphData(index, subPixelPosition)) {
1997 if (fast_glyph_data[index]) {
1998 delete fast_glyph_data[index];
1999 fast_glyph_data[index] = 0;
2000 if (fast_glyph_count > 0)
2004 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2008 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2010 if (useFastGlyphData(index, subPixelPosition)) {
2011 if (!fast_glyph_data[index])
2013 fast_glyph_data[index] = glyph;
2015 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2019 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2022 bool hsubpixel = true;
2024 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2025 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2030 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2032 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2035 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2037 freetype->ref.ref();
2039 default_load_flags = fe->default_load_flags;
2040 default_hint_style = fe->default_hint_style;
2041 antialias = fe->antialias;
2042 transform = fe->transform;
2043 embolden = fe->embolden;
2044 obliquen = fe->obliquen;
2045 subpixelType = fe->subpixelType;
2046 lcdFilterType = fe->lcdFilterType;
2047 embeddedbitmap = fe->embeddedbitmap;
2052 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2054 QFontDef fontDef(this->fontDef);
2055 fontDef.pixelSize = pixelSize;
2056 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2057 if (!fe->initFromFontEngine(this)) {
2067 #endif // QT_NO_FREETYPE