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 = 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;
647 default_hint_style = HintNone;
648 subpixelType = Subpixel_None;
650 #if defined(FT_LCD_FILTER_H)
651 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
653 defaultFormat = Format_None;
654 canUploadGlyphsToServer = false;
655 embeddedbitmap = false;
658 QFontEngineFT::~QFontEngineFT()
661 freetype->release(face_id);
662 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
665 void QFontEngineFT::freeGlyphSets()
667 freeServerGlyphSet(defaultGlyphSet.id);
668 for (int i = 0; i < transformedGlyphSets.count(); ++i)
669 freeServerGlyphSet(transformedGlyphSets.at(i).id);
672 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
673 const QByteArray &fontData)
675 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
678 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
679 QFreetypeFace *freetypeFace)
681 freetype = freetypeFace;
687 defaultFormat = format;
688 this->antialias = antialias;
691 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
692 else if (format == Format_A8)
693 glyphFormat = QFontEngineGlyphCache::Raster_A8;
694 else if (format == Format_A32)
695 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
699 symbol = freetype->symbol_map != 0;
700 PS_FontInfoRec psrec;
701 // don't assume that type1 fonts are symbol fonts by default
702 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
703 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
706 freetype->hbFace->isSymbolFont = symbol;
708 lbearing = rbearing = SHRT_MIN;
709 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
711 FT_Face face = lockFace();
713 if (FT_IS_SCALABLE(face)) {
714 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
716 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
717 matrix.xy = 0x10000*3/10;
723 FT_Set_Transform(face, &matrix, 0);
724 freetype->matrix = matrix;
726 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
729 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
730 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
732 // copied from QFontEngineQPF
734 int score = fontDef.weight * fontDef.pixelSize;
735 line_thickness = score / 700;
736 // looks better with thicker line for small pointsizes
737 if (line_thickness < 2 && score >= 1050)
739 underline_position = ((line_thickness * 2) + 3) / 6;
741 if (line_thickness < 1)
744 hbFont.x_ppem = face->size->metrics.x_ppem;
745 hbFont.y_ppem = face->size->metrics.y_ppem;
746 hbFont.x_scale = face->size->metrics.x_scale;
747 hbFont.y_scale = face->size->metrics.y_scale;
749 hbFace = freetype->hbFace;
751 metrics = face->size->metrics;
753 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
755 TrueType fonts with embedded bitmaps may have a bitmap font specific
756 ascent/descent in the EBLC table. There is no direct public API
757 to extract those values. The only way we've found is to trick freetype
758 into thinking that it's not a scalable font in FT_SelectSize so that
759 the metrics are retrieved from the bitmap strikes.
761 if (FT_IS_SCALABLE(face)) {
762 for (int i = 0; i < face->num_fixed_sizes; ++i) {
763 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
764 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
766 FT_Select_Size(face, i);
767 metrics.ascender = face->size->metrics.ascender;
768 metrics.descender = face->size->metrics.descender;
769 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
771 face->face_flags |= FT_FACE_FLAG_SCALABLE;
778 fontDef.styleName = QString::fromUtf8(face->style_name);
782 fsType = freetype->fsType();
783 defaultGlyphSet.id = allocateServerGlyphSet();
787 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
789 default_hint_style = style;
792 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
793 bool &hsubpixel, int &vfactor) const
795 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
796 int load_target = default_hint_style == HintLight
797 ? FT_LOAD_TARGET_LIGHT
798 : FT_LOAD_TARGET_NORMAL;
800 if (format == Format_Mono) {
801 load_target = FT_LOAD_TARGET_MONO;
802 } else if (format == Format_A32) {
803 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
804 if (default_hint_style == HintFull)
805 load_target = FT_LOAD_TARGET_LCD;
807 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
808 if (default_hint_style == HintFull)
809 load_target = FT_LOAD_TARGET_LCD_V;
814 if (set && set->outline_drawing)
815 load_flags = FT_LOAD_NO_BITMAP;
817 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
818 load_flags |= FT_LOAD_NO_HINTING;
820 load_flags |= load_target;
825 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
826 QFixed subPixelPosition,
828 bool fetchMetricsOnly) const
830 // Q_ASSERT(freetype->lock == 1);
832 bool uploadToServer = false;
833 if (format == Format_None) {
834 if (defaultFormat != Format_None) {
835 format = defaultFormat;
836 if (canUploadGlyphsToServer)
837 uploadToServer = true;
839 format = Format_Mono;
843 Glyph *g = set->getGlyph(glyph, subPixelPosition);
844 if (g && g->format == format) {
845 if (uploadToServer && !g->uploadedToServer) {
846 set->setGlyph(glyph, subPixelPosition, 0);
854 QFontEngineFT::GlyphInfo info;
856 Q_ASSERT(format != Format_None);
857 bool hsubpixel = false;
859 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
862 if (format != Format_Mono && !embeddedbitmap)
863 load_flags |= FT_LOAD_NO_BITMAP;
866 FT_Matrix matrix = freetype->matrix;
867 bool transform = matrix.xx != 0x10000
868 || matrix.yy != 0x10000
873 load_flags |= FT_LOAD_NO_BITMAP;
875 FT_Face face = freetype->face;
878 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
880 FT_Set_Transform(face, &freetype->matrix, &v);
882 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
883 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
884 load_flags &= ~FT_LOAD_NO_BITMAP;
885 err = FT_Load_Glyph(face, glyph, load_flags);
887 if (err == FT_Err_Too_Few_Arguments) {
888 // this is an error in the bytecode interpreter, just try to run without it
889 load_flags |= FT_LOAD_FORCE_AUTOHINT;
890 err = FT_Load_Glyph(face, glyph, load_flags);
892 if (err != FT_Err_Ok)
893 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
895 if (set->outline_drawing && fetchMetricsOnly)
898 FT_GlyphSlot slot = face->glyph;
899 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
901 Q_FT_GLYPHSLOT_OBLIQUE(slot);
903 // While Embolden alters the metrics of the slot, oblique does not, so we need
904 // to fix this ourselves.
912 FT_Matrix_Multiply(&m, &matrix);
915 FT_Library library = qt_getFreetype();
917 info.xOff = TRUNC(ROUND(slot->advance.x));
920 uchar *glyph_buffer = 0;
921 int glyph_buffer_size = 0;
922 #if defined(QT_USE_FREETYPE_LCDFILTER)
923 bool useFreetypeRenderGlyph = false;
924 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
925 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
926 if (err == FT_Err_Ok)
927 useFreetypeRenderGlyph = true;
930 if (useFreetypeRenderGlyph) {
931 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
933 if (err != FT_Err_Ok)
934 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
936 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
938 info.height = slot->bitmap.rows / vfactor;
939 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
940 info.x = -slot->bitmap_left;
941 info.y = slot->bitmap_top;
943 glyph_buffer_size = info.width * info.height * 4;
944 glyph_buffer = new uchar[glyph_buffer_size];
947 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
948 else if (vfactor != 1)
949 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
953 int left = slot->metrics.horiBearingX;
954 int right = slot->metrics.horiBearingX + slot->metrics.width;
955 int top = slot->metrics.horiBearingY;
956 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
957 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
962 FT_Vector_Transform(&vector, &matrix);
967 FT_Vector_Transform(&vector, &matrix);
968 if (l > vector.x) l = vector.x;
969 if (r < vector.x) r = vector.x;
970 if (t < vector.y) t = vector.y;
971 if (b > vector.y) b = vector.y;
974 FT_Vector_Transform(&vector, &matrix);
975 if (l > vector.x) l = vector.x;
976 if (r < vector.x) r = vector.x;
977 if (t < vector.y) t = vector.y;
978 if (b > vector.y) b = vector.y;
981 FT_Vector_Transform(&vector, &matrix);
982 if (l > vector.x) l = vector.x;
983 if (r < vector.x) r = vector.x;
984 if (t < vector.y) t = vector.y;
985 if (b > vector.y) b = vector.y;
993 bottom = FLOOR(bottom);
996 int hpixels = TRUNC(right - left);
997 // subpixel position requires one more pixel
998 if (subPixelPosition > 0 && format != Format_Mono)
1002 hpixels = hpixels*3 + 8;
1003 info.width = hpixels;
1004 info.height = TRUNC(top - bottom);
1005 info.x = -TRUNC(left);
1006 info.y = TRUNC(top);
1012 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1013 || ((uchar)(info.width) != info.width)
1014 || ((uchar)(info.height) != info.height)
1015 || ((signed char)(info.x) != info.x)
1016 || ((signed char)(info.y) != info.y)
1017 || ((signed char)(info.xOff) != info.xOff));
1020 delete [] glyph_buffer;
1024 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1025 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1026 glyph_buffer_size = pitch * info.height;
1027 glyph_buffer = new uchar[glyph_buffer_size];
1029 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1031 bitmap.rows = info.height*vfactor;
1032 bitmap.width = hpixels;
1033 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1034 if (!hsubpixel && vfactor == 1)
1035 bitmap.buffer = glyph_buffer;
1037 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1038 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1039 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1041 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1042 matrix.yy = vfactor << 16;
1043 matrix.yx = matrix.xy = 0;
1045 FT_Outline_Transform(&slot->outline, &matrix);
1046 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1047 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1049 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1050 Q_ASSERT(antialias);
1051 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1052 bool useLegacyLcdFilter = false;
1053 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1054 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1056 uchar *buffer = bitmap.buffer;
1057 if (!useLegacyLcdFilter) {
1058 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1059 buffer = convoluted;
1061 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1062 delete [] convoluted;
1063 } else if (vfactor != 1) {
1064 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1067 if (bitmap.buffer != glyph_buffer)
1068 delete [] bitmap.buffer;
1069 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1070 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1071 uchar *src = slot->bitmap.buffer;
1072 uchar *dst = glyph_buffer;
1073 int h = slot->bitmap.rows;
1074 if (format == Format_Mono) {
1075 int bytes = ((info.width + 7) & ~7) >> 3;
1077 memcpy (dst, src, bytes);
1079 src += slot->bitmap.pitch;
1084 uint *dd = (uint *)dst;
1086 for (int x = 0; x < slot->bitmap.width; x++) {
1087 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1092 src += slot->bitmap.pitch;
1094 } else if (vfactor != 1) {
1096 uint *dd = (uint *)dst;
1097 for (int x = 0; x < slot->bitmap.width; x++) {
1098 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1102 src += slot->bitmap.pitch;
1106 for (int x = 0; x < slot->bitmap.width; x++) {
1107 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1111 src += slot->bitmap.pitch;
1116 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1117 delete [] glyph_buffer;
1125 g->uploadedToServer = false;
1129 g->linearAdvance = slot->linearHoriAdvance >> 10;
1130 g->width = info.width;
1131 g->height = info.height;
1134 g->advance = info.xOff;
1137 g->data = glyph_buffer;
1139 if (uploadToServer) {
1140 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1143 set->setGlyph(glyph, subPixelPosition, g);
1148 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1154 Q_UNUSED(glyphDataSize);
1158 QFontEngine::FaceId QFontEngineFT::faceId() const
1163 QFontEngine::Properties QFontEngineFT::properties() const
1165 Properties p = freetype->properties();
1166 if (p.postscriptName.isEmpty()) {
1167 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1170 return freetype->properties();
1173 QFixed QFontEngineFT::emSquareSize() const
1175 if (FT_IS_SCALABLE(freetype->face))
1176 return freetype->face->units_per_EM;
1178 return freetype->face->size->metrics.y_ppem;
1181 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1183 return freetype->getSfntTable(tag, buffer, length);
1186 int QFontEngineFT::synthesized() const
1189 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1190 s = SynthesizedItalic;
1191 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1192 s |= SynthesizedBold;
1193 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1194 s |= SynthesizedStretch;
1198 QFixed QFontEngineFT::ascent() const
1200 return QFixed::fromFixed(metrics.ascender);
1203 QFixed QFontEngineFT::descent() const
1205 // subtract a pixel to work around QFontMetrics's built-in + 1
1206 return QFixed::fromFixed(-metrics.descender - 64);
1209 QFixed QFontEngineFT::leading() const
1211 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1214 QFixed QFontEngineFT::xHeight() const
1216 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1217 if (os2 && os2->sxHeight) {
1219 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1223 return QFontEngine::xHeight();
1226 QFixed QFontEngineFT::averageCharWidth() const
1228 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1229 if (os2 && os2->xAvgCharWidth) {
1231 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1235 return QFontEngine::averageCharWidth();
1238 qreal QFontEngineFT::maxCharWidth() const
1240 return metrics.max_advance >> 6;
1243 static const ushort char_table[] = {
1264 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1267 qreal QFontEngineFT::minLeftBearing() const
1269 if (lbearing == SHRT_MIN)
1270 (void) minRightBearing(); // calculates both
1271 return lbearing.toReal();
1274 qreal QFontEngineFT::minRightBearing() const
1276 if (rbearing == SHRT_MIN) {
1277 lbearing = rbearing = 0;
1278 const QChar *ch = (const QChar *)(const void*)char_table;
1279 QGlyphLayoutArray<char_table_entries> glyphs;
1280 int ng = char_table_entries;
1281 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1283 if (glyphs.glyphs[ng]) {
1284 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1285 lbearing = qMin(lbearing, gi.x);
1286 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1290 return rbearing.toReal();
1293 QFixed QFontEngineFT::lineThickness() const
1295 return line_thickness;
1298 QFixed QFontEngineFT::underlinePosition() const
1300 return underline_position;
1303 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1305 if (!kerning_pairs_loaded) {
1306 kerning_pairs_loaded = true;
1308 if (freetype->face->size->metrics.x_ppem != 0) {
1309 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1311 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1316 QFontEngine::doKerning(g, flags);
1319 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1321 if (matrix.type() > QTransform::TxShear)
1324 // FT_Set_Transform only supports scalable fonts
1325 if (!FT_IS_SCALABLE(freetype->face))
1329 m.xx = FT_Fixed(matrix.m11() * 65536);
1330 m.xy = FT_Fixed(-matrix.m21() * 65536);
1331 m.yx = FT_Fixed(-matrix.m12() * 65536);
1332 m.yy = FT_Fixed(matrix.m22() * 65536);
1336 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1337 const QGlyphSet &g = transformedGlyphSets.at(i);
1338 if (g.transformationMatrix.xx == m.xx
1339 && g.transformationMatrix.xy == m.xy
1340 && g.transformationMatrix.yx == m.yx
1341 && g.transformationMatrix.yy == m.yy) {
1343 // found a match, move it to the front
1344 transformedGlyphSets.move(i, 0);
1345 gs = &transformedGlyphSets[0];
1351 // don't try to load huge fonts
1352 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1353 if (draw_as_outline)
1356 // don't cache more than 10 transformations
1357 if (transformedGlyphSets.count() >= 10) {
1358 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1359 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1361 transformedGlyphSets.prepend(QGlyphSet());
1363 gs = &transformedGlyphSets[0];
1367 gs->id = allocateServerGlyphSet();
1369 gs->transformationMatrix = m;
1370 gs->outline_drawing = draw_as_outline;
1376 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1377 const QFixedPoint *positions,
1382 for (int i = 0; i < num_glyphs; ++i) {
1383 QFixed spp = subPixelPositionForX(positions[i].x);
1384 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1385 if (glyph == 0 || glyph->format != format) {
1388 FT_Matrix m = matrix;
1389 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1390 FT_Set_Transform(face, &m, 0);
1391 freetype->matrix = m;
1393 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1406 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1408 FT_Face face = lockFace(Unscaled);
1409 FT_Set_Transform(face, 0, 0);
1410 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1412 int left = face->glyph->metrics.horiBearingX;
1413 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1414 int top = face->glyph->metrics.horiBearingY;
1415 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1421 metrics->width = QFixed::fromFixed(right-left);
1422 metrics->height = QFixed::fromFixed(top-bottom);
1423 metrics->x = QFixed::fromFixed(left);
1424 metrics->y = QFixed::fromFixed(-top);
1425 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1427 if (!FT_IS_SCALABLE(freetype->face))
1428 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1430 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1432 FT_Set_Transform(face, &freetype->matrix, 0);
1436 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1438 uint ucs4 = str[i].unicode();
1439 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1441 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1446 bool QFontEngineFT::canRender(const QChar *string, int len)
1448 FT_Face face = freetype->face;
1452 for ( int i = 0; i < len; i++ ) {
1453 unsigned int uc = getChar(string, i, len);
1454 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1463 for ( int i = 0; i < len; i++ ) {
1464 unsigned int uc = getChar(string, i, len);
1465 if (!FT_Get_Char_Index(face, uc))
1472 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1474 if (!glyphs.numGlyphs)
1477 if (FT_IS_SCALABLE(freetype->face)) {
1478 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1480 QVarLengthArray<QFixedPoint> positions;
1481 QVarLengthArray<glyph_t> positioned_glyphs;
1483 matrix.translate(x, y);
1484 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1486 FT_Face face = lockFace(Unscaled);
1487 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1488 FT_UInt glyph = positioned_glyphs[gl];
1489 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1490 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1496 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1497 QPainterPath *path, QTextItem::RenderFlags)
1499 FT_Face face = lockFace(Unscaled);
1501 for (int gl = 0; gl < numGlyphs; gl++) {
1502 FT_UInt glyph = glyphs[gl];
1504 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1506 FT_GlyphSlot g = face->glyph;
1507 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1509 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1510 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1511 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1516 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1517 QTextEngine::ShaperFlags flags) const
1519 if (*nglyphs < len) {
1524 #if !defined(QT_NO_FONTCONFIG)
1525 extern QMutex *qt_fontdatabase_mutex();
1529 bool mirrored = flags & QTextEngine::RightToLeft;
1531 if (freetype->symbol_map) {
1532 FT_Face face = freetype->face;
1533 for ( int i = 0; i < len; ++i ) {
1534 unsigned int uc = getChar(str, i, len);
1535 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1536 if ( !glyphs->glyphs[glyph_pos] ) {
1538 #if !defined(QT_NO_FONTCONFIG)
1540 mtx = qt_fontdatabase_mutex();
1544 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1549 glyph = FT_Get_Char_Index(face, uc);
1550 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1555 FT_Set_Charmap(face, freetype->symbol_map);
1556 glyph = FT_Get_Char_Index(face, uc);
1557 FT_Set_Charmap(face, freetype->unicode_map);
1559 glyphs->glyphs[glyph_pos] = glyph;
1560 if (uc < QFreetypeFace::cmapCacheSize)
1561 freetype->cmapCache[uc] = glyph;
1566 FT_Face face = freetype->face;
1567 for (int i = 0; i < len; ++i) {
1568 unsigned int uc = getChar(str, i, len);
1570 uc = QChar::mirroredChar(uc);
1571 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1572 if (!glyphs->glyphs[glyph_pos]) {
1573 #if !defined(QT_NO_FONTCONFIG)
1575 mtx = qt_fontdatabase_mutex();
1579 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1583 glyph_t glyph = FT_Get_Char_Index(face, uc);
1584 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1588 glyphs->glyphs[glyph_pos] = glyph;
1589 if (uc < QFreetypeFace::cmapCacheSize)
1590 freetype->cmapCache[uc] = glyph;
1597 *nglyphs = glyph_pos;
1598 glyphs->numGlyphs = glyph_pos;
1600 #if !defined(QT_NO_FONTCONFIG)
1605 if (flags & QTextEngine::GlyphIndicesOnly)
1608 recalcAdvances(glyphs, flags);
1613 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1616 bool design = (default_hint_style == HintNone ||
1617 default_hint_style == HintLight ||
1618 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1619 for (int i = 0; i < glyphs->numGlyphs; i++) {
1620 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1622 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1626 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1627 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1628 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1630 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1631 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1632 glyphs->advances_y[i] = 0;
1638 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1643 glyph_metrics_t overall;
1644 // initialize with line height, we get the same behaviour on all platforms
1645 overall.y = -ascent();
1646 overall.height = ascent() + descent() + 1;
1650 for (int i = 0; i < glyphs.numGlyphs; i++) {
1651 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1655 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1658 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1659 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1660 overall.x = qMin(overall.x, x);
1661 overall.y = qMin(overall.y, y);
1662 xmax = qMax(xmax, x + g->width);
1663 ymax = qMax(ymax, y + g->height);
1664 overall.xoff += g->advance;
1666 int left = FLOOR(face->glyph->metrics.horiBearingX);
1667 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1668 int top = CEIL(face->glyph->metrics.horiBearingY);
1669 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1671 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1672 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1673 overall.x = qMin(overall.x, x);
1674 overall.y = qMin(overall.y, y);
1675 xmax = qMax(xmax, x + TRUNC(right - left));
1676 ymax = qMax(ymax, y + TRUNC(top - bottom));
1677 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1680 overall.height = qMax(overall.height, ymax - overall.y);
1681 overall.width = xmax - overall.x;
1689 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1692 glyph_metrics_t overall;
1693 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1696 g = loadGlyph(glyph, 0, Format_None, true);
1701 overall.width = g->width;
1702 overall.height = g->height;
1703 overall.xoff = g->advance;
1704 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1705 overall.xoff = overall.xoff.round();
1707 int left = FLOOR(face->glyph->metrics.horiBearingX);
1708 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1709 int top = CEIL(face->glyph->metrics.horiBearingY);
1710 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1712 overall.width = TRUNC(right-left);
1713 overall.height = TRUNC(top-bottom);
1714 overall.x = TRUNC(left);
1715 overall.y = -TRUNC(top);
1716 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1723 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1725 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1728 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1731 glyph_metrics_t overall;
1732 QGlyphSet *glyphSet = 0;
1733 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1734 // TODO move everything here to a method of its own to access glyphSets
1735 // to be shared with a new method that will replace loadTransformedGlyphSet()
1737 m.xx = FT_Fixed(matrix.m11() * 65536);
1738 m.xy = FT_Fixed(-matrix.m21() * 65536);
1739 m.yx = FT_Fixed(-matrix.m12() * 65536);
1740 m.yy = FT_Fixed(matrix.m22() * 65536);
1741 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1742 const QGlyphSet &g = transformedGlyphSets.at(i);
1743 if (g.transformationMatrix.xx == m.xx
1744 && g.transformationMatrix.xy == m.xy
1745 && g.transformationMatrix.yx == m.yx
1746 && g.transformationMatrix.yy == m.yy) {
1748 // found a match, move it to the front
1749 transformedGlyphSets.move(i, 0);
1750 glyphSet = &transformedGlyphSets[0];
1756 // don't cache more than 10 transformations
1757 if (transformedGlyphSets.count() >= 10) {
1758 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1759 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1761 transformedGlyphSets.prepend(QGlyphSet());
1763 glyphSet = &transformedGlyphSets[0];
1765 glyphSet->id = allocateServerGlyphSet();
1766 glyphSet->transformationMatrix = m;
1770 glyphSet = &defaultGlyphSet;
1772 Glyph * g = glyphSet->getGlyph(glyph);
1773 if (!g || g->format != format) {
1775 FT_Matrix m = this->matrix;
1776 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1777 freetype->matrix = m;
1778 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1784 overall.width = g->width;
1785 overall.height = g->height;
1786 overall.xoff = g->advance;
1788 int left = FLOOR(face->glyph->metrics.horiBearingX);
1789 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1790 int top = CEIL(face->glyph->metrics.horiBearingY);
1791 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1793 overall.width = TRUNC(right-left);
1794 overall.height = TRUNC(top-bottom);
1795 overall.x = TRUNC(left);
1796 overall.y = -TRUNC(top);
1797 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1804 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1805 QFontEngine::GlyphFormat neededFormat,
1806 const QTransform &t, QPoint *offset)
1808 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1812 neededFormat = Format_Mono;
1813 else if (neededFormat == Format_None && defaultFormat != Format_None)
1814 neededFormat = defaultFormat;
1815 else if (neededFormat == Format_None)
1816 neededFormat = Format_A8;
1818 QFontEngineFT::QGlyphSet *gset = defaultGlyphs();
1819 if (t.type() >= QTransform::TxScale) {
1821 gset = loadTransformedGlyphSet(t);
1826 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1829 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1833 QImage::Format format;
1834 switch (neededFormat) {
1835 case QFontEngine::Format_Mono:
1836 format = QImage::Format_Mono;
1838 case QFontEngine::Format_A8:
1839 format = QImage::Format_Indexed8;
1841 case QFontEngine::Format_A32:
1842 format = QImage::Format_ARGB32;
1846 format = QImage::Format_Invalid;
1849 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1850 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1856 switch (neededFormat) {
1857 case QFontEngineFT::Format_Mono:
1858 pitch = ((glyph->width + 31) & ~31) >> 3;
1860 case QFontEngineFT::Format_A8:
1861 pitch = (glyph->width + 3) & ~3;
1863 case QFontEngineFT::Format_A32:
1864 pitch = glyph->width * 4;
1872 *offset = QPoint(glyph->x, -glyph->y);
1875 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1876 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1878 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1879 data->is_locked = true;
1881 return ¤tlyLockedAlphaMap;
1884 void QFontEngineFT::unlockAlphaMapForGlyph()
1886 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1888 currentlyLockedAlphaMap = QImage();
1891 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1895 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1897 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1900 return QFontEngine::alphaMapForGlyph(g);
1903 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1905 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1907 QVector<QRgb> colors(256);
1908 for (int i=0; i<256; ++i)
1909 colors[i] = qRgba(0, 0, 0, i);
1910 img.setColorTable(colors);
1912 QVector<QRgb> colors(2);
1913 colors[0] = qRgba(0, 0, 0, 0);
1914 colors[1] = qRgba(0, 0, 0, 255);
1915 img.setColorTable(colors);
1917 Q_ASSERT(img.bytesPerLine() == pitch);
1919 for (int y = 0; y < glyph->height; ++y)
1920 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1927 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1929 if (t.type() > QTransform::TxTranslate)
1930 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1934 GlyphFormat glyph_format = Format_A32;
1936 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1939 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1942 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1943 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1949 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1951 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1954 int QFontEngineFT::glyphCount() const
1957 FT_Face face = lockFace();
1959 count = face->num_glyphs;
1965 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1968 FT_Face face = freetype->face;
1969 if (scale == Unscaled) {
1970 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1971 freetype->xsize = face->units_per_EM << 6;
1972 freetype->ysize = face->units_per_EM << 6;
1973 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1974 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1975 freetype->xsize = xsize;
1976 freetype->ysize = ysize;
1978 if (freetype->matrix.xx != matrix.xx ||
1979 freetype->matrix.yy != matrix.yy ||
1980 freetype->matrix.xy != matrix.xy ||
1981 freetype->matrix.yx != matrix.yx) {
1982 freetype->matrix = matrix;
1983 FT_Set_Transform(face, &freetype->matrix, 0);
1989 void QFontEngineFT::unlockFace() const
1994 FT_Face QFontEngineFT::non_locked_face() const
1996 return freetype->face;
2000 QFontEngineFT::QGlyphSet::QGlyphSet()
2001 : id(0), outline_drawing(false)
2003 transformationMatrix.xx = 0x10000;
2004 transformationMatrix.yy = 0x10000;
2005 transformationMatrix.xy = 0;
2006 transformationMatrix.yx = 0;
2007 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2008 fast_glyph_count = 0;
2011 QFontEngineFT::QGlyphSet::~QGlyphSet()
2016 void QFontEngineFT::QGlyphSet::clear()
2018 if (fast_glyph_count > 0) {
2019 for (int i = 0; i < 256; ++i) {
2020 if (fast_glyph_data[i]) {
2021 delete fast_glyph_data[i];
2022 fast_glyph_data[i] = 0;
2025 fast_glyph_count = 0;
2027 qDeleteAll(glyph_data);
2031 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2033 if (useFastGlyphData(index, subPixelPosition)) {
2034 if (fast_glyph_data[index]) {
2035 delete fast_glyph_data[index];
2036 fast_glyph_data[index] = 0;
2037 if (fast_glyph_count > 0)
2041 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2045 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2047 if (useFastGlyphData(index, subPixelPosition)) {
2048 if (!fast_glyph_data[index])
2050 fast_glyph_data[index] = glyph;
2052 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2056 unsigned long QFontEngineFT::allocateServerGlyphSet()
2061 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
2066 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2069 bool hsubpixel = true;
2071 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2072 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2077 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2079 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2082 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2084 freetype->ref.ref();
2086 default_load_flags = fe->default_load_flags;
2087 default_hint_style = fe->default_hint_style;
2088 antialias = fe->antialias;
2089 transform = fe->transform;
2090 embolden = fe->embolden;
2091 obliquen = fe->obliquen;
2092 subpixelType = fe->subpixelType;
2093 lcdFilterType = fe->lcdFilterType;
2094 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2095 embeddedbitmap = fe->embeddedbitmap;
2100 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2103 fontDef.pixelSize = pixelSize;
2104 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2105 if (!fe->initFromFontEngine(this)) {
2115 #endif // QT_NO_FREETYPE