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;
660 m_subPixelPositionCount = 4;
663 QFontEngineFT::~QFontEngineFT()
666 freetype->release(face_id);
667 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
670 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
671 const QByteArray &fontData)
673 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
676 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
677 QFreetypeFace *freetypeFace)
679 freetype = freetypeFace;
685 defaultFormat = format;
686 this->antialias = antialias;
689 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
690 else if (format == Format_A8)
691 glyphFormat = QFontEngineGlyphCache::Raster_A8;
692 else if (format == Format_A32)
693 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
697 symbol = freetype->symbol_map != 0;
698 PS_FontInfoRec psrec;
699 // don't assume that type1 fonts are symbol fonts by default
700 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
701 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
704 freetype->hbFace->isSymbolFont = symbol;
706 lbearing = rbearing = SHRT_MIN;
707 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
709 FT_Face face = lockFace();
711 if (FT_IS_SCALABLE(face)) {
712 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
714 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
715 matrix.xy = 0x10000*3/10;
721 FT_Set_Transform(face, &matrix, 0);
722 freetype->matrix = matrix;
724 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
727 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
728 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
730 // copied from QFontEngineQPF
732 int score = fontDef.weight * fontDef.pixelSize;
733 line_thickness = score / 700;
734 // looks better with thicker line for small pointsizes
735 if (line_thickness < 2 && score >= 1050)
737 underline_position = ((line_thickness * 2) + 3) / 6;
739 if (line_thickness < 1)
742 hbFont.x_ppem = face->size->metrics.x_ppem;
743 hbFont.y_ppem = face->size->metrics.y_ppem;
744 hbFont.x_scale = face->size->metrics.x_scale;
745 hbFont.y_scale = face->size->metrics.y_scale;
747 hbFace = freetype->hbFace;
749 metrics = face->size->metrics;
752 TrueType fonts with embedded bitmaps may have a bitmap font specific
753 ascent/descent in the EBLC table. There is no direct public API
754 to extract those values. The only way we've found is to trick freetype
755 into thinking that it's not a scalable font in FT_SelectSize so that
756 the metrics are retrieved from the bitmap strikes.
758 if (FT_IS_SCALABLE(face)) {
759 for (int i = 0; i < face->num_fixed_sizes; ++i) {
760 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
761 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
763 FT_Select_Size(face, i);
764 metrics.ascender = face->size->metrics.ascender;
765 metrics.descender = face->size->metrics.descender;
766 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
768 face->face_flags |= FT_FACE_FLAG_SCALABLE;
774 fontDef.styleName = QString::fromUtf8(face->style_name);
778 fsType = freetype->fsType();
782 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
784 default_hint_style = style;
787 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
788 bool &hsubpixel, int &vfactor) const
790 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
791 int load_target = default_hint_style == HintLight
792 ? FT_LOAD_TARGET_LIGHT
793 : FT_LOAD_TARGET_NORMAL;
795 if (format == Format_Mono) {
796 load_target = FT_LOAD_TARGET_MONO;
797 } else if (format == Format_A32) {
798 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
799 if (default_hint_style == HintFull)
800 load_target = FT_LOAD_TARGET_LCD;
802 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
803 if (default_hint_style == HintFull)
804 load_target = FT_LOAD_TARGET_LCD_V;
809 if (set && set->outline_drawing)
810 load_flags = FT_LOAD_NO_BITMAP;
812 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
813 load_flags |= FT_LOAD_NO_HINTING;
815 load_flags |= load_target;
820 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
821 QFixed subPixelPosition,
823 bool fetchMetricsOnly) const
825 // Q_ASSERT(freetype->lock == 1);
827 if (format == Format_None) {
828 if (defaultFormat != Format_None) {
829 format = defaultFormat;
831 format = Format_Mono;
835 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
836 if (g && g->format == format)
839 QFontEngineFT::GlyphInfo info;
841 Q_ASSERT(format != Format_None);
842 bool hsubpixel = false;
844 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
846 if (format != Format_Mono && !embeddedbitmap)
847 load_flags |= FT_LOAD_NO_BITMAP;
849 FT_Matrix matrix = freetype->matrix;
850 bool transform = matrix.xx != 0x10000
851 || matrix.yy != 0x10000
856 load_flags |= FT_LOAD_NO_BITMAP;
858 FT_Face face = freetype->face;
861 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
863 FT_Set_Transform(face, &freetype->matrix, &v);
865 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
866 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
867 load_flags &= ~FT_LOAD_NO_BITMAP;
868 err = FT_Load_Glyph(face, glyph, load_flags);
870 if (err == FT_Err_Too_Few_Arguments) {
871 // this is an error in the bytecode interpreter, just try to run without it
872 load_flags |= FT_LOAD_FORCE_AUTOHINT;
873 err = FT_Load_Glyph(face, glyph, load_flags);
875 if (err != FT_Err_Ok)
876 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
878 if ((!set || set->outline_drawing) && fetchMetricsOnly)
881 FT_GlyphSlot slot = face->glyph;
882 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
884 Q_FT_GLYPHSLOT_OBLIQUE(slot);
886 // While Embolden alters the metrics of the slot, oblique does not, so we need
887 // to fix this ourselves.
895 FT_Matrix_Multiply(&m, &matrix);
898 FT_Library library = qt_getFreetype();
900 info.xOff = TRUNC(ROUND(slot->advance.x));
903 uchar *glyph_buffer = 0;
904 int glyph_buffer_size = 0;
905 #if defined(QT_USE_FREETYPE_LCDFILTER)
906 bool useFreetypeRenderGlyph = false;
907 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
908 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
909 if (err == FT_Err_Ok)
910 useFreetypeRenderGlyph = true;
913 if (useFreetypeRenderGlyph) {
914 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
916 if (err != FT_Err_Ok)
917 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
919 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
921 info.height = slot->bitmap.rows / vfactor;
922 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
923 info.x = -slot->bitmap_left;
924 info.y = slot->bitmap_top;
926 glyph_buffer_size = info.width * info.height * 4;
927 glyph_buffer = new uchar[glyph_buffer_size];
930 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
931 else if (vfactor != 1)
932 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
936 int left = slot->metrics.horiBearingX;
937 int right = slot->metrics.horiBearingX + slot->metrics.width;
938 int top = slot->metrics.horiBearingY;
939 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
940 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
945 FT_Vector_Transform(&vector, &matrix);
950 FT_Vector_Transform(&vector, &matrix);
951 if (l > vector.x) l = vector.x;
952 if (r < vector.x) r = vector.x;
953 if (t < vector.y) t = vector.y;
954 if (b > vector.y) b = vector.y;
957 FT_Vector_Transform(&vector, &matrix);
958 if (l > vector.x) l = vector.x;
959 if (r < vector.x) r = vector.x;
960 if (t < vector.y) t = vector.y;
961 if (b > vector.y) b = vector.y;
964 FT_Vector_Transform(&vector, &matrix);
965 if (l > vector.x) l = vector.x;
966 if (r < vector.x) r = vector.x;
967 if (t < vector.y) t = vector.y;
968 if (b > vector.y) b = vector.y;
976 bottom = FLOOR(bottom);
979 int hpixels = TRUNC(right - left);
980 // subpixel position requires one more pixel
981 if (subPixelPosition > 0 && format != Format_Mono)
985 hpixels = hpixels*3 + 8;
986 info.width = hpixels;
987 info.height = TRUNC(top - bottom);
988 info.x = -TRUNC(left);
995 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
996 || ((uchar)(info.width) != info.width)
997 || ((uchar)(info.height) != info.height)
998 || ((signed char)(info.x) != info.x)
999 || ((signed char)(info.y) != info.y)
1000 || ((signed char)(info.xOff) != info.xOff));
1003 delete [] glyph_buffer;
1007 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1008 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1009 glyph_buffer_size = pitch * info.height;
1010 glyph_buffer = new uchar[glyph_buffer_size];
1012 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1014 bitmap.rows = info.height*vfactor;
1015 bitmap.width = hpixels;
1016 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1017 if (!hsubpixel && vfactor == 1)
1018 bitmap.buffer = glyph_buffer;
1020 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1021 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1022 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1024 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1025 matrix.yy = vfactor << 16;
1026 matrix.yx = matrix.xy = 0;
1028 FT_Outline_Transform(&slot->outline, &matrix);
1029 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1030 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1032 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1033 Q_ASSERT(antialias);
1034 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1035 bool useLegacyLcdFilter = false;
1036 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1037 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1039 uchar *buffer = bitmap.buffer;
1040 if (!useLegacyLcdFilter) {
1041 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1042 buffer = convoluted;
1044 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1045 delete [] convoluted;
1046 } else if (vfactor != 1) {
1047 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1050 if (bitmap.buffer != glyph_buffer)
1051 delete [] bitmap.buffer;
1052 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1053 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1054 uchar *src = slot->bitmap.buffer;
1055 uchar *dst = glyph_buffer;
1056 int h = slot->bitmap.rows;
1057 if (format == Format_Mono) {
1058 int bytes = ((info.width + 7) & ~7) >> 3;
1060 memcpy (dst, src, bytes);
1062 src += slot->bitmap.pitch;
1067 uint *dd = (uint *)dst;
1069 for (int x = 0; x < slot->bitmap.width; x++) {
1070 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1075 src += slot->bitmap.pitch;
1077 } else if (vfactor != 1) {
1079 uint *dd = (uint *)dst;
1080 for (int x = 0; x < slot->bitmap.width; x++) {
1081 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1085 src += slot->bitmap.pitch;
1089 for (int x = 0; x < slot->bitmap.width; x++) {
1090 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1094 src += slot->bitmap.pitch;
1099 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1100 delete [] glyph_buffer;
1111 g->linearAdvance = slot->linearHoriAdvance >> 10;
1112 g->width = info.width;
1113 g->height = info.height;
1116 g->advance = info.xOff;
1119 g->data = glyph_buffer;
1122 set->setGlyph(glyph, subPixelPosition, g);
1127 QFontEngine::FaceId QFontEngineFT::faceId() const
1132 QFontEngine::Properties QFontEngineFT::properties() const
1134 Properties p = freetype->properties();
1135 if (p.postscriptName.isEmpty()) {
1136 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1139 return freetype->properties();
1142 QFixed QFontEngineFT::emSquareSize() const
1144 if (FT_IS_SCALABLE(freetype->face))
1145 return freetype->face->units_per_EM;
1147 return freetype->face->size->metrics.y_ppem;
1150 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1152 return freetype->getSfntTable(tag, buffer, length);
1155 int QFontEngineFT::synthesized() const
1158 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1159 s = SynthesizedItalic;
1160 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1161 s |= SynthesizedBold;
1162 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1163 s |= SynthesizedStretch;
1167 QFixed QFontEngineFT::ascent() const
1169 return QFixed::fromFixed(metrics.ascender);
1172 QFixed QFontEngineFT::descent() const
1174 // subtract a pixel to work around QFontMetrics's built-in + 1
1175 return QFixed::fromFixed(-metrics.descender - 64);
1178 QFixed QFontEngineFT::leading() const
1180 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1183 QFixed QFontEngineFT::xHeight() const
1185 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1186 if (os2 && os2->sxHeight) {
1188 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1192 return QFontEngine::xHeight();
1195 QFixed QFontEngineFT::averageCharWidth() const
1197 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1198 if (os2 && os2->xAvgCharWidth) {
1200 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1204 return QFontEngine::averageCharWidth();
1207 qreal QFontEngineFT::maxCharWidth() const
1209 return metrics.max_advance >> 6;
1212 static const ushort char_table[] = {
1233 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1236 qreal QFontEngineFT::minLeftBearing() const
1238 if (lbearing == SHRT_MIN)
1239 (void) minRightBearing(); // calculates both
1240 return lbearing.toReal();
1243 qreal QFontEngineFT::minRightBearing() const
1245 if (rbearing == SHRT_MIN) {
1246 lbearing = rbearing = 0;
1247 const QChar *ch = (const QChar *)(const void*)char_table;
1248 QGlyphLayoutArray<char_table_entries> glyphs;
1249 int ng = char_table_entries;
1250 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1252 if (glyphs.glyphs[ng]) {
1253 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1254 lbearing = qMin(lbearing, gi.x);
1255 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1259 return rbearing.toReal();
1262 QFixed QFontEngineFT::lineThickness() const
1264 return line_thickness;
1267 QFixed QFontEngineFT::underlinePosition() const
1269 return underline_position;
1272 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1274 if (!kerning_pairs_loaded) {
1275 kerning_pairs_loaded = true;
1277 if (freetype->face->size->metrics.x_ppem != 0) {
1278 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1280 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1285 QFontEngine::doKerning(g, flags);
1288 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1290 if (matrix.type() > QTransform::TxShear)
1293 // FT_Set_Transform only supports scalable fonts
1294 if (!FT_IS_SCALABLE(freetype->face))
1298 m.xx = FT_Fixed(matrix.m11() * 65536);
1299 m.xy = FT_Fixed(-matrix.m21() * 65536);
1300 m.yx = FT_Fixed(-matrix.m12() * 65536);
1301 m.yy = FT_Fixed(matrix.m22() * 65536);
1305 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1306 const QGlyphSet &g = transformedGlyphSets.at(i);
1307 if (g.transformationMatrix.xx == m.xx
1308 && g.transformationMatrix.xy == m.xy
1309 && g.transformationMatrix.yx == m.yx
1310 && g.transformationMatrix.yy == m.yy) {
1312 // found a match, move it to the front
1313 transformedGlyphSets.move(i, 0);
1314 gs = &transformedGlyphSets[0];
1320 // don't try to load huge fonts
1321 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1322 if (draw_as_outline)
1325 // don't cache more than 10 transformations
1326 if (transformedGlyphSets.count() >= 10) {
1327 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1329 transformedGlyphSets.prepend(QGlyphSet());
1331 gs = &transformedGlyphSets[0];
1333 gs->transformationMatrix = m;
1334 gs->outline_drawing = draw_as_outline;
1340 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1341 const QFixedPoint *positions,
1346 for (int i = 0; i < num_glyphs; ++i) {
1347 QFixed spp = subPixelPositionForX(positions[i].x);
1348 Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1349 if (glyph == 0 || glyph->format != format) {
1352 FT_Matrix m = matrix;
1353 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1354 FT_Set_Transform(face, &m, 0);
1355 freetype->matrix = m;
1357 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1370 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1372 FT_Face face = lockFace(Unscaled);
1373 FT_Set_Transform(face, 0, 0);
1374 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1376 int left = face->glyph->metrics.horiBearingX;
1377 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1378 int top = face->glyph->metrics.horiBearingY;
1379 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1385 metrics->width = QFixed::fromFixed(right-left);
1386 metrics->height = QFixed::fromFixed(top-bottom);
1387 metrics->x = QFixed::fromFixed(left);
1388 metrics->y = QFixed::fromFixed(-top);
1389 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1391 if (!FT_IS_SCALABLE(freetype->face))
1392 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1394 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1396 FT_Set_Transform(face, &freetype->matrix, 0);
1400 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1402 uint ucs4 = str[i].unicode();
1403 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1405 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1410 bool QFontEngineFT::canRender(const QChar *string, int len)
1412 FT_Face face = freetype->face;
1416 for ( int i = 0; i < len; i++ ) {
1417 unsigned int uc = getChar(string, i, len);
1418 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1427 for ( int i = 0; i < len; i++ ) {
1428 unsigned int uc = getChar(string, i, len);
1429 if (!FT_Get_Char_Index(face, uc))
1436 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1438 if (!glyphs.numGlyphs)
1441 if (FT_IS_SCALABLE(freetype->face)) {
1442 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1444 QVarLengthArray<QFixedPoint> positions;
1445 QVarLengthArray<glyph_t> positioned_glyphs;
1447 matrix.translate(x, y);
1448 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1450 FT_Face face = lockFace(Unscaled);
1451 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1452 FT_UInt glyph = positioned_glyphs[gl];
1453 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1454 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1460 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1461 QPainterPath *path, QTextItem::RenderFlags)
1463 FT_Face face = lockFace(Unscaled);
1465 for (int gl = 0; gl < numGlyphs; gl++) {
1466 FT_UInt glyph = glyphs[gl];
1468 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1470 FT_GlyphSlot g = face->glyph;
1471 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1473 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1474 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1475 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1480 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1481 QTextEngine::ShaperFlags flags) const
1483 if (*nglyphs < len) {
1488 #if !defined(QT_NO_FONTCONFIG)
1489 extern QMutex *qt_fontdatabase_mutex();
1493 bool mirrored = flags & QTextEngine::RightToLeft;
1495 if (freetype->symbol_map) {
1496 FT_Face face = freetype->face;
1497 for ( int i = 0; i < len; ++i ) {
1498 unsigned int uc = getChar(str, i, len);
1499 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1500 if ( !glyphs->glyphs[glyph_pos] ) {
1502 #if !defined(QT_NO_FONTCONFIG)
1504 mtx = qt_fontdatabase_mutex();
1508 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1513 glyph = FT_Get_Char_Index(face, uc);
1514 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1519 FT_Set_Charmap(face, freetype->symbol_map);
1520 glyph = FT_Get_Char_Index(face, uc);
1521 FT_Set_Charmap(face, freetype->unicode_map);
1523 glyphs->glyphs[glyph_pos] = glyph;
1524 if (uc < QFreetypeFace::cmapCacheSize)
1525 freetype->cmapCache[uc] = glyph;
1530 FT_Face face = freetype->face;
1531 for (int i = 0; i < len; ++i) {
1532 unsigned int uc = getChar(str, i, len);
1534 uc = QChar::mirroredChar(uc);
1535 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1536 if (!glyphs->glyphs[glyph_pos]) {
1537 #if !defined(QT_NO_FONTCONFIG)
1539 mtx = qt_fontdatabase_mutex();
1543 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1547 glyph_t glyph = FT_Get_Char_Index(face, uc);
1548 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1552 glyphs->glyphs[glyph_pos] = glyph;
1553 if (uc < QFreetypeFace::cmapCacheSize)
1554 freetype->cmapCache[uc] = glyph;
1561 *nglyphs = glyph_pos;
1562 glyphs->numGlyphs = glyph_pos;
1564 #if !defined(QT_NO_FONTCONFIG)
1569 if (flags & QTextEngine::GlyphIndicesOnly)
1572 recalcAdvances(glyphs, flags);
1577 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1580 bool design = (default_hint_style == HintNone ||
1581 default_hint_style == HintLight ||
1582 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1583 for (int i = 0; i < glyphs->numGlyphs; i++) {
1584 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1586 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1590 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1591 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1592 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1594 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1595 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1596 glyphs->advances_y[i] = 0;
1602 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1606 glyph_metrics_t overall;
1607 // initialize with line height, we get the same behaviour on all platforms
1608 overall.y = -ascent();
1609 overall.height = ascent() + descent() + 1;
1613 for (int i = 0; i < glyphs.numGlyphs; i++) {
1614 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1618 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1621 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1622 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1623 overall.x = qMin(overall.x, x);
1624 overall.y = qMin(overall.y, y);
1625 xmax = qMax(xmax, x + g->width);
1626 ymax = qMax(ymax, y + g->height);
1627 overall.xoff += g->advance;
1629 int left = FLOOR(face->glyph->metrics.horiBearingX);
1630 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1631 int top = CEIL(face->glyph->metrics.horiBearingY);
1632 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1634 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1635 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1636 overall.x = qMin(overall.x, x);
1637 overall.y = qMin(overall.y, y);
1638 xmax = qMax(xmax, x + TRUNC(right - left));
1639 ymax = qMax(ymax, y + TRUNC(top - bottom));
1640 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1643 overall.height = qMax(overall.height, ymax - overall.y);
1644 overall.width = xmax - overall.x;
1652 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1655 glyph_metrics_t overall;
1656 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1659 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1664 overall.width = g->width;
1665 overall.height = g->height;
1666 overall.xoff = g->advance;
1667 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1668 overall.xoff = overall.xoff.round();
1670 int left = FLOOR(face->glyph->metrics.horiBearingX);
1671 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1672 int top = CEIL(face->glyph->metrics.horiBearingY);
1673 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1675 overall.width = TRUNC(right-left);
1676 overall.height = TRUNC(top-bottom);
1677 overall.x = TRUNC(left);
1678 overall.y = -TRUNC(top);
1679 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1686 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1688 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1691 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1695 m.xx = FT_Fixed(matrix.m11() * 65536);
1696 m.xy = FT_Fixed(-matrix.m21() * 65536);
1697 m.yx = FT_Fixed(-matrix.m12() * 65536);
1698 m.yy = FT_Fixed(matrix.m22() * 65536);
1703 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1706 glyph_metrics_t overall;
1707 QGlyphSet *glyphSet = 0;
1708 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1710 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1711 // TODO move everything here to a method of its own to access glyphSets
1712 // to be shared with a new method that will replace loadTransformedGlyphSet()
1713 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1714 const QGlyphSet &g = transformedGlyphSets.at(i);
1715 if (g.transformationMatrix.xx == ftMatrix.xx
1716 && g.transformationMatrix.xy == ftMatrix.xy
1717 && g.transformationMatrix.yx == ftMatrix.yx
1718 && g.transformationMatrix.yy == ftMatrix.yy) {
1720 // found a match, move it to the front
1721 transformedGlyphSets.move(i, 0);
1722 glyphSet = &transformedGlyphSets[0];
1728 // don't cache more than 10 transformations
1729 if (transformedGlyphSets.count() >= 10) {
1730 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1732 transformedGlyphSets.prepend(QGlyphSet());
1734 glyphSet = &transformedGlyphSets[0];
1736 glyphSet->transformationMatrix = ftMatrix;
1740 glyphSet = &defaultGlyphSet;
1743 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1744 if (!g || g->format != format) {
1746 FT_Matrix m = this->matrix;
1747 FT_Matrix_Multiply(&ftMatrix, &m);
1748 freetype->matrix = m;
1749 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1755 overall.width = g->width;
1756 overall.height = g->height;
1757 overall.xoff = g->advance;
1759 int left = FLOOR(face->glyph->metrics.horiBearingX);
1760 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1761 int top = CEIL(face->glyph->metrics.horiBearingY);
1762 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1764 overall.width = TRUNC(right-left);
1765 overall.height = TRUNC(top-bottom);
1766 overall.x = TRUNC(left);
1767 overall.y = -TRUNC(top);
1768 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1775 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1776 QFontEngine::GlyphFormat neededFormat,
1777 const QTransform &t, QPoint *offset)
1779 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1783 neededFormat = Format_Mono;
1784 else if (neededFormat == Format_None && defaultFormat != Format_None)
1785 neededFormat = defaultFormat;
1786 else if (neededFormat == Format_None)
1787 neededFormat = Format_A8;
1789 QImage::Format format;
1790 switch (neededFormat) {
1792 format = QImage::Format_Mono;
1795 format = QImage::Format_Indexed8;
1798 format = QImage::Format_ARGB32;
1802 format = QImage::Format_Invalid;
1805 QFontEngineFT::Glyph *glyph;
1807 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1808 if (t.type() >= QTransform::TxScale) {
1810 gset = loadTransformedGlyphSet(t);
1816 FT_Matrix m = matrix;
1817 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1818 FT_Set_Transform(freetype->face, &m, 0);
1819 freetype->matrix = m;
1822 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1824 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1828 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1830 FT_Matrix m = matrix;
1831 FT_Matrix extra = QTransformToFTMatrix(t);
1832 FT_Matrix_Multiply(&extra, &m);
1833 FT_Set_Transform(freetype->face, &m, 0);
1834 freetype->matrix = m;
1835 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1838 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1844 switch (neededFormat) {
1846 pitch = ((glyph->width + 31) & ~31) >> 3;
1849 pitch = (glyph->width + 3) & ~3;
1852 pitch = glyph->width * 4;
1860 *offset = QPoint(glyph->x, -glyph->y);
1862 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1863 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1865 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1866 data->is_locked = true;
1868 return ¤tlyLockedAlphaMap;
1871 void QFontEngineFT::unlockAlphaMapForGlyph()
1873 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1875 currentlyLockedAlphaMap = QImage();
1878 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1880 return defaultGlyphSet.outline_drawing ? 0 :
1881 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1884 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1888 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1891 return QFontEngine::alphaMapForGlyph(g);
1894 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1896 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1898 QVector<QRgb> colors(256);
1899 for (int i=0; i<256; ++i)
1900 colors[i] = qRgba(0, 0, 0, i);
1901 img.setColorTable(colors);
1903 QVector<QRgb> colors(2);
1904 colors[0] = qRgba(0, 0, 0, 0);
1905 colors[1] = qRgba(0, 0, 0, 255);
1906 img.setColorTable(colors);
1908 Q_ASSERT(img.bytesPerLine() == pitch);
1910 for (int y = 0; y < glyph->height; ++y)
1911 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1918 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1920 if (t.type() > QTransform::TxTranslate)
1921 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1925 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1928 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1931 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1932 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1938 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1940 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1943 int QFontEngineFT::glyphCount() const
1946 FT_Face face = lockFace();
1948 count = face->num_glyphs;
1954 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1957 FT_Face face = freetype->face;
1958 if (scale == Unscaled) {
1959 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1960 freetype->xsize = face->units_per_EM << 6;
1961 freetype->ysize = face->units_per_EM << 6;
1962 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1963 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1964 freetype->xsize = xsize;
1965 freetype->ysize = ysize;
1967 if (freetype->matrix.xx != matrix.xx ||
1968 freetype->matrix.yy != matrix.yy ||
1969 freetype->matrix.xy != matrix.xy ||
1970 freetype->matrix.yx != matrix.yx) {
1971 freetype->matrix = matrix;
1972 FT_Set_Transform(face, &freetype->matrix, 0);
1978 void QFontEngineFT::unlockFace() const
1983 FT_Face QFontEngineFT::non_locked_face() const
1985 return freetype->face;
1989 QFontEngineFT::QGlyphSet::QGlyphSet()
1990 : outline_drawing(false)
1992 transformationMatrix.xx = 0x10000;
1993 transformationMatrix.yy = 0x10000;
1994 transformationMatrix.xy = 0;
1995 transformationMatrix.yx = 0;
1996 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1997 fast_glyph_count = 0;
2000 QFontEngineFT::QGlyphSet::~QGlyphSet()
2005 void QFontEngineFT::QGlyphSet::clear()
2007 if (fast_glyph_count > 0) {
2008 for (int i = 0; i < 256; ++i) {
2009 if (fast_glyph_data[i]) {
2010 delete fast_glyph_data[i];
2011 fast_glyph_data[i] = 0;
2014 fast_glyph_count = 0;
2016 qDeleteAll(glyph_data);
2020 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2022 if (useFastGlyphData(index, subPixelPosition)) {
2023 if (fast_glyph_data[index]) {
2024 delete fast_glyph_data[index];
2025 fast_glyph_data[index] = 0;
2026 if (fast_glyph_count > 0)
2030 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2034 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2036 if (useFastGlyphData(index, subPixelPosition)) {
2037 if (!fast_glyph_data[index])
2039 fast_glyph_data[index] = glyph;
2041 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2045 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2048 bool hsubpixel = true;
2050 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2051 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2056 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2058 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2061 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2063 freetype->ref.ref();
2065 default_load_flags = fe->default_load_flags;
2066 default_hint_style = fe->default_hint_style;
2067 antialias = fe->antialias;
2068 transform = fe->transform;
2069 embolden = fe->embolden;
2070 obliquen = fe->obliquen;
2071 subpixelType = fe->subpixelType;
2072 lcdFilterType = fe->lcdFilterType;
2073 embeddedbitmap = fe->embeddedbitmap;
2078 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2081 fontDef.pixelSize = pixelSize;
2082 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2083 if (!fe->initFromFontEngine(this)) {
2093 #endif // QT_NO_FREETYPE