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;
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 canUploadGlyphsToServer = false;
659 embeddedbitmap = false;
662 QFontEngineFT::~QFontEngineFT()
665 freetype->release(face_id);
666 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
669 void QFontEngineFT::freeGlyphSets()
671 freeServerGlyphSet(defaultGlyphSet.id);
672 for (int i = 0; i < transformedGlyphSets.count(); ++i)
673 freeServerGlyphSet(transformedGlyphSets.at(i).id);
676 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
677 const QByteArray &fontData)
679 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
682 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
683 QFreetypeFace *freetypeFace)
685 freetype = freetypeFace;
691 defaultFormat = format;
692 this->antialias = antialias;
695 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
696 else if (format == Format_A8)
697 glyphFormat = QFontEngineGlyphCache::Raster_A8;
698 else if (format == Format_A32)
699 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
703 symbol = freetype->symbol_map != 0;
704 PS_FontInfoRec psrec;
705 // don't assume that type1 fonts are symbol fonts by default
706 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
707 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
710 freetype->hbFace->isSymbolFont = symbol;
712 lbearing = rbearing = SHRT_MIN;
713 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
715 FT_Face face = lockFace();
717 if (FT_IS_SCALABLE(face)) {
718 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
720 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
721 matrix.xy = 0x10000*3/10;
727 FT_Set_Transform(face, &matrix, 0);
728 freetype->matrix = matrix;
730 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
733 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
734 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
736 // copied from QFontEngineQPF
738 int score = fontDef.weight * fontDef.pixelSize;
739 line_thickness = score / 700;
740 // looks better with thicker line for small pointsizes
741 if (line_thickness < 2 && score >= 1050)
743 underline_position = ((line_thickness * 2) + 3) / 6;
745 if (line_thickness < 1)
748 hbFont.x_ppem = face->size->metrics.x_ppem;
749 hbFont.y_ppem = face->size->metrics.y_ppem;
750 hbFont.x_scale = face->size->metrics.x_scale;
751 hbFont.y_scale = face->size->metrics.y_scale;
753 hbFace = freetype->hbFace;
755 metrics = face->size->metrics;
758 TrueType fonts with embedded bitmaps may have a bitmap font specific
759 ascent/descent in the EBLC table. There is no direct public API
760 to extract those values. The only way we've found is to trick freetype
761 into thinking that it's not a scalable font in FT_SelectSize so that
762 the metrics are retrieved from the bitmap strikes.
764 if (FT_IS_SCALABLE(face)) {
765 for (int i = 0; i < face->num_fixed_sizes; ++i) {
766 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
767 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
769 FT_Select_Size(face, i);
770 metrics.ascender = face->size->metrics.ascender;
771 metrics.descender = face->size->metrics.descender;
772 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
774 face->face_flags |= FT_FACE_FLAG_SCALABLE;
780 fontDef.styleName = QString::fromUtf8(face->style_name);
784 fsType = freetype->fsType();
785 defaultGlyphSet.id = allocateServerGlyphSet();
789 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
791 default_hint_style = style;
794 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
795 bool &hsubpixel, int &vfactor) const
797 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
798 int load_target = default_hint_style == HintLight
799 ? FT_LOAD_TARGET_LIGHT
800 : FT_LOAD_TARGET_NORMAL;
802 if (format == Format_Mono) {
803 load_target = FT_LOAD_TARGET_MONO;
804 } else if (format == Format_A32) {
805 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
806 if (default_hint_style == HintFull)
807 load_target = FT_LOAD_TARGET_LCD;
809 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
810 if (default_hint_style == HintFull)
811 load_target = FT_LOAD_TARGET_LCD_V;
816 if (set && set->outline_drawing)
817 load_flags = FT_LOAD_NO_BITMAP;
819 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
820 load_flags |= FT_LOAD_NO_HINTING;
822 load_flags |= load_target;
827 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
828 QFixed subPixelPosition,
830 bool fetchMetricsOnly) const
832 // Q_ASSERT(freetype->lock == 1);
834 bool uploadToServer = false;
835 if (format == Format_None) {
836 if (defaultFormat != Format_None) {
837 format = defaultFormat;
838 if (canUploadGlyphsToServer)
839 uploadToServer = true;
841 format = Format_Mono;
845 Glyph *g = set->getGlyph(glyph, subPixelPosition);
846 if (g && g->format == format) {
847 if (uploadToServer && !g->uploadedToServer) {
848 set->setGlyph(glyph, subPixelPosition, 0);
856 QFontEngineFT::GlyphInfo info;
858 Q_ASSERT(format != Format_None);
859 bool hsubpixel = false;
861 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
863 if (format != Format_Mono && !embeddedbitmap)
864 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);
1827 FT_Matrix m = matrix;
1828 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1829 FT_Set_Transform(freetype->face, &m, 0);
1830 freetype->matrix = m;
1833 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1835 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1839 QImage::Format format;
1840 switch (neededFormat) {
1841 case QFontEngine::Format_Mono:
1842 format = QImage::Format_Mono;
1844 case QFontEngine::Format_A8:
1845 format = QImage::Format_Indexed8;
1847 case QFontEngine::Format_A32:
1848 format = QImage::Format_ARGB32;
1852 format = QImage::Format_Invalid;
1855 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1856 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1862 switch (neededFormat) {
1863 case QFontEngineFT::Format_Mono:
1864 pitch = ((glyph->width + 31) & ~31) >> 3;
1866 case QFontEngineFT::Format_A8:
1867 pitch = (glyph->width + 3) & ~3;
1869 case QFontEngineFT::Format_A32:
1870 pitch = glyph->width * 4;
1878 *offset = QPoint(glyph->x, -glyph->y);
1881 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1882 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1884 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1885 data->is_locked = true;
1887 return ¤tlyLockedAlphaMap;
1890 void QFontEngineFT::unlockAlphaMapForGlyph()
1892 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1894 currentlyLockedAlphaMap = QImage();
1897 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1901 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1903 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1906 return QFontEngine::alphaMapForGlyph(g);
1909 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1911 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1913 QVector<QRgb> colors(256);
1914 for (int i=0; i<256; ++i)
1915 colors[i] = qRgba(0, 0, 0, i);
1916 img.setColorTable(colors);
1918 QVector<QRgb> colors(2);
1919 colors[0] = qRgba(0, 0, 0, 0);
1920 colors[1] = qRgba(0, 0, 0, 255);
1921 img.setColorTable(colors);
1923 Q_ASSERT(img.bytesPerLine() == pitch);
1925 for (int y = 0; y < glyph->height; ++y)
1926 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1933 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1935 if (t.type() > QTransform::TxTranslate)
1936 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1940 GlyphFormat glyph_format = Format_A32;
1942 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1945 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1948 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1949 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1955 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1957 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1960 int QFontEngineFT::glyphCount() const
1963 FT_Face face = lockFace();
1965 count = face->num_glyphs;
1971 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1974 FT_Face face = freetype->face;
1975 if (scale == Unscaled) {
1976 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1977 freetype->xsize = face->units_per_EM << 6;
1978 freetype->ysize = face->units_per_EM << 6;
1979 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1980 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1981 freetype->xsize = xsize;
1982 freetype->ysize = ysize;
1984 if (freetype->matrix.xx != matrix.xx ||
1985 freetype->matrix.yy != matrix.yy ||
1986 freetype->matrix.xy != matrix.xy ||
1987 freetype->matrix.yx != matrix.yx) {
1988 freetype->matrix = matrix;
1989 FT_Set_Transform(face, &freetype->matrix, 0);
1995 void QFontEngineFT::unlockFace() const
2000 FT_Face QFontEngineFT::non_locked_face() const
2002 return freetype->face;
2006 QFontEngineFT::QGlyphSet::QGlyphSet()
2007 : id(0), outline_drawing(false)
2009 transformationMatrix.xx = 0x10000;
2010 transformationMatrix.yy = 0x10000;
2011 transformationMatrix.xy = 0;
2012 transformationMatrix.yx = 0;
2013 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2014 fast_glyph_count = 0;
2017 QFontEngineFT::QGlyphSet::~QGlyphSet()
2022 void QFontEngineFT::QGlyphSet::clear()
2024 if (fast_glyph_count > 0) {
2025 for (int i = 0; i < 256; ++i) {
2026 if (fast_glyph_data[i]) {
2027 delete fast_glyph_data[i];
2028 fast_glyph_data[i] = 0;
2031 fast_glyph_count = 0;
2033 qDeleteAll(glyph_data);
2037 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2039 if (useFastGlyphData(index, subPixelPosition)) {
2040 if (fast_glyph_data[index]) {
2041 delete fast_glyph_data[index];
2042 fast_glyph_data[index] = 0;
2043 if (fast_glyph_count > 0)
2047 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2051 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2053 if (useFastGlyphData(index, subPixelPosition)) {
2054 if (!fast_glyph_data[index])
2056 fast_glyph_data[index] = glyph;
2058 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2062 unsigned long QFontEngineFT::allocateServerGlyphSet()
2067 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
2072 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2075 bool hsubpixel = true;
2077 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2078 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2083 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2085 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2088 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2090 freetype->ref.ref();
2092 default_load_flags = fe->default_load_flags;
2093 default_hint_style = fe->default_hint_style;
2094 antialias = fe->antialias;
2095 transform = fe->transform;
2096 embolden = fe->embolden;
2097 obliquen = fe->obliquen;
2098 subpixelType = fe->subpixelType;
2099 lcdFilterType = fe->lcdFilterType;
2100 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2101 embeddedbitmap = fe->embeddedbitmap;
2106 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2109 fontDef.pixelSize = pixelSize;
2110 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2111 if (!fe->initFromFontEngine(this)) {
2121 #endif // QT_NO_FREETYPE