1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include "qmetatype.h"
44 #include "qtextstream.h"
46 #include "qfontengine_ft_p.h"
47 #include "private/qimage_p.h"
49 #ifndef QT_NO_FREETYPE
52 #include "qabstractfileengine.h"
53 #include "qthreadstorage.h"
56 #include "qfontengine_ft_p.h"
58 #include FT_FREETYPE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
81 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
82 # define QT_MAX_CACHED_GLYPH_SIZE 64
88 * Freetype 2.1.7 and earlier used width/height
89 * for matching sizes in the BDF and PCF loaders.
90 * This has been fixed for 2.1.8.
92 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
93 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
94 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
96 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
97 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
100 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
101 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
102 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
104 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
107 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
108 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
109 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
110 #define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
112 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
115 #define FLOOR(x) ((x) & -64)
116 #define CEIL(x) (((x)+63) & -64)
117 #define TRUNC(x) ((x) >> 6)
118 #define ROUND(x) (((x)+32) & -64)
120 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
122 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
123 FT_Face face = (FT_Face)font;
124 FT_ULong ftlen = *length;
127 if ( !FT_IS_SFNT(face) )
128 return HB_Err_Invalid_Argument;
130 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
132 return (HB_Error)error;
134 return HB_Err_Invalid_Argument;
138 // -------------------------- Freetype support ------------------------------
148 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
152 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
154 QtFreetypeData *qt_getFreetypeData()
156 return theFreetypeData();
159 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
161 QtFreetypeData *qt_getFreetypeData()
163 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
165 freetypeData = new QtFreetypeData;
170 FT_Library qt_getFreetype()
172 QtFreetypeData *freetypeData = qt_getFreetypeData();
173 if (!freetypeData->library)
174 FT_Init_FreeType(&freetypeData->library);
175 return freetypeData->library;
178 int QFreetypeFace::fsType() const
181 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
183 fsType = os2->fsType;
187 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
189 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
192 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
193 return HB_Err_Invalid_SubTable;
195 *nPoints = face->glyph->outline.n_points;
199 if (point > *nPoints)
200 return HB_Err_Invalid_SubTable;
202 *xpos = face->glyph->outline.points[point].x;
203 *ypos = face->glyph->outline.points[point].y;
209 * One font file can contain more than one font (bold/italic for example)
210 * find the right one and return it.
212 * Returns the freetype face or 0 in case of an empty file or any other problems
213 * (like not being able to open the file)
215 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
216 const QByteArray &fontData)
218 if (face_id.filename.isEmpty() && fontData.isEmpty())
221 QtFreetypeData *freetypeData = qt_getFreetypeData();
222 if (!freetypeData->library)
223 FT_Init_FreeType(&freetypeData->library);
225 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
229 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
231 if (!face_id.filename.isEmpty()) {
232 QFile file(QString::fromUtf8(face_id.filename));
233 if (face_id.filename.startsWith(":qmemoryfonts/")) {
234 // from qfontdatabase.cpp
235 extern QByteArray qt_fontdata_from_index(int);
236 QByteArray idx = face_id.filename;
237 idx.remove(0, 14); // remove ':qmemoryfonts/'
239 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
241 newFreetype->fontData = QByteArray();
242 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
243 if (!file.open(QIODevice::ReadOnly)) {
246 newFreetype->fontData = file.readAll();
249 newFreetype->fontData = fontData;
251 if (!newFreetype->fontData.isEmpty()) {
252 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
255 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
258 newFreetype->face = face;
260 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
261 Q_CHECK_PTR(newFreetype->hbFace);
262 newFreetype->ref.store(1);
263 newFreetype->xsize = 0;
264 newFreetype->ysize = 0;
265 newFreetype->matrix.xx = 0x10000;
266 newFreetype->matrix.yy = 0x10000;
267 newFreetype->matrix.xy = 0;
268 newFreetype->matrix.yx = 0;
269 newFreetype->unicode_map = 0;
270 newFreetype->symbol_map = 0;
271 #ifndef QT_NO_FONTCONFIG
272 newFreetype->charset = 0;
275 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
277 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
278 FT_CharMap cm = newFreetype->face->charmaps[i];
279 switch(cm->encoding) {
280 case FT_ENCODING_UNICODE:
281 newFreetype->unicode_map = cm;
283 case FT_ENCODING_APPLE_ROMAN:
284 case FT_ENCODING_ADOBE_LATIN_1:
285 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
286 newFreetype->unicode_map = cm;
288 case FT_ENCODING_ADOBE_CUSTOM:
289 case FT_ENCODING_MS_SYMBOL:
290 if (!newFreetype->symbol_map)
291 newFreetype->symbol_map = cm;
298 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
299 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
302 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
303 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
304 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
305 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
306 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
308 for (int i = 0; i < 256; i += 8)
309 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
310 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
311 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
312 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
313 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
316 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
318 freetypeData->faces.insert(face_id, newFreetype.data());
320 newFreetype.take()->release(face_id);
321 // we could return null in principle instead of throwing
324 freetype = newFreetype.take();
329 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
331 QtFreetypeData *freetypeData = qt_getFreetypeData();
335 #ifndef QT_NO_FONTCONFIG
337 FcCharSetDestroy(charset);
339 if(freetypeData->faces.contains(face_id))
340 freetypeData->faces.take(face_id);
343 if (freetypeData->faces.isEmpty()) {
344 FT_Done_FreeType(freetypeData->library);
345 freetypeData->library = 0;
350 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
352 *ysize = qRound(fontDef.pixelSize * 64);
353 *xsize = *ysize * fontDef.stretch / 100;
354 *outline_drawing = false;
357 * Bitmap only faces must match exactly, so find the closest
358 * one (height dominant search)
360 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
362 for (int i = 1; i < face->num_fixed_sizes; i++) {
363 if (qAbs(*ysize - Y_SIZE(face,i)) <
364 qAbs (*ysize - Y_SIZE(face, best)) ||
365 (qAbs (*ysize - Y_SIZE(face, i)) ==
366 qAbs (*ysize - Y_SIZE(face, best)) &&
367 qAbs (*xsize - X_SIZE(face, i)) <
368 qAbs (*xsize - X_SIZE(face, best)))) {
372 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
373 *xsize = X_SIZE(face, best);
374 *ysize = Y_SIZE(face, best);
377 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
378 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
379 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
380 if (err && face->num_fixed_sizes == 1)
381 err = 0; //even more of a workaround...
388 *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
392 QFontEngine::Properties QFreetypeFace::properties() const
394 QFontEngine::Properties p;
395 p.postscriptName = FT_Get_Postscript_Name(face);
396 PS_FontInfoRec font_info;
397 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
398 p.copyright = font_info.notice;
399 if (FT_IS_SCALABLE(face)) {
400 p.ascent = face->ascender;
401 p.descent = -face->descender;
402 p.leading = face->height - face->ascender + face->descender;
403 p.emSquare = face->units_per_EM;
404 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
405 face->bbox.xMax - face->bbox.xMin,
406 face->bbox.yMax - face->bbox.yMin);
408 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
409 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
410 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
411 p.emSquare = face->size->metrics.y_ppem;
412 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
413 p.boundingBox = QRectF(0, -p.ascent.toReal(),
414 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
417 p.capHeight = p.ascent;
418 p.lineWidth = face->underline_thickness;
422 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
425 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
426 if (FT_IS_SFNT(face)) {
427 FT_ULong len = *length;
428 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
435 /* Some fonts (such as MingLiu rely on hinting to scale different
436 components to their correct sizes. While this is really broken (it
437 should be done in the component glyph itself, not the hinter) we
438 will have to live with it.
440 This means we can not use FT_LOAD_NO_HINTING to get the glyph
441 outline. All we can do is to load the unscaled glyph and scale it
442 down manually when required.
444 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
446 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
447 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
448 FT_Vector *p = g->outline.points;
449 const FT_Vector *e = p + g->outline.n_points;
451 p->x = FT_MulFix(p->x, x_scale);
452 p->y = FT_MulFix(p->y, y_scale);
457 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
459 const qreal factor = 1/64.;
460 scaleOutline(face, g, x_scale, y_scale);
462 QPointF cp = point.toPointF();
464 // convert the outline to a painter path
466 for (int j = 0; j < g->outline.n_contours; ++j) {
467 int last_point = g->outline.contours[j];
468 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
469 if(!(g->outline.tags[i] & 1)) {
470 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
473 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
474 // qDebug("first point at %f %f", start.x(), start.y());
480 while (i < last_point) {
482 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
483 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
485 switch (g->outline.tags[i] & 3) {
487 // cubic bezier element
490 c[3] = (c[3] + c[2])/2;
494 // quadratic bezier element
497 c[3] = (c[1] + c[2])/2;
498 c[2] = (2*c[1] + c[3])/3;
499 c[1] = (2*c[1] + c[0])/3;
505 // qDebug() << "lineTo" << c[1];
512 c[2] = (2*c[1] + c[3])/3;
513 c[1] = (2*c[1] + c[0])/3;
517 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
518 path->cubicTo(c[1], c[2], c[3]);
523 // qDebug() << "closeSubpath";
524 path->closeSubpath();
528 c[2] = (2*c[1] + c[3])/3;
529 c[1] = (2*c[1] + c[0])/3;
531 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
532 path->cubicTo(c[1], c[2], c[3]);
538 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
540 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
542 if (slot->format != FT_GLYPH_FORMAT_BITMAP
543 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
546 QPointF cp = point.toPointF();
547 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
548 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
551 QFontEngineFT::Glyph::~Glyph()
556 static const uint subpixel_filter[3][3] = {
562 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
566 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
567 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
568 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
569 res = (mid << 24) + (high << 16) + (mid << 8) + low;
572 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
577 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
580 const int offs = bgr ? -1 : 1;
581 const int w = width * 3;
584 for (int x = 0; x < w; x += 3) {
585 uint red = src[x+1-offs];
586 uint green = src[x+1];
587 uint blue = src[x+1+offs];
588 *dd = filterPixel(red, green, blue, legacyFilter);
596 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
599 const int offs = bgr ? -src_pitch : src_pitch;
601 for (int x = 0; x < width; x++) {
602 uint red = src[x+src_pitch-offs];
603 uint green = src[x+src_pitch];
604 uint blue = src[x+src_pitch+offs];
605 dst[x] = filterPixel(red, green, blue, legacyFilter);
612 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
614 // convolute the bitmap with a triangle filter to get rid of color fringes
615 // If we take account for a gamma value of 2, we end up with
616 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
617 // as this nicely sums up to 16 :)
622 for (int x = 2; x < width - 2; ++x) {
623 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
624 dst[x] = (uchar) (sum >> 4);
626 dst[width - 2] = dst[width - 1] = 0;
632 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
640 kerning_pairs_loaded = false;
646 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
648 default_hint_style = HintNone;
650 default_hint_style = HintFull;
652 subpixelType = Subpixel_None;
654 #if defined(FT_LCD_FILTER_H)
655 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
657 defaultFormat = Format_None;
658 embeddedbitmap = false;
659 cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").toInt() == 0;
660 m_subPixelPositionCount = 4;
663 QFontEngineFT::~QFontEngineFT()
666 freetype->release(face_id);
667 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
670 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
671 const QByteArray &fontData)
673 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
676 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
677 QFreetypeFace *freetypeFace)
679 freetype = freetypeFace;
685 defaultFormat = format;
686 this->antialias = antialias;
689 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
690 else if (format == Format_A8)
691 glyphFormat = QFontEngineGlyphCache::Raster_A8;
692 else if (format == Format_A32)
693 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
697 symbol = freetype->symbol_map != 0;
698 PS_FontInfoRec psrec;
699 // don't assume that type1 fonts are symbol fonts by default
700 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
701 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
704 freetype->hbFace->isSymbolFont = symbol;
706 lbearing = rbearing = SHRT_MIN;
707 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
709 FT_Face face = lockFace();
711 if (FT_IS_SCALABLE(face)) {
712 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
714 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
715 matrix.xy = 0x10000*3/10;
721 FT_Set_Transform(face, &matrix, 0);
722 freetype->matrix = matrix;
724 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
727 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
728 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
730 // copied from QFontEngineQPF
732 int score = fontDef.weight * fontDef.pixelSize;
733 line_thickness = score / 700;
734 // looks better with thicker line for small pointsizes
735 if (line_thickness < 2 && score >= 1050)
737 underline_position = ((line_thickness * 2) + 3) / 6;
739 if (line_thickness < 1)
742 hbFont.x_ppem = face->size->metrics.x_ppem;
743 hbFont.y_ppem = face->size->metrics.y_ppem;
744 hbFont.x_scale = face->size->metrics.x_scale;
745 hbFont.y_scale = face->size->metrics.y_scale;
747 hbFace = freetype->hbFace;
749 metrics = face->size->metrics;
752 TrueType fonts with embedded bitmaps may have a bitmap font specific
753 ascent/descent in the EBLC table. There is no direct public API
754 to extract those values. The only way we've found is to trick freetype
755 into thinking that it's not a scalable font in FT_SelectSize so that
756 the metrics are retrieved from the bitmap strikes.
758 if (FT_IS_SCALABLE(face)) {
759 for (int i = 0; i < face->num_fixed_sizes; ++i) {
760 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
761 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
763 FT_Select_Size(face, i);
764 metrics.ascender = face->size->metrics.ascender;
765 metrics.descender = face->size->metrics.descender;
766 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
768 face->face_flags |= FT_FACE_FLAG_SCALABLE;
774 fontDef.styleName = QString::fromUtf8(face->style_name);
778 fsType = freetype->fsType();
782 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
784 default_hint_style = style;
787 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
788 bool &hsubpixel, int &vfactor) const
790 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
791 int load_target = default_hint_style == HintLight
792 ? FT_LOAD_TARGET_LIGHT
793 : FT_LOAD_TARGET_NORMAL;
795 if (format == Format_Mono) {
796 load_target = FT_LOAD_TARGET_MONO;
797 } else if (format == Format_A32) {
798 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
799 if (default_hint_style == HintFull)
800 load_target = FT_LOAD_TARGET_LCD;
802 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
803 if (default_hint_style == HintFull)
804 load_target = FT_LOAD_TARGET_LCD_V;
809 if (set && set->outline_drawing)
810 load_flags = FT_LOAD_NO_BITMAP;
812 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
813 load_flags |= FT_LOAD_NO_HINTING;
815 load_flags |= load_target;
820 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
821 QFixed subPixelPosition,
823 bool fetchMetricsOnly) const
825 // Q_ASSERT(freetype->lock == 1);
827 if (format == Format_None) {
828 if (defaultFormat != Format_None) {
829 format = defaultFormat;
831 format = Format_Mono;
835 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
836 if (g && g->format == format)
839 QFontEngineFT::GlyphInfo info;
841 Q_ASSERT(format != Format_None);
842 bool hsubpixel = false;
844 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
846 if (format != Format_Mono && !embeddedbitmap)
847 load_flags |= FT_LOAD_NO_BITMAP;
849 FT_Matrix matrix = freetype->matrix;
850 bool transform = matrix.xx != 0x10000
851 || matrix.yy != 0x10000
856 load_flags |= FT_LOAD_NO_BITMAP;
858 FT_Face face = freetype->face;
861 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
863 FT_Set_Transform(face, &freetype->matrix, &v);
865 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
866 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
867 load_flags &= ~FT_LOAD_NO_BITMAP;
868 err = FT_Load_Glyph(face, glyph, load_flags);
870 if (err == FT_Err_Too_Few_Arguments) {
871 // this is an error in the bytecode interpreter, just try to run without it
872 load_flags |= FT_LOAD_FORCE_AUTOHINT;
873 err = FT_Load_Glyph(face, glyph, load_flags);
875 if (err != FT_Err_Ok)
876 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
878 if ((!set || set->outline_drawing) && fetchMetricsOnly)
881 FT_GlyphSlot slot = face->glyph;
882 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
884 Q_FT_GLYPHSLOT_OBLIQUE(slot);
886 // While Embolden alters the metrics of the slot, oblique does not, so we need
887 // to fix this ourselves.
895 FT_Matrix_Multiply(&m, &matrix);
898 FT_Library library = qt_getFreetype();
900 info.xOff = TRUNC(ROUND(slot->advance.x));
903 uchar *glyph_buffer = 0;
904 int glyph_buffer_size = 0;
905 #if defined(QT_USE_FREETYPE_LCDFILTER)
906 bool useFreetypeRenderGlyph = false;
907 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
908 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
909 if (err == FT_Err_Ok)
910 useFreetypeRenderGlyph = true;
913 if (useFreetypeRenderGlyph) {
914 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
916 if (err != FT_Err_Ok)
917 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
919 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
921 info.height = slot->bitmap.rows / vfactor;
922 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
923 info.x = -slot->bitmap_left;
924 info.y = slot->bitmap_top;
926 glyph_buffer_size = info.width * info.height * 4;
927 glyph_buffer = new uchar[glyph_buffer_size];
930 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
931 else if (vfactor != 1)
932 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
936 int left = slot->metrics.horiBearingX;
937 int right = slot->metrics.horiBearingX + slot->metrics.width;
938 int top = slot->metrics.horiBearingY;
939 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
940 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
945 FT_Vector_Transform(&vector, &matrix);
950 FT_Vector_Transform(&vector, &matrix);
951 if (l > vector.x) l = vector.x;
952 if (r < vector.x) r = vector.x;
953 if (t < vector.y) t = vector.y;
954 if (b > vector.y) b = vector.y;
957 FT_Vector_Transform(&vector, &matrix);
958 if (l > vector.x) l = vector.x;
959 if (r < vector.x) r = vector.x;
960 if (t < vector.y) t = vector.y;
961 if (b > vector.y) b = vector.y;
964 FT_Vector_Transform(&vector, &matrix);
965 if (l > vector.x) l = vector.x;
966 if (r < vector.x) r = vector.x;
967 if (t < vector.y) t = vector.y;
968 if (b > vector.y) b = vector.y;
976 bottom = FLOOR(bottom);
979 int hpixels = TRUNC(right - left);
980 // subpixel position requires one more pixel
981 if (subPixelPosition > 0 && format != Format_Mono)
985 hpixels = hpixels*3 + 8;
986 info.width = hpixels;
987 info.height = TRUNC(top - bottom);
988 info.x = -TRUNC(left);
995 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
996 || ((uchar)(info.width) != info.width)
997 || ((uchar)(info.height) != info.height)
998 || ((signed char)(info.x) != info.x)
999 || ((signed char)(info.y) != info.y)
1000 || ((signed char)(info.xOff) != info.xOff));
1003 delete [] glyph_buffer;
1007 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1008 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1009 glyph_buffer_size = pitch * info.height;
1010 glyph_buffer = new uchar[glyph_buffer_size];
1012 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1014 bitmap.rows = info.height*vfactor;
1015 bitmap.width = hpixels;
1016 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1017 if (!hsubpixel && vfactor == 1)
1018 bitmap.buffer = glyph_buffer;
1020 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1021 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1022 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1024 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1025 matrix.yy = vfactor << 16;
1026 matrix.yx = matrix.xy = 0;
1028 FT_Outline_Transform(&slot->outline, &matrix);
1029 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1030 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1032 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1033 Q_ASSERT(antialias);
1034 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1035 bool useLegacyLcdFilter = false;
1036 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1037 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1039 uchar *buffer = bitmap.buffer;
1040 if (!useLegacyLcdFilter) {
1041 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1042 buffer = convoluted;
1044 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1045 delete [] convoluted;
1046 } else if (vfactor != 1) {
1047 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1050 if (bitmap.buffer != glyph_buffer)
1051 delete [] bitmap.buffer;
1052 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1053 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1054 uchar *src = slot->bitmap.buffer;
1055 uchar *dst = glyph_buffer;
1056 int h = slot->bitmap.rows;
1057 if (format == Format_Mono) {
1058 int bytes = ((info.width + 7) & ~7) >> 3;
1060 memcpy (dst, src, bytes);
1062 src += slot->bitmap.pitch;
1067 uint *dd = (uint *)dst;
1069 for (int x = 0; x < slot->bitmap.width; x++) {
1070 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1075 src += slot->bitmap.pitch;
1077 } else if (vfactor != 1) {
1079 uint *dd = (uint *)dst;
1080 for (int x = 0; x < slot->bitmap.width; x++) {
1081 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1085 src += slot->bitmap.pitch;
1089 for (int x = 0; x < slot->bitmap.width; x++) {
1090 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1094 src += slot->bitmap.pitch;
1099 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1100 delete [] glyph_buffer;
1111 g->linearAdvance = slot->linearHoriAdvance >> 10;
1112 g->width = info.width;
1113 g->height = info.height;
1116 g->advance = info.xOff;
1119 g->data = glyph_buffer;
1122 set->setGlyph(glyph, subPixelPosition, g);
1127 QFontEngine::FaceId QFontEngineFT::faceId() const
1132 QFontEngine::Properties QFontEngineFT::properties() const
1134 Properties p = freetype->properties();
1135 if (p.postscriptName.isEmpty()) {
1136 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1139 return freetype->properties();
1142 QFixed QFontEngineFT::emSquareSize() const
1144 if (FT_IS_SCALABLE(freetype->face))
1145 return freetype->face->units_per_EM;
1147 return freetype->face->size->metrics.y_ppem;
1150 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1152 return freetype->getSfntTable(tag, buffer, length);
1155 int QFontEngineFT::synthesized() const
1158 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1159 s = SynthesizedItalic;
1160 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1161 s |= SynthesizedBold;
1162 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1163 s |= SynthesizedStretch;
1167 QFixed QFontEngineFT::ascent() const
1169 return QFixed::fromFixed(metrics.ascender);
1172 QFixed QFontEngineFT::descent() const
1174 // subtract a pixel to work around QFontMetrics's built-in + 1
1175 return QFixed::fromFixed(-metrics.descender - 64);
1178 QFixed QFontEngineFT::leading() const
1180 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1183 QFixed QFontEngineFT::xHeight() const
1185 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1186 if (os2 && os2->sxHeight) {
1188 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1192 return QFontEngine::xHeight();
1195 QFixed QFontEngineFT::averageCharWidth() const
1197 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1198 if (os2 && os2->xAvgCharWidth) {
1200 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1204 return QFontEngine::averageCharWidth();
1207 qreal QFontEngineFT::maxCharWidth() const
1209 return metrics.max_advance >> 6;
1212 static const ushort char_table[] = {
1234 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1237 qreal QFontEngineFT::minLeftBearing() const
1239 if (lbearing == SHRT_MIN)
1240 (void) minRightBearing(); // calculates both
1241 return lbearing.toReal();
1244 qreal QFontEngineFT::minRightBearing() const
1246 if (rbearing == SHRT_MIN) {
1247 lbearing = rbearing = 0;
1248 const QChar *ch = (const QChar *)(const void*)char_table;
1249 QGlyphLayoutArray<char_table_entries> glyphs;
1250 int ng = char_table_entries;
1251 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1253 if (glyphs.glyphs[ng]) {
1254 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1255 lbearing = qMin(lbearing, gi.x);
1256 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1260 return rbearing.toReal();
1263 QFixed QFontEngineFT::lineThickness() const
1265 return line_thickness;
1268 QFixed QFontEngineFT::underlinePosition() const
1270 return underline_position;
1273 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1275 if (!kerning_pairs_loaded) {
1276 kerning_pairs_loaded = true;
1278 if (freetype->face->size->metrics.x_ppem != 0) {
1279 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1281 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1286 QFontEngine::doKerning(g, flags);
1289 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1291 if (matrix.type() > QTransform::TxShear)
1294 // FT_Set_Transform only supports scalable fonts
1295 if (!FT_IS_SCALABLE(freetype->face))
1299 m.xx = FT_Fixed(matrix.m11() * 65536);
1300 m.xy = FT_Fixed(-matrix.m21() * 65536);
1301 m.yx = FT_Fixed(-matrix.m12() * 65536);
1302 m.yy = FT_Fixed(matrix.m22() * 65536);
1306 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1307 const QGlyphSet &g = transformedGlyphSets.at(i);
1308 if (g.transformationMatrix.xx == m.xx
1309 && g.transformationMatrix.xy == m.xy
1310 && g.transformationMatrix.yx == m.yx
1311 && g.transformationMatrix.yy == m.yy) {
1313 // found a match, move it to the front
1314 transformedGlyphSets.move(i, 0);
1315 gs = &transformedGlyphSets[0];
1321 // don't try to load huge fonts
1322 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1323 if (draw_as_outline)
1326 // don't cache more than 10 transformations
1327 if (transformedGlyphSets.count() >= 10) {
1328 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1330 transformedGlyphSets.prepend(QGlyphSet());
1332 gs = &transformedGlyphSets[0];
1334 gs->transformationMatrix = m;
1335 gs->outline_drawing = draw_as_outline;
1341 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1342 const QFixedPoint *positions,
1347 for (int i = 0; i < num_glyphs; ++i) {
1348 QFixed spp = subPixelPositionForX(positions[i].x);
1349 Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1350 if (glyph == 0 || glyph->format != format) {
1353 FT_Matrix m = matrix;
1354 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1355 FT_Set_Transform(face, &m, 0);
1356 freetype->matrix = m;
1358 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1371 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1373 FT_Face face = lockFace(Unscaled);
1374 FT_Set_Transform(face, 0, 0);
1375 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1377 int left = face->glyph->metrics.horiBearingX;
1378 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1379 int top = face->glyph->metrics.horiBearingY;
1380 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1386 metrics->width = QFixed::fromFixed(right-left);
1387 metrics->height = QFixed::fromFixed(top-bottom);
1388 metrics->x = QFixed::fromFixed(left);
1389 metrics->y = QFixed::fromFixed(-top);
1390 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1392 if (!FT_IS_SCALABLE(freetype->face))
1393 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1395 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1397 FT_Set_Transform(face, &freetype->matrix, 0);
1401 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1403 uint ucs4 = str[i].unicode();
1404 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1406 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1411 bool QFontEngineFT::canRender(const QChar *string, int len)
1413 FT_Face face = freetype->face;
1417 for ( int i = 0; i < len; i++ ) {
1418 unsigned int uc = getChar(string, i, len);
1419 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1428 for ( int i = 0; i < len; i++ ) {
1429 unsigned int uc = getChar(string, i, len);
1430 if (!FT_Get_Char_Index(face, uc))
1437 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1439 if (!glyphs.numGlyphs)
1442 if (FT_IS_SCALABLE(freetype->face)) {
1443 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1445 QVarLengthArray<QFixedPoint> positions;
1446 QVarLengthArray<glyph_t> positioned_glyphs;
1448 matrix.translate(x, y);
1449 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1451 FT_Face face = lockFace(Unscaled);
1452 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1453 FT_UInt glyph = positioned_glyphs[gl];
1454 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1455 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1461 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1462 QPainterPath *path, QTextItem::RenderFlags)
1464 FT_Face face = lockFace(Unscaled);
1466 for (int gl = 0; gl < numGlyphs; gl++) {
1467 FT_UInt glyph = glyphs[gl];
1469 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1471 FT_GlyphSlot g = face->glyph;
1472 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1474 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1475 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1476 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1481 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1482 QTextEngine::ShaperFlags flags) const
1484 if (*nglyphs < len) {
1489 bool mirrored = flags & QTextEngine::RightToLeft;
1491 if (freetype->symbol_map) {
1492 FT_Face face = freetype->face;
1493 for ( int i = 0; i < len; ++i ) {
1494 unsigned int uc = getChar(str, i, len);
1495 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1496 if ( !glyphs->glyphs[glyph_pos] ) {
1498 #if !defined(QT_NO_FONTCONFIG)
1499 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1504 glyph = FT_Get_Char_Index(face, uc);
1505 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1510 FT_Set_Charmap(face, freetype->symbol_map);
1511 glyph = FT_Get_Char_Index(face, uc);
1512 FT_Set_Charmap(face, freetype->unicode_map);
1514 glyphs->glyphs[glyph_pos] = glyph;
1515 if (uc < QFreetypeFace::cmapCacheSize)
1516 freetype->cmapCache[uc] = glyph;
1521 FT_Face face = freetype->face;
1522 for (int i = 0; i < len; ++i) {
1523 unsigned int uc = getChar(str, i, len);
1525 uc = QChar::mirroredChar(uc);
1526 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1527 if (!glyphs->glyphs[glyph_pos]) {
1528 #if !defined(QT_NO_FONTCONFIG)
1529 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1533 glyph_t glyph = FT_Get_Char_Index(face, uc);
1534 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1538 glyphs->glyphs[glyph_pos] = glyph;
1539 if (uc < QFreetypeFace::cmapCacheSize)
1540 freetype->cmapCache[uc] = glyph;
1547 *nglyphs = glyph_pos;
1548 glyphs->numGlyphs = glyph_pos;
1550 if (flags & QTextEngine::GlyphIndicesOnly)
1553 recalcAdvances(glyphs, flags);
1558 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1561 bool design = (default_hint_style == HintNone ||
1562 default_hint_style == HintLight ||
1563 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1564 for (int i = 0; i < glyphs->numGlyphs; i++) {
1565 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1567 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1571 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1572 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1573 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1575 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1576 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1577 glyphs->advances_y[i] = 0;
1583 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1587 glyph_metrics_t overall;
1588 // initialize with line height, we get the same behaviour on all platforms
1589 overall.y = -ascent();
1590 overall.height = ascent() + descent() + 1;
1594 for (int i = 0; i < glyphs.numGlyphs; i++) {
1595 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1599 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1602 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1603 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1604 overall.x = qMin(overall.x, x);
1605 overall.y = qMin(overall.y, y);
1606 xmax = qMax(xmax, x + g->width);
1607 ymax = qMax(ymax, y + g->height);
1608 overall.xoff += g->advance;
1610 int left = FLOOR(face->glyph->metrics.horiBearingX);
1611 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1612 int top = CEIL(face->glyph->metrics.horiBearingY);
1613 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1615 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1616 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1617 overall.x = qMin(overall.x, x);
1618 overall.y = qMin(overall.y, y);
1619 xmax = qMax(xmax, x + TRUNC(right - left));
1620 ymax = qMax(ymax, y + TRUNC(top - bottom));
1621 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1624 overall.height = qMax(overall.height, ymax - overall.y);
1625 overall.width = xmax - overall.x;
1633 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1636 glyph_metrics_t overall;
1637 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1640 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1645 overall.width = g->width;
1646 overall.height = g->height;
1647 overall.xoff = g->advance;
1648 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1649 overall.xoff = overall.xoff.round();
1651 int left = FLOOR(face->glyph->metrics.horiBearingX);
1652 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1653 int top = CEIL(face->glyph->metrics.horiBearingY);
1654 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1656 overall.width = TRUNC(right-left);
1657 overall.height = TRUNC(top-bottom);
1658 overall.x = TRUNC(left);
1659 overall.y = -TRUNC(top);
1660 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1667 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1669 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1672 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1676 m.xx = FT_Fixed(matrix.m11() * 65536);
1677 m.xy = FT_Fixed(-matrix.m21() * 65536);
1678 m.yx = FT_Fixed(-matrix.m12() * 65536);
1679 m.yy = FT_Fixed(matrix.m22() * 65536);
1684 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1687 glyph_metrics_t overall;
1688 QGlyphSet *glyphSet = 0;
1689 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1691 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1692 // TODO move everything here to a method of its own to access glyphSets
1693 // to be shared with a new method that will replace loadTransformedGlyphSet()
1694 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1695 const QGlyphSet &g = transformedGlyphSets.at(i);
1696 if (g.transformationMatrix.xx == ftMatrix.xx
1697 && g.transformationMatrix.xy == ftMatrix.xy
1698 && g.transformationMatrix.yx == ftMatrix.yx
1699 && g.transformationMatrix.yy == ftMatrix.yy) {
1701 // found a match, move it to the front
1702 transformedGlyphSets.move(i, 0);
1703 glyphSet = &transformedGlyphSets[0];
1709 // don't cache more than 10 transformations
1710 if (transformedGlyphSets.count() >= 10) {
1711 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1713 transformedGlyphSets.prepend(QGlyphSet());
1715 glyphSet = &transformedGlyphSets[0];
1717 glyphSet->transformationMatrix = ftMatrix;
1721 glyphSet = &defaultGlyphSet;
1724 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1725 if (!g || g->format != format) {
1727 FT_Matrix m = this->matrix;
1728 FT_Matrix_Multiply(&ftMatrix, &m);
1729 freetype->matrix = m;
1730 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1736 overall.width = g->width;
1737 overall.height = g->height;
1738 overall.xoff = g->advance;
1740 int left = FLOOR(face->glyph->metrics.horiBearingX);
1741 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1742 int top = CEIL(face->glyph->metrics.horiBearingY);
1743 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1745 overall.width = TRUNC(right-left);
1746 overall.height = TRUNC(top-bottom);
1747 overall.x = TRUNC(left);
1748 overall.y = -TRUNC(top);
1749 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1756 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1757 QFontEngine::GlyphFormat neededFormat,
1758 const QTransform &t, QPoint *offset)
1760 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1764 neededFormat = Format_Mono;
1765 else if (neededFormat == Format_None && defaultFormat != Format_None)
1766 neededFormat = defaultFormat;
1767 else if (neededFormat == Format_None)
1768 neededFormat = Format_A8;
1770 QImage::Format format;
1771 switch (neededFormat) {
1773 format = QImage::Format_Mono;
1776 format = QImage::Format_Indexed8;
1779 format = QImage::Format_ARGB32;
1783 format = QImage::Format_Invalid;
1786 QFontEngineFT::Glyph *glyph;
1788 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1789 if (t.type() >= QTransform::TxScale) {
1791 gset = loadTransformedGlyphSet(t);
1797 FT_Matrix m = matrix;
1798 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1799 FT_Set_Transform(freetype->face, &m, 0);
1800 freetype->matrix = m;
1803 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1805 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1809 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1811 FT_Matrix m = matrix;
1812 FT_Matrix extra = QTransformToFTMatrix(t);
1813 FT_Matrix_Multiply(&extra, &m);
1814 FT_Set_Transform(freetype->face, &m, 0);
1815 freetype->matrix = m;
1816 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1819 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1825 switch (neededFormat) {
1827 pitch = ((glyph->width + 31) & ~31) >> 3;
1830 pitch = (glyph->width + 3) & ~3;
1833 pitch = glyph->width * 4;
1841 *offset = QPoint(glyph->x, -glyph->y);
1843 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1844 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1846 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1847 data->is_locked = true;
1849 return ¤tlyLockedAlphaMap;
1852 void QFontEngineFT::unlockAlphaMapForGlyph()
1854 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1856 currentlyLockedAlphaMap = QImage();
1859 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1861 return defaultGlyphSet.outline_drawing ? 0 :
1862 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1865 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1869 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1872 return QFontEngine::alphaMapForGlyph(g);
1875 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1877 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1879 QVector<QRgb> colors(256);
1880 for (int i=0; i<256; ++i)
1881 colors[i] = qRgba(0, 0, 0, i);
1882 img.setColorTable(colors);
1884 QVector<QRgb> colors(2);
1885 colors[0] = qRgba(0, 0, 0, 0);
1886 colors[1] = qRgba(0, 0, 0, 255);
1887 img.setColorTable(colors);
1889 Q_ASSERT(img.bytesPerLine() == pitch);
1891 for (int y = 0; y < glyph->height; ++y)
1892 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1899 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1901 if (t.type() > QTransform::TxTranslate)
1902 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1906 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1909 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1912 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1913 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1919 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1921 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1924 int QFontEngineFT::glyphCount() const
1927 FT_Face face = lockFace();
1929 count = face->num_glyphs;
1935 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1938 FT_Face face = freetype->face;
1939 if (scale == Unscaled) {
1940 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1941 freetype->xsize = face->units_per_EM << 6;
1942 freetype->ysize = face->units_per_EM << 6;
1943 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1944 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1945 freetype->xsize = xsize;
1946 freetype->ysize = ysize;
1948 if (freetype->matrix.xx != matrix.xx ||
1949 freetype->matrix.yy != matrix.yy ||
1950 freetype->matrix.xy != matrix.xy ||
1951 freetype->matrix.yx != matrix.yx) {
1952 freetype->matrix = matrix;
1953 FT_Set_Transform(face, &freetype->matrix, 0);
1959 void QFontEngineFT::unlockFace() const
1964 FT_Face QFontEngineFT::non_locked_face() const
1966 return freetype->face;
1970 QFontEngineFT::QGlyphSet::QGlyphSet()
1971 : outline_drawing(false)
1973 transformationMatrix.xx = 0x10000;
1974 transformationMatrix.yy = 0x10000;
1975 transformationMatrix.xy = 0;
1976 transformationMatrix.yx = 0;
1977 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1978 fast_glyph_count = 0;
1981 QFontEngineFT::QGlyphSet::~QGlyphSet()
1986 void QFontEngineFT::QGlyphSet::clear()
1988 if (fast_glyph_count > 0) {
1989 for (int i = 0; i < 256; ++i) {
1990 if (fast_glyph_data[i]) {
1991 delete fast_glyph_data[i];
1992 fast_glyph_data[i] = 0;
1995 fast_glyph_count = 0;
1997 qDeleteAll(glyph_data);
2001 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2003 if (useFastGlyphData(index, subPixelPosition)) {
2004 if (fast_glyph_data[index]) {
2005 delete fast_glyph_data[index];
2006 fast_glyph_data[index] = 0;
2007 if (fast_glyph_count > 0)
2011 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2015 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2017 if (useFastGlyphData(index, subPixelPosition)) {
2018 if (!fast_glyph_data[index])
2020 fast_glyph_data[index] = glyph;
2022 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2026 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2029 bool hsubpixel = true;
2031 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2032 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2037 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2039 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2042 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2044 freetype->ref.ref();
2046 default_load_flags = fe->default_load_flags;
2047 default_hint_style = fe->default_hint_style;
2048 antialias = fe->antialias;
2049 transform = fe->transform;
2050 embolden = fe->embolden;
2051 obliquen = fe->obliquen;
2052 subpixelType = fe->subpixelType;
2053 lcdFilterType = fe->lcdFilterType;
2054 embeddedbitmap = fe->embeddedbitmap;
2059 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2062 fontDef.pixelSize = pixelSize;
2063 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2064 if (!fe->initFromFontEngine(this)) {
2074 #endif // QT_NO_FREETYPE