1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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 "qabstractfileengine.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;
209 * One font file can contain more than one font (bold/italic for example)
210 * find the right one and return it.
212 * Returns the freetype face or 0 in case of an empty file or any other problems
213 * (like not being able to open the file)
215 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
216 const QByteArray &fontData)
218 if (face_id.filename.isEmpty() && fontData.isEmpty())
221 QtFreetypeData *freetypeData = qt_getFreetypeData();
222 if (!freetypeData->library)
223 FT_Init_FreeType(&freetypeData->library);
225 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
229 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
231 if (!face_id.filename.isEmpty()) {
232 QFile file(QString::fromUtf8(face_id.filename));
233 if (face_id.filename.startsWith(":qmemoryfonts/")) {
234 // from qfontdatabase.cpp
235 extern QByteArray qt_fontdata_from_index(int);
236 QByteArray idx = face_id.filename;
237 idx.remove(0, 14); // remove ':qmemoryfonts/'
239 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
241 newFreetype->fontData = QByteArray();
242 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
243 if (!file.open(QIODevice::ReadOnly)) {
246 newFreetype->fontData = file.readAll();
249 newFreetype->fontData = fontData;
251 if (!newFreetype->fontData.isEmpty()) {
252 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
255 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
258 newFreetype->face = face;
260 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
261 Q_CHECK_PTR(newFreetype->hbFace);
262 newFreetype->ref.store(1);
263 newFreetype->xsize = 0;
264 newFreetype->ysize = 0;
265 newFreetype->matrix.xx = 0x10000;
266 newFreetype->matrix.yy = 0x10000;
267 newFreetype->matrix.xy = 0;
268 newFreetype->matrix.yx = 0;
269 newFreetype->unicode_map = 0;
270 newFreetype->symbol_map = 0;
271 #ifndef QT_NO_FONTCONFIG
272 newFreetype->charset = 0;
275 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
277 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
278 FT_CharMap cm = newFreetype->face->charmaps[i];
279 switch(cm->encoding) {
280 case FT_ENCODING_UNICODE:
281 newFreetype->unicode_map = cm;
283 case FT_ENCODING_APPLE_ROMAN:
284 case FT_ENCODING_ADOBE_LATIN_1:
285 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
286 newFreetype->unicode_map = cm;
288 case FT_ENCODING_ADOBE_CUSTOM:
289 case FT_ENCODING_MS_SYMBOL:
290 if (!newFreetype->symbol_map)
291 newFreetype->symbol_map = cm;
298 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
299 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
302 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
303 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
304 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
305 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
306 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
308 for (int i = 0; i < 256; i += 8)
309 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
310 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
311 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
312 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
313 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
316 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
318 freetypeData->faces.insert(face_id, newFreetype.data());
320 newFreetype.take()->release(face_id);
321 // we could return null in principle instead of throwing
324 freetype = newFreetype.take();
329 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
331 QtFreetypeData *freetypeData = qt_getFreetypeData();
335 #ifndef QT_NO_FONTCONFIG
337 FcCharSetDestroy(charset);
339 if(freetypeData->faces.contains(face_id))
340 freetypeData->faces.take(face_id);
343 if (freetypeData->faces.isEmpty()) {
344 FT_Done_FreeType(freetypeData->library);
345 freetypeData->library = 0;
350 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
352 *ysize = qRound(fontDef.pixelSize * 64);
353 *xsize = *ysize * fontDef.stretch / 100;
354 *outline_drawing = false;
357 * Bitmap only faces must match exactly, so find the closest
358 * one (height dominant search)
360 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
362 for (int i = 1; i < face->num_fixed_sizes; i++) {
363 if (qAbs(*ysize - Y_SIZE(face,i)) <
364 qAbs (*ysize - Y_SIZE(face, best)) ||
365 (qAbs (*ysize - Y_SIZE(face, i)) ==
366 qAbs (*ysize - Y_SIZE(face, best)) &&
367 qAbs (*xsize - X_SIZE(face, i)) <
368 qAbs (*xsize - X_SIZE(face, best)))) {
372 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
373 *xsize = X_SIZE(face, best);
374 *ysize = Y_SIZE(face, best);
377 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
378 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
379 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
380 if (err && face->num_fixed_sizes == 1)
381 err = 0; //even more of a workaround...
388 *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
392 QFontEngine::Properties QFreetypeFace::properties() const
394 QFontEngine::Properties p;
395 p.postscriptName = FT_Get_Postscript_Name(face);
396 PS_FontInfoRec font_info;
397 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
398 p.copyright = font_info.notice;
399 if (FT_IS_SCALABLE(face)) {
400 p.ascent = face->ascender;
401 p.descent = -face->descender;
402 p.leading = face->height - face->ascender + face->descender;
403 p.emSquare = face->units_per_EM;
404 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
405 face->bbox.xMax - face->bbox.xMin,
406 face->bbox.yMax - face->bbox.yMin);
408 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
409 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
410 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
411 p.emSquare = face->size->metrics.y_ppem;
412 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
413 p.boundingBox = QRectF(0, -p.ascent.toReal(),
414 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
417 p.capHeight = p.ascent;
418 p.lineWidth = face->underline_thickness;
422 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
425 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
426 if (FT_IS_SFNT(face)) {
427 FT_ULong len = *length;
428 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
435 /* Some fonts (such as MingLiu rely on hinting to scale different
436 components to their correct sizes. While this is really broken (it
437 should be done in the component glyph itself, not the hinter) we
438 will have to live with it.
440 This means we can not use FT_LOAD_NO_HINTING to get the glyph
441 outline. All we can do is to load the unscaled glyph and scale it
442 down manually when required.
444 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
446 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
447 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
448 FT_Vector *p = g->outline.points;
449 const FT_Vector *e = p + g->outline.n_points;
451 p->x = FT_MulFix(p->x, x_scale);
452 p->y = FT_MulFix(p->y, y_scale);
457 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
459 const qreal factor = 1/64.;
460 scaleOutline(face, g, x_scale, y_scale);
462 QPointF cp = point.toPointF();
464 // convert the outline to a painter path
466 for (int j = 0; j < g->outline.n_contours; ++j) {
467 int last_point = g->outline.contours[j];
468 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
469 if(!(g->outline.tags[i] & 1)) {
470 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
473 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
474 // qDebug("first point at %f %f", start.x(), start.y());
480 while (i < last_point) {
482 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
483 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
485 switch (g->outline.tags[i] & 3) {
487 // cubic bezier element
490 c[3] = (c[3] + c[2])/2;
494 // quadratic bezier element
497 c[3] = (c[1] + c[2])/2;
498 c[2] = (2*c[1] + c[3])/3;
499 c[1] = (2*c[1] + c[0])/3;
505 // qDebug() << "lineTo" << c[1];
512 c[2] = (2*c[1] + c[3])/3;
513 c[1] = (2*c[1] + c[0])/3;
517 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
518 path->cubicTo(c[1], c[2], c[3]);
523 // qDebug() << "closeSubpath";
524 path->closeSubpath();
528 c[2] = (2*c[1] + c[3])/3;
529 c[1] = (2*c[1] + c[0])/3;
531 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
532 path->cubicTo(c[1], c[2], c[3]);
538 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
540 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
542 if (slot->format != FT_GLYPH_FORMAT_BITMAP
543 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
546 QPointF cp = point.toPointF();
547 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
548 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
551 QFontEngineFT::Glyph::~Glyph()
556 static const uint subpixel_filter[3][3] = {
562 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
566 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
567 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
568 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
569 res = (mid << 24) + (high << 16) + (mid << 8) + low;
572 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
577 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
580 const int offs = bgr ? -1 : 1;
581 const int w = width * 3;
584 for (int x = 0; x < w; x += 3) {
585 uint red = src[x+1-offs];
586 uint green = src[x+1];
587 uint blue = src[x+1+offs];
588 *dd = filterPixel(red, green, blue, legacyFilter);
596 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
599 const int offs = bgr ? -src_pitch : src_pitch;
601 for (int x = 0; x < width; x++) {
602 uint red = src[x+src_pitch-offs];
603 uint green = src[x+src_pitch];
604 uint blue = src[x+src_pitch+offs];
605 dst[x] = filterPixel(red, green, blue, legacyFilter);
612 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
614 // convolute the bitmap with a triangle filter to get rid of color fringes
615 // If we take account for a gamma value of 2, we end up with
616 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
617 // as this nicely sums up to 16 :)
622 for (int x = 2; x < width - 2; ++x) {
623 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
624 dst[x] = (uchar) (sum >> 4);
626 dst[width - 2] = dst[width - 1] = 0;
632 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
640 kerning_pairs_loaded = false;
646 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
648 default_hint_style = HintNone;
650 default_hint_style = HintFull;
652 subpixelType = Subpixel_None;
654 #if defined(FT_LCD_FILTER_H)
655 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
657 defaultFormat = Format_None;
658 embeddedbitmap = false;
659 cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").toInt() == 0;
662 QFontEngineFT::~QFontEngineFT()
665 freetype->release(face_id);
666 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
669 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
670 const QByteArray &fontData)
672 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
675 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
676 QFreetypeFace *freetypeFace)
678 freetype = freetypeFace;
684 defaultFormat = format;
685 this->antialias = antialias;
688 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
689 else if (format == Format_A8)
690 glyphFormat = QFontEngineGlyphCache::Raster_A8;
691 else if (format == Format_A32)
692 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
696 symbol = freetype->symbol_map != 0;
697 PS_FontInfoRec psrec;
698 // don't assume that type1 fonts are symbol fonts by default
699 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
700 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
703 freetype->hbFace->isSymbolFont = symbol;
705 lbearing = rbearing = SHRT_MIN;
706 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
708 FT_Face face = lockFace();
710 if (FT_IS_SCALABLE(face)) {
711 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
713 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
714 matrix.xy = 0x10000*3/10;
720 FT_Set_Transform(face, &matrix, 0);
721 freetype->matrix = matrix;
723 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
726 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
727 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
729 // copied from QFontEngineQPF
731 int score = fontDef.weight * fontDef.pixelSize;
732 line_thickness = score / 700;
733 // looks better with thicker line for small pointsizes
734 if (line_thickness < 2 && score >= 1050)
736 underline_position = ((line_thickness * 2) + 3) / 6;
738 if (line_thickness < 1)
741 hbFont.x_ppem = face->size->metrics.x_ppem;
742 hbFont.y_ppem = face->size->metrics.y_ppem;
743 hbFont.x_scale = face->size->metrics.x_scale;
744 hbFont.y_scale = face->size->metrics.y_scale;
746 hbFace = freetype->hbFace;
748 metrics = face->size->metrics;
751 TrueType fonts with embedded bitmaps may have a bitmap font specific
752 ascent/descent in the EBLC table. There is no direct public API
753 to extract those values. The only way we've found is to trick freetype
754 into thinking that it's not a scalable font in FT_SelectSize so that
755 the metrics are retrieved from the bitmap strikes.
757 if (FT_IS_SCALABLE(face)) {
758 for (int i = 0; i < face->num_fixed_sizes; ++i) {
759 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
760 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
762 FT_Select_Size(face, i);
763 metrics.ascender = face->size->metrics.ascender;
764 metrics.descender = face->size->metrics.descender;
765 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
767 face->face_flags |= FT_FACE_FLAG_SCALABLE;
773 fontDef.styleName = QString::fromUtf8(face->style_name);
777 fsType = freetype->fsType();
781 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
783 default_hint_style = style;
786 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
787 bool &hsubpixel, int &vfactor) const
789 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
790 int load_target = default_hint_style == HintLight
791 ? FT_LOAD_TARGET_LIGHT
792 : FT_LOAD_TARGET_NORMAL;
794 if (format == Format_Mono) {
795 load_target = FT_LOAD_TARGET_MONO;
796 } else if (format == Format_A32) {
797 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
798 if (default_hint_style == HintFull)
799 load_target = FT_LOAD_TARGET_LCD;
801 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
802 if (default_hint_style == HintFull)
803 load_target = FT_LOAD_TARGET_LCD_V;
808 if (set && set->outline_drawing)
809 load_flags = FT_LOAD_NO_BITMAP;
811 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
812 load_flags |= FT_LOAD_NO_HINTING;
814 load_flags |= load_target;
819 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
820 QFixed subPixelPosition,
822 bool fetchMetricsOnly) const
824 // Q_ASSERT(freetype->lock == 1);
826 if (format == Format_None) {
827 if (defaultFormat != Format_None) {
828 format = defaultFormat;
830 format = Format_Mono;
834 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
835 if (g && g->format == format)
838 QFontEngineFT::GlyphInfo info;
840 Q_ASSERT(format != Format_None);
841 bool hsubpixel = false;
843 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
845 if (format != Format_Mono && !embeddedbitmap)
846 load_flags |= FT_LOAD_NO_BITMAP;
848 FT_Matrix matrix = freetype->matrix;
849 bool transform = matrix.xx != 0x10000
850 || matrix.yy != 0x10000
855 load_flags |= FT_LOAD_NO_BITMAP;
857 FT_Face face = freetype->face;
860 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
862 FT_Set_Transform(face, &freetype->matrix, &v);
864 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
865 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
866 load_flags &= ~FT_LOAD_NO_BITMAP;
867 err = FT_Load_Glyph(face, glyph, load_flags);
869 if (err == FT_Err_Too_Few_Arguments) {
870 // this is an error in the bytecode interpreter, just try to run without it
871 load_flags |= FT_LOAD_FORCE_AUTOHINT;
872 err = FT_Load_Glyph(face, glyph, load_flags);
874 if (err != FT_Err_Ok)
875 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
877 if ((!set || set->outline_drawing) && fetchMetricsOnly)
880 FT_GlyphSlot slot = face->glyph;
881 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
883 Q_FT_GLYPHSLOT_OBLIQUE(slot);
885 // While Embolden alters the metrics of the slot, oblique does not, so we need
886 // to fix this ourselves.
894 FT_Matrix_Multiply(&m, &matrix);
897 FT_Library library = qt_getFreetype();
899 info.xOff = TRUNC(ROUND(slot->advance.x));
902 uchar *glyph_buffer = 0;
903 int glyph_buffer_size = 0;
904 #if defined(QT_USE_FREETYPE_LCDFILTER)
905 bool useFreetypeRenderGlyph = false;
906 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
907 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
908 if (err == FT_Err_Ok)
909 useFreetypeRenderGlyph = true;
912 if (useFreetypeRenderGlyph) {
913 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
915 if (err != FT_Err_Ok)
916 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
918 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
920 info.height = slot->bitmap.rows / vfactor;
921 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
922 info.x = -slot->bitmap_left;
923 info.y = slot->bitmap_top;
925 glyph_buffer_size = info.width * info.height * 4;
926 glyph_buffer = new uchar[glyph_buffer_size];
929 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
930 else if (vfactor != 1)
931 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
935 int left = slot->metrics.horiBearingX;
936 int right = slot->metrics.horiBearingX + slot->metrics.width;
937 int top = slot->metrics.horiBearingY;
938 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
939 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
944 FT_Vector_Transform(&vector, &matrix);
949 FT_Vector_Transform(&vector, &matrix);
950 if (l > vector.x) l = vector.x;
951 if (r < vector.x) r = vector.x;
952 if (t < vector.y) t = vector.y;
953 if (b > vector.y) b = vector.y;
956 FT_Vector_Transform(&vector, &matrix);
957 if (l > vector.x) l = vector.x;
958 if (r < vector.x) r = vector.x;
959 if (t < vector.y) t = vector.y;
960 if (b > vector.y) b = vector.y;
963 FT_Vector_Transform(&vector, &matrix);
964 if (l > vector.x) l = vector.x;
965 if (r < vector.x) r = vector.x;
966 if (t < vector.y) t = vector.y;
967 if (b > vector.y) b = vector.y;
975 bottom = FLOOR(bottom);
978 int hpixels = TRUNC(right - left);
979 // subpixel position requires one more pixel
980 if (subPixelPosition > 0 && format != Format_Mono)
984 hpixels = hpixels*3 + 8;
985 info.width = hpixels;
986 info.height = TRUNC(top - bottom);
987 info.x = -TRUNC(left);
994 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
995 || ((uchar)(info.width) != info.width)
996 || ((uchar)(info.height) != info.height)
997 || ((signed char)(info.x) != info.x)
998 || ((signed char)(info.y) != info.y)
999 || ((signed char)(info.xOff) != info.xOff));
1002 delete [] glyph_buffer;
1006 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1007 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1008 glyph_buffer_size = pitch * info.height;
1009 glyph_buffer = new uchar[glyph_buffer_size];
1011 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1013 bitmap.rows = info.height*vfactor;
1014 bitmap.width = hpixels;
1015 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1016 if (!hsubpixel && vfactor == 1)
1017 bitmap.buffer = glyph_buffer;
1019 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1020 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1021 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1023 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1024 matrix.yy = vfactor << 16;
1025 matrix.yx = matrix.xy = 0;
1027 FT_Outline_Transform(&slot->outline, &matrix);
1028 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1029 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1031 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1032 Q_ASSERT(antialias);
1033 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1034 bool useLegacyLcdFilter = false;
1035 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1036 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1038 uchar *buffer = bitmap.buffer;
1039 if (!useLegacyLcdFilter) {
1040 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1041 buffer = convoluted;
1043 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1044 delete [] convoluted;
1045 } else if (vfactor != 1) {
1046 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1049 if (bitmap.buffer != glyph_buffer)
1050 delete [] bitmap.buffer;
1051 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1052 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1053 uchar *src = slot->bitmap.buffer;
1054 uchar *dst = glyph_buffer;
1055 int h = slot->bitmap.rows;
1056 if (format == Format_Mono) {
1057 int bytes = ((info.width + 7) & ~7) >> 3;
1059 memcpy (dst, src, bytes);
1061 src += slot->bitmap.pitch;
1066 uint *dd = (uint *)dst;
1068 for (int x = 0; x < slot->bitmap.width; x++) {
1069 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1074 src += slot->bitmap.pitch;
1076 } else if (vfactor != 1) {
1078 uint *dd = (uint *)dst;
1079 for (int x = 0; x < slot->bitmap.width; x++) {
1080 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1084 src += slot->bitmap.pitch;
1088 for (int x = 0; x < slot->bitmap.width; x++) {
1089 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1093 src += slot->bitmap.pitch;
1098 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1099 delete [] glyph_buffer;
1110 g->linearAdvance = slot->linearHoriAdvance >> 10;
1111 g->width = info.width;
1112 g->height = info.height;
1115 g->advance = info.xOff;
1118 g->data = glyph_buffer;
1121 set->setGlyph(glyph, subPixelPosition, g);
1126 QFontEngine::FaceId QFontEngineFT::faceId() const
1131 QFontEngine::Properties QFontEngineFT::properties() const
1133 Properties p = freetype->properties();
1134 if (p.postscriptName.isEmpty()) {
1135 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1138 return freetype->properties();
1141 QFixed QFontEngineFT::emSquareSize() const
1143 if (FT_IS_SCALABLE(freetype->face))
1144 return freetype->face->units_per_EM;
1146 return freetype->face->size->metrics.y_ppem;
1149 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1151 return freetype->getSfntTable(tag, buffer, length);
1154 int QFontEngineFT::synthesized() const
1157 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1158 s = SynthesizedItalic;
1159 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1160 s |= SynthesizedBold;
1161 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1162 s |= SynthesizedStretch;
1166 QFixed QFontEngineFT::ascent() const
1168 return QFixed::fromFixed(metrics.ascender);
1171 QFixed QFontEngineFT::descent() const
1173 // subtract a pixel to work around QFontMetrics's built-in + 1
1174 return QFixed::fromFixed(-metrics.descender - 64);
1177 QFixed QFontEngineFT::leading() const
1179 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1182 QFixed QFontEngineFT::xHeight() const
1184 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1185 if (os2 && os2->sxHeight) {
1187 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1191 return QFontEngine::xHeight();
1194 QFixed QFontEngineFT::averageCharWidth() const
1196 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1197 if (os2 && os2->xAvgCharWidth) {
1199 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1203 return QFontEngine::averageCharWidth();
1206 qreal QFontEngineFT::maxCharWidth() const
1208 return metrics.max_advance >> 6;
1211 static const ushort char_table[] = {
1232 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1235 qreal QFontEngineFT::minLeftBearing() const
1237 if (lbearing == SHRT_MIN)
1238 (void) minRightBearing(); // calculates both
1239 return lbearing.toReal();
1242 qreal QFontEngineFT::minRightBearing() const
1244 if (rbearing == SHRT_MIN) {
1245 lbearing = rbearing = 0;
1246 const QChar *ch = (const QChar *)(const void*)char_table;
1247 QGlyphLayoutArray<char_table_entries> glyphs;
1248 int ng = char_table_entries;
1249 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1251 if (glyphs.glyphs[ng]) {
1252 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1253 lbearing = qMin(lbearing, gi.x);
1254 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1258 return rbearing.toReal();
1261 QFixed QFontEngineFT::lineThickness() const
1263 return line_thickness;
1266 QFixed QFontEngineFT::underlinePosition() const
1268 return underline_position;
1271 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1273 if (!kerning_pairs_loaded) {
1274 kerning_pairs_loaded = true;
1276 if (freetype->face->size->metrics.x_ppem != 0) {
1277 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1279 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1284 QFontEngine::doKerning(g, flags);
1287 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1289 if (matrix.type() > QTransform::TxShear)
1292 // FT_Set_Transform only supports scalable fonts
1293 if (!FT_IS_SCALABLE(freetype->face))
1297 m.xx = FT_Fixed(matrix.m11() * 65536);
1298 m.xy = FT_Fixed(-matrix.m21() * 65536);
1299 m.yx = FT_Fixed(-matrix.m12() * 65536);
1300 m.yy = FT_Fixed(matrix.m22() * 65536);
1304 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1305 const QGlyphSet &g = transformedGlyphSets.at(i);
1306 if (g.transformationMatrix.xx == m.xx
1307 && g.transformationMatrix.xy == m.xy
1308 && g.transformationMatrix.yx == m.yx
1309 && g.transformationMatrix.yy == m.yy) {
1311 // found a match, move it to the front
1312 transformedGlyphSets.move(i, 0);
1313 gs = &transformedGlyphSets[0];
1319 // don't try to load huge fonts
1320 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1321 if (draw_as_outline)
1324 // don't cache more than 10 transformations
1325 if (transformedGlyphSets.count() >= 10) {
1326 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1328 transformedGlyphSets.prepend(QGlyphSet());
1330 gs = &transformedGlyphSets[0];
1332 gs->transformationMatrix = m;
1333 gs->outline_drawing = draw_as_outline;
1339 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1340 const QFixedPoint *positions,
1345 for (int i = 0; i < num_glyphs; ++i) {
1346 QFixed spp = subPixelPositionForX(positions[i].x);
1347 Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1348 if (glyph == 0 || glyph->format != format) {
1351 FT_Matrix m = matrix;
1352 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1353 FT_Set_Transform(face, &m, 0);
1354 freetype->matrix = m;
1356 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1369 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1371 FT_Face face = lockFace(Unscaled);
1372 FT_Set_Transform(face, 0, 0);
1373 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1375 int left = face->glyph->metrics.horiBearingX;
1376 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1377 int top = face->glyph->metrics.horiBearingY;
1378 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1384 metrics->width = QFixed::fromFixed(right-left);
1385 metrics->height = QFixed::fromFixed(top-bottom);
1386 metrics->x = QFixed::fromFixed(left);
1387 metrics->y = QFixed::fromFixed(-top);
1388 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1390 if (!FT_IS_SCALABLE(freetype->face))
1391 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1393 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1395 FT_Set_Transform(face, &freetype->matrix, 0);
1399 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1401 uint ucs4 = str[i].unicode();
1402 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1404 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1409 bool QFontEngineFT::canRender(const QChar *string, int len)
1411 FT_Face face = freetype->face;
1415 for ( int i = 0; i < len; i++ ) {
1416 unsigned int uc = getChar(string, i, len);
1417 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1426 for ( int i = 0; i < len; i++ ) {
1427 unsigned int uc = getChar(string, i, len);
1428 if (!FT_Get_Char_Index(face, uc))
1435 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1437 if (!glyphs.numGlyphs)
1440 if (FT_IS_SCALABLE(freetype->face)) {
1441 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1443 QVarLengthArray<QFixedPoint> positions;
1444 QVarLengthArray<glyph_t> positioned_glyphs;
1446 matrix.translate(x, y);
1447 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1449 FT_Face face = lockFace(Unscaled);
1450 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1451 FT_UInt glyph = positioned_glyphs[gl];
1452 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1453 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1459 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1460 QPainterPath *path, QTextItem::RenderFlags)
1462 FT_Face face = lockFace(Unscaled);
1464 for (int gl = 0; gl < numGlyphs; gl++) {
1465 FT_UInt glyph = glyphs[gl];
1467 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1469 FT_GlyphSlot g = face->glyph;
1470 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1472 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1473 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1474 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1479 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1480 QTextEngine::ShaperFlags flags) const
1482 if (*nglyphs < len) {
1487 #if !defined(QT_NO_FONTCONFIG)
1488 extern QMutex *qt_fontdatabase_mutex();
1492 bool mirrored = flags & QTextEngine::RightToLeft;
1494 if (freetype->symbol_map) {
1495 FT_Face face = freetype->face;
1496 for ( int i = 0; i < len; ++i ) {
1497 unsigned int uc = getChar(str, i, len);
1498 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1499 if ( !glyphs->glyphs[glyph_pos] ) {
1501 #if !defined(QT_NO_FONTCONFIG)
1503 mtx = qt_fontdatabase_mutex();
1507 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1512 glyph = FT_Get_Char_Index(face, uc);
1513 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1518 FT_Set_Charmap(face, freetype->symbol_map);
1519 glyph = FT_Get_Char_Index(face, uc);
1520 FT_Set_Charmap(face, freetype->unicode_map);
1522 glyphs->glyphs[glyph_pos] = glyph;
1523 if (uc < QFreetypeFace::cmapCacheSize)
1524 freetype->cmapCache[uc] = glyph;
1529 FT_Face face = freetype->face;
1530 for (int i = 0; i < len; ++i) {
1531 unsigned int uc = getChar(str, i, len);
1533 uc = QChar::mirroredChar(uc);
1534 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1535 if (!glyphs->glyphs[glyph_pos]) {
1536 #if !defined(QT_NO_FONTCONFIG)
1538 mtx = qt_fontdatabase_mutex();
1542 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1546 glyph_t glyph = FT_Get_Char_Index(face, uc);
1547 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1551 glyphs->glyphs[glyph_pos] = glyph;
1552 if (uc < QFreetypeFace::cmapCacheSize)
1553 freetype->cmapCache[uc] = glyph;
1560 *nglyphs = glyph_pos;
1561 glyphs->numGlyphs = glyph_pos;
1563 #if !defined(QT_NO_FONTCONFIG)
1568 if (flags & QTextEngine::GlyphIndicesOnly)
1571 recalcAdvances(glyphs, flags);
1576 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1579 bool design = (default_hint_style == HintNone ||
1580 default_hint_style == HintLight ||
1581 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1582 for (int i = 0; i < glyphs->numGlyphs; i++) {
1583 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1585 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1589 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1590 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1591 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1593 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1594 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1595 glyphs->advances_y[i] = 0;
1601 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1605 glyph_metrics_t overall;
1606 // initialize with line height, we get the same behaviour on all platforms
1607 overall.y = -ascent();
1608 overall.height = ascent() + descent() + 1;
1612 for (int i = 0; i < glyphs.numGlyphs; i++) {
1613 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1617 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1620 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1621 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1622 overall.x = qMin(overall.x, x);
1623 overall.y = qMin(overall.y, y);
1624 xmax = qMax(xmax, x + g->width);
1625 ymax = qMax(ymax, y + g->height);
1626 overall.xoff += g->advance;
1628 int left = FLOOR(face->glyph->metrics.horiBearingX);
1629 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1630 int top = CEIL(face->glyph->metrics.horiBearingY);
1631 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1633 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1634 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1635 overall.x = qMin(overall.x, x);
1636 overall.y = qMin(overall.y, y);
1637 xmax = qMax(xmax, x + TRUNC(right - left));
1638 ymax = qMax(ymax, y + TRUNC(top - bottom));
1639 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1642 overall.height = qMax(overall.height, ymax - overall.y);
1643 overall.width = xmax - overall.x;
1651 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1654 glyph_metrics_t overall;
1655 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1658 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1663 overall.width = g->width;
1664 overall.height = g->height;
1665 overall.xoff = g->advance;
1666 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1667 overall.xoff = overall.xoff.round();
1669 int left = FLOOR(face->glyph->metrics.horiBearingX);
1670 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1671 int top = CEIL(face->glyph->metrics.horiBearingY);
1672 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1674 overall.width = TRUNC(right-left);
1675 overall.height = TRUNC(top-bottom);
1676 overall.x = TRUNC(left);
1677 overall.y = -TRUNC(top);
1678 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1685 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1687 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1690 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1694 m.xx = FT_Fixed(matrix.m11() * 65536);
1695 m.xy = FT_Fixed(-matrix.m21() * 65536);
1696 m.yx = FT_Fixed(-matrix.m12() * 65536);
1697 m.yy = FT_Fixed(matrix.m22() * 65536);
1702 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1705 glyph_metrics_t overall;
1706 QGlyphSet *glyphSet = 0;
1707 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1709 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1710 // TODO move everything here to a method of its own to access glyphSets
1711 // to be shared with a new method that will replace loadTransformedGlyphSet()
1712 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1713 const QGlyphSet &g = transformedGlyphSets.at(i);
1714 if (g.transformationMatrix.xx == ftMatrix.xx
1715 && g.transformationMatrix.xy == ftMatrix.xy
1716 && g.transformationMatrix.yx == ftMatrix.yx
1717 && g.transformationMatrix.yy == ftMatrix.yy) {
1719 // found a match, move it to the front
1720 transformedGlyphSets.move(i, 0);
1721 glyphSet = &transformedGlyphSets[0];
1727 // don't cache more than 10 transformations
1728 if (transformedGlyphSets.count() >= 10) {
1729 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1731 transformedGlyphSets.prepend(QGlyphSet());
1733 glyphSet = &transformedGlyphSets[0];
1735 glyphSet->transformationMatrix = ftMatrix;
1739 glyphSet = &defaultGlyphSet;
1742 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1743 if (!g || g->format != format) {
1745 FT_Matrix m = this->matrix;
1746 FT_Matrix_Multiply(&ftMatrix, &m);
1747 freetype->matrix = m;
1748 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1754 overall.width = g->width;
1755 overall.height = g->height;
1756 overall.xoff = g->advance;
1758 int left = FLOOR(face->glyph->metrics.horiBearingX);
1759 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1760 int top = CEIL(face->glyph->metrics.horiBearingY);
1761 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1763 overall.width = TRUNC(right-left);
1764 overall.height = TRUNC(top-bottom);
1765 overall.x = TRUNC(left);
1766 overall.y = -TRUNC(top);
1767 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1774 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1775 QFontEngine::GlyphFormat neededFormat,
1776 const QTransform &t, QPoint *offset)
1778 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1782 neededFormat = Format_Mono;
1783 else if (neededFormat == Format_None && defaultFormat != Format_None)
1784 neededFormat = defaultFormat;
1785 else if (neededFormat == Format_None)
1786 neededFormat = Format_A8;
1788 QImage::Format format;
1789 switch (neededFormat) {
1791 format = QImage::Format_Mono;
1794 format = QImage::Format_Indexed8;
1797 format = QImage::Format_ARGB32;
1801 format = QImage::Format_Invalid;
1804 QFontEngineFT::Glyph *glyph;
1806 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1807 if (t.type() >= QTransform::TxScale) {
1809 gset = loadTransformedGlyphSet(t);
1815 FT_Matrix m = matrix;
1816 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1817 FT_Set_Transform(freetype->face, &m, 0);
1818 freetype->matrix = m;
1821 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1823 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1827 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1829 FT_Matrix m = matrix;
1830 FT_Matrix extra = QTransformToFTMatrix(t);
1831 FT_Matrix_Multiply(&extra, &m);
1832 FT_Set_Transform(freetype->face, &m, 0);
1833 freetype->matrix = m;
1834 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1837 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1843 switch (neededFormat) {
1845 pitch = ((glyph->width + 31) & ~31) >> 3;
1848 pitch = (glyph->width + 3) & ~3;
1851 pitch = glyph->width * 4;
1859 *offset = QPoint(glyph->x, -glyph->y);
1861 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1862 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1864 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1865 data->is_locked = true;
1867 return ¤tlyLockedAlphaMap;
1870 void QFontEngineFT::unlockAlphaMapForGlyph()
1872 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1874 currentlyLockedAlphaMap = QImage();
1877 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1879 return defaultGlyphSet.outline_drawing ? 0 :
1880 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1883 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1887 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1890 return QFontEngine::alphaMapForGlyph(g);
1893 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1895 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1897 QVector<QRgb> colors(256);
1898 for (int i=0; i<256; ++i)
1899 colors[i] = qRgba(0, 0, 0, i);
1900 img.setColorTable(colors);
1902 QVector<QRgb> colors(2);
1903 colors[0] = qRgba(0, 0, 0, 0);
1904 colors[1] = qRgba(0, 0, 0, 255);
1905 img.setColorTable(colors);
1907 Q_ASSERT(img.bytesPerLine() == pitch);
1909 for (int y = 0; y < glyph->height; ++y)
1910 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1917 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1919 if (t.type() > QTransform::TxTranslate)
1920 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1924 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1927 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1930 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1931 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1937 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1939 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1942 int QFontEngineFT::glyphCount() const
1945 FT_Face face = lockFace();
1947 count = face->num_glyphs;
1953 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1956 FT_Face face = freetype->face;
1957 if (scale == Unscaled) {
1958 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1959 freetype->xsize = face->units_per_EM << 6;
1960 freetype->ysize = face->units_per_EM << 6;
1961 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1962 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1963 freetype->xsize = xsize;
1964 freetype->ysize = ysize;
1966 if (freetype->matrix.xx != matrix.xx ||
1967 freetype->matrix.yy != matrix.yy ||
1968 freetype->matrix.xy != matrix.xy ||
1969 freetype->matrix.yx != matrix.yx) {
1970 freetype->matrix = matrix;
1971 FT_Set_Transform(face, &freetype->matrix, 0);
1977 void QFontEngineFT::unlockFace() const
1982 FT_Face QFontEngineFT::non_locked_face() const
1984 return freetype->face;
1988 QFontEngineFT::QGlyphSet::QGlyphSet()
1989 : outline_drawing(false)
1991 transformationMatrix.xx = 0x10000;
1992 transformationMatrix.yy = 0x10000;
1993 transformationMatrix.xy = 0;
1994 transformationMatrix.yx = 0;
1995 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1996 fast_glyph_count = 0;
1999 QFontEngineFT::QGlyphSet::~QGlyphSet()
2004 void QFontEngineFT::QGlyphSet::clear()
2006 if (fast_glyph_count > 0) {
2007 for (int i = 0; i < 256; ++i) {
2008 if (fast_glyph_data[i]) {
2009 delete fast_glyph_data[i];
2010 fast_glyph_data[i] = 0;
2013 fast_glyph_count = 0;
2015 qDeleteAll(glyph_data);
2019 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2021 if (useFastGlyphData(index, subPixelPosition)) {
2022 if (fast_glyph_data[index]) {
2023 delete fast_glyph_data[index];
2024 fast_glyph_data[index] = 0;
2025 if (fast_glyph_count > 0)
2029 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2033 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2035 if (useFastGlyphData(index, subPixelPosition)) {
2036 if (!fast_glyph_data[index])
2038 fast_glyph_data[index] = glyph;
2040 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2044 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2047 bool hsubpixel = true;
2049 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2050 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2055 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2057 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2060 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2062 freetype->ref.ref();
2064 default_load_flags = fe->default_load_flags;
2065 default_hint_style = fe->default_hint_style;
2066 antialias = fe->antialias;
2067 transform = fe->transform;
2068 embolden = fe->embolden;
2069 obliquen = fe->obliquen;
2070 subpixelType = fe->subpixelType;
2071 lcdFilterType = fe->lcdFilterType;
2072 embeddedbitmap = fe->embeddedbitmap;
2077 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2080 fontDef.pixelSize = pixelSize;
2081 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2082 if (!fe->initFromFontEngine(this)) {
2092 #endif // QT_NO_FREETYPE