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 bool mirrored = flags & QTextEngine::RightToLeft;
1490 if (freetype->symbol_map) {
1491 FT_Face face = freetype->face;
1492 for ( int i = 0; i < len; ++i ) {
1493 unsigned int uc = getChar(str, i, len);
1494 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1495 if ( !glyphs->glyphs[glyph_pos] ) {
1497 #if !defined(QT_NO_FONTCONFIG)
1498 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1503 glyph = FT_Get_Char_Index(face, uc);
1504 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1509 FT_Set_Charmap(face, freetype->symbol_map);
1510 glyph = FT_Get_Char_Index(face, uc);
1511 FT_Set_Charmap(face, freetype->unicode_map);
1513 glyphs->glyphs[glyph_pos] = glyph;
1514 if (uc < QFreetypeFace::cmapCacheSize)
1515 freetype->cmapCache[uc] = glyph;
1520 FT_Face face = freetype->face;
1521 for (int i = 0; i < len; ++i) {
1522 unsigned int uc = getChar(str, i, len);
1524 uc = QChar::mirroredChar(uc);
1525 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1526 if (!glyphs->glyphs[glyph_pos]) {
1527 #if !defined(QT_NO_FONTCONFIG)
1528 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1532 glyph_t glyph = FT_Get_Char_Index(face, uc);
1533 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1537 glyphs->glyphs[glyph_pos] = glyph;
1538 if (uc < QFreetypeFace::cmapCacheSize)
1539 freetype->cmapCache[uc] = glyph;
1546 *nglyphs = glyph_pos;
1547 glyphs->numGlyphs = glyph_pos;
1549 if (flags & QTextEngine::GlyphIndicesOnly)
1552 recalcAdvances(glyphs, flags);
1557 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1560 bool design = (default_hint_style == HintNone ||
1561 default_hint_style == HintLight ||
1562 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1563 for (int i = 0; i < glyphs->numGlyphs; i++) {
1564 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1566 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1570 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1571 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1572 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1574 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1575 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1576 glyphs->advances_y[i] = 0;
1582 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1586 glyph_metrics_t overall;
1587 // initialize with line height, we get the same behaviour on all platforms
1588 overall.y = -ascent();
1589 overall.height = ascent() + descent() + 1;
1593 for (int i = 0; i < glyphs.numGlyphs; i++) {
1594 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1598 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1601 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1602 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1603 overall.x = qMin(overall.x, x);
1604 overall.y = qMin(overall.y, y);
1605 xmax = qMax(xmax, x + g->width);
1606 ymax = qMax(ymax, y + g->height);
1607 overall.xoff += g->advance;
1609 int left = FLOOR(face->glyph->metrics.horiBearingX);
1610 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1611 int top = CEIL(face->glyph->metrics.horiBearingY);
1612 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1614 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1615 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1616 overall.x = qMin(overall.x, x);
1617 overall.y = qMin(overall.y, y);
1618 xmax = qMax(xmax, x + TRUNC(right - left));
1619 ymax = qMax(ymax, y + TRUNC(top - bottom));
1620 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1623 overall.height = qMax(overall.height, ymax - overall.y);
1624 overall.width = xmax - overall.x;
1632 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1635 glyph_metrics_t overall;
1636 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1639 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1644 overall.width = g->width;
1645 overall.height = g->height;
1646 overall.xoff = g->advance;
1647 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1648 overall.xoff = overall.xoff.round();
1650 int left = FLOOR(face->glyph->metrics.horiBearingX);
1651 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1652 int top = CEIL(face->glyph->metrics.horiBearingY);
1653 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1655 overall.width = TRUNC(right-left);
1656 overall.height = TRUNC(top-bottom);
1657 overall.x = TRUNC(left);
1658 overall.y = -TRUNC(top);
1659 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1666 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1668 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1671 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1675 m.xx = FT_Fixed(matrix.m11() * 65536);
1676 m.xy = FT_Fixed(-matrix.m21() * 65536);
1677 m.yx = FT_Fixed(-matrix.m12() * 65536);
1678 m.yy = FT_Fixed(matrix.m22() * 65536);
1683 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1686 glyph_metrics_t overall;
1687 QGlyphSet *glyphSet = 0;
1688 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1690 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1691 // TODO move everything here to a method of its own to access glyphSets
1692 // to be shared with a new method that will replace loadTransformedGlyphSet()
1693 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1694 const QGlyphSet &g = transformedGlyphSets.at(i);
1695 if (g.transformationMatrix.xx == ftMatrix.xx
1696 && g.transformationMatrix.xy == ftMatrix.xy
1697 && g.transformationMatrix.yx == ftMatrix.yx
1698 && g.transformationMatrix.yy == ftMatrix.yy) {
1700 // found a match, move it to the front
1701 transformedGlyphSets.move(i, 0);
1702 glyphSet = &transformedGlyphSets[0];
1708 // don't cache more than 10 transformations
1709 if (transformedGlyphSets.count() >= 10) {
1710 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1712 transformedGlyphSets.prepend(QGlyphSet());
1714 glyphSet = &transformedGlyphSets[0];
1716 glyphSet->transformationMatrix = ftMatrix;
1720 glyphSet = &defaultGlyphSet;
1723 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1724 if (!g || g->format != format) {
1726 FT_Matrix m = this->matrix;
1727 FT_Matrix_Multiply(&ftMatrix, &m);
1728 freetype->matrix = m;
1729 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1735 overall.width = g->width;
1736 overall.height = g->height;
1737 overall.xoff = g->advance;
1739 int left = FLOOR(face->glyph->metrics.horiBearingX);
1740 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1741 int top = CEIL(face->glyph->metrics.horiBearingY);
1742 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1744 overall.width = TRUNC(right-left);
1745 overall.height = TRUNC(top-bottom);
1746 overall.x = TRUNC(left);
1747 overall.y = -TRUNC(top);
1748 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1755 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1756 QFontEngine::GlyphFormat neededFormat,
1757 const QTransform &t, QPoint *offset)
1759 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1763 neededFormat = Format_Mono;
1764 else if (neededFormat == Format_None && defaultFormat != Format_None)
1765 neededFormat = defaultFormat;
1766 else if (neededFormat == Format_None)
1767 neededFormat = Format_A8;
1769 QImage::Format format;
1770 switch (neededFormat) {
1772 format = QImage::Format_Mono;
1775 format = QImage::Format_Indexed8;
1778 format = QImage::Format_ARGB32;
1782 format = QImage::Format_Invalid;
1785 QFontEngineFT::Glyph *glyph;
1787 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1788 if (t.type() >= QTransform::TxScale) {
1790 gset = loadTransformedGlyphSet(t);
1796 FT_Matrix m = matrix;
1797 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1798 FT_Set_Transform(freetype->face, &m, 0);
1799 freetype->matrix = m;
1802 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1804 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1808 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1810 FT_Matrix m = matrix;
1811 FT_Matrix extra = QTransformToFTMatrix(t);
1812 FT_Matrix_Multiply(&extra, &m);
1813 FT_Set_Transform(freetype->face, &m, 0);
1814 freetype->matrix = m;
1815 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1818 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1824 switch (neededFormat) {
1826 pitch = ((glyph->width + 31) & ~31) >> 3;
1829 pitch = (glyph->width + 3) & ~3;
1832 pitch = glyph->width * 4;
1840 *offset = QPoint(glyph->x, -glyph->y);
1842 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1843 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1845 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1846 data->is_locked = true;
1848 return ¤tlyLockedAlphaMap;
1851 void QFontEngineFT::unlockAlphaMapForGlyph()
1853 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1855 currentlyLockedAlphaMap = QImage();
1858 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1860 return defaultGlyphSet.outline_drawing ? 0 :
1861 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1864 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1868 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1871 return QFontEngine::alphaMapForGlyph(g);
1874 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1876 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1878 QVector<QRgb> colors(256);
1879 for (int i=0; i<256; ++i)
1880 colors[i] = qRgba(0, 0, 0, i);
1881 img.setColorTable(colors);
1883 QVector<QRgb> colors(2);
1884 colors[0] = qRgba(0, 0, 0, 0);
1885 colors[1] = qRgba(0, 0, 0, 255);
1886 img.setColorTable(colors);
1888 Q_ASSERT(img.bytesPerLine() == pitch);
1890 for (int y = 0; y < glyph->height; ++y)
1891 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1898 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1900 if (t.type() > QTransform::TxTranslate)
1901 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1905 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1908 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1911 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1912 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1918 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1920 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1923 int QFontEngineFT::glyphCount() const
1926 FT_Face face = lockFace();
1928 count = face->num_glyphs;
1934 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1937 FT_Face face = freetype->face;
1938 if (scale == Unscaled) {
1939 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1940 freetype->xsize = face->units_per_EM << 6;
1941 freetype->ysize = face->units_per_EM << 6;
1942 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1943 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1944 freetype->xsize = xsize;
1945 freetype->ysize = ysize;
1947 if (freetype->matrix.xx != matrix.xx ||
1948 freetype->matrix.yy != matrix.yy ||
1949 freetype->matrix.xy != matrix.xy ||
1950 freetype->matrix.yx != matrix.yx) {
1951 freetype->matrix = matrix;
1952 FT_Set_Transform(face, &freetype->matrix, 0);
1958 void QFontEngineFT::unlockFace() const
1963 FT_Face QFontEngineFT::non_locked_face() const
1965 return freetype->face;
1969 QFontEngineFT::QGlyphSet::QGlyphSet()
1970 : outline_drawing(false)
1972 transformationMatrix.xx = 0x10000;
1973 transformationMatrix.yy = 0x10000;
1974 transformationMatrix.xy = 0;
1975 transformationMatrix.yx = 0;
1976 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1977 fast_glyph_count = 0;
1980 QFontEngineFT::QGlyphSet::~QGlyphSet()
1985 void QFontEngineFT::QGlyphSet::clear()
1987 if (fast_glyph_count > 0) {
1988 for (int i = 0; i < 256; ++i) {
1989 if (fast_glyph_data[i]) {
1990 delete fast_glyph_data[i];
1991 fast_glyph_data[i] = 0;
1994 fast_glyph_count = 0;
1996 qDeleteAll(glyph_data);
2000 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2002 if (useFastGlyphData(index, subPixelPosition)) {
2003 if (fast_glyph_data[index]) {
2004 delete fast_glyph_data[index];
2005 fast_glyph_data[index] = 0;
2006 if (fast_glyph_count > 0)
2010 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2014 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2016 if (useFastGlyphData(index, subPixelPosition)) {
2017 if (!fast_glyph_data[index])
2019 fast_glyph_data[index] = glyph;
2021 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2025 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2028 bool hsubpixel = true;
2030 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2031 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2036 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2038 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2041 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2043 freetype->ref.ref();
2045 default_load_flags = fe->default_load_flags;
2046 default_hint_style = fe->default_hint_style;
2047 antialias = fe->antialias;
2048 transform = fe->transform;
2049 embolden = fe->embolden;
2050 obliquen = fe->obliquen;
2051 subpixelType = fe->subpixelType;
2052 lcdFilterType = fe->lcdFilterType;
2053 embeddedbitmap = fe->embeddedbitmap;
2058 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2061 fontDef.pixelSize = pixelSize;
2062 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2063 if (!fe->initFromFontEngine(this)) {
2073 #endif // QT_NO_FREETYPE