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;
757 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
759 TrueType fonts with embedded bitmaps may have a bitmap font specific
760 ascent/descent in the EBLC table. There is no direct public API
761 to extract those values. The only way we've found is to trick freetype
762 into thinking that it's not a scalable font in FT_SelectSize so that
763 the metrics are retrieved from the bitmap strikes.
765 if (FT_IS_SCALABLE(face)) {
766 for (int i = 0; i < face->num_fixed_sizes; ++i) {
767 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
768 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
770 FT_Select_Size(face, i);
771 metrics.ascender = face->size->metrics.ascender;
772 metrics.descender = face->size->metrics.descender;
773 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
775 face->face_flags |= FT_FACE_FLAG_SCALABLE;
782 fontDef.styleName = QString::fromUtf8(face->style_name);
786 fsType = freetype->fsType();
787 defaultGlyphSet.id = allocateServerGlyphSet();
791 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
793 default_hint_style = style;
796 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
797 bool &hsubpixel, int &vfactor) const
799 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
800 int load_target = default_hint_style == HintLight
801 ? FT_LOAD_TARGET_LIGHT
802 : FT_LOAD_TARGET_NORMAL;
804 if (format == Format_Mono) {
805 load_target = FT_LOAD_TARGET_MONO;
806 } else if (format == Format_A32) {
807 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
808 if (default_hint_style == HintFull)
809 load_target = FT_LOAD_TARGET_LCD;
811 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
812 if (default_hint_style == HintFull)
813 load_target = FT_LOAD_TARGET_LCD_V;
818 if (set && set->outline_drawing)
819 load_flags = FT_LOAD_NO_BITMAP;
821 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
822 load_flags |= FT_LOAD_NO_HINTING;
824 load_flags |= load_target;
829 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
830 QFixed subPixelPosition,
832 bool fetchMetricsOnly) const
834 // Q_ASSERT(freetype->lock == 1);
836 bool uploadToServer = false;
837 if (format == Format_None) {
838 if (defaultFormat != Format_None) {
839 format = defaultFormat;
840 if (canUploadGlyphsToServer)
841 uploadToServer = true;
843 format = Format_Mono;
847 Glyph *g = set->getGlyph(glyph, subPixelPosition);
848 if (g && g->format == format) {
849 if (uploadToServer && !g->uploadedToServer) {
850 set->setGlyph(glyph, subPixelPosition, 0);
858 QFontEngineFT::GlyphInfo info;
860 Q_ASSERT(format != Format_None);
861 bool hsubpixel = false;
863 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
866 if (format != Format_Mono && !embeddedbitmap)
867 load_flags |= FT_LOAD_NO_BITMAP;
870 FT_Matrix matrix = freetype->matrix;
871 bool transform = matrix.xx != 0x10000
872 || matrix.yy != 0x10000
877 load_flags |= FT_LOAD_NO_BITMAP;
879 FT_Face face = freetype->face;
882 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
884 FT_Set_Transform(face, &freetype->matrix, &v);
886 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
887 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
888 load_flags &= ~FT_LOAD_NO_BITMAP;
889 err = FT_Load_Glyph(face, glyph, load_flags);
891 if (err == FT_Err_Too_Few_Arguments) {
892 // this is an error in the bytecode interpreter, just try to run without it
893 load_flags |= FT_LOAD_FORCE_AUTOHINT;
894 err = FT_Load_Glyph(face, glyph, load_flags);
896 if (err != FT_Err_Ok)
897 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
899 if (set->outline_drawing && fetchMetricsOnly)
902 FT_GlyphSlot slot = face->glyph;
903 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
905 Q_FT_GLYPHSLOT_OBLIQUE(slot);
907 // While Embolden alters the metrics of the slot, oblique does not, so we need
908 // to fix this ourselves.
916 FT_Matrix_Multiply(&m, &matrix);
919 FT_Library library = qt_getFreetype();
921 info.xOff = TRUNC(ROUND(slot->advance.x));
924 uchar *glyph_buffer = 0;
925 int glyph_buffer_size = 0;
926 #if defined(QT_USE_FREETYPE_LCDFILTER)
927 bool useFreetypeRenderGlyph = false;
928 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
929 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
930 if (err == FT_Err_Ok)
931 useFreetypeRenderGlyph = true;
934 if (useFreetypeRenderGlyph) {
935 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
937 if (err != FT_Err_Ok)
938 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
940 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
942 info.height = slot->bitmap.rows / vfactor;
943 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
944 info.x = -slot->bitmap_left;
945 info.y = slot->bitmap_top;
947 glyph_buffer_size = info.width * info.height * 4;
948 glyph_buffer = new uchar[glyph_buffer_size];
951 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
952 else if (vfactor != 1)
953 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
957 int left = slot->metrics.horiBearingX;
958 int right = slot->metrics.horiBearingX + slot->metrics.width;
959 int top = slot->metrics.horiBearingY;
960 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
961 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
966 FT_Vector_Transform(&vector, &matrix);
971 FT_Vector_Transform(&vector, &matrix);
972 if (l > vector.x) l = vector.x;
973 if (r < vector.x) r = vector.x;
974 if (t < vector.y) t = vector.y;
975 if (b > vector.y) b = vector.y;
978 FT_Vector_Transform(&vector, &matrix);
979 if (l > vector.x) l = vector.x;
980 if (r < vector.x) r = vector.x;
981 if (t < vector.y) t = vector.y;
982 if (b > vector.y) b = vector.y;
985 FT_Vector_Transform(&vector, &matrix);
986 if (l > vector.x) l = vector.x;
987 if (r < vector.x) r = vector.x;
988 if (t < vector.y) t = vector.y;
989 if (b > vector.y) b = vector.y;
997 bottom = FLOOR(bottom);
1000 int hpixels = TRUNC(right - left);
1001 // subpixel position requires one more pixel
1002 if (subPixelPosition > 0 && format != Format_Mono)
1006 hpixels = hpixels*3 + 8;
1007 info.width = hpixels;
1008 info.height = TRUNC(top - bottom);
1009 info.x = -TRUNC(left);
1010 info.y = TRUNC(top);
1016 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1017 || ((uchar)(info.width) != info.width)
1018 || ((uchar)(info.height) != info.height)
1019 || ((signed char)(info.x) != info.x)
1020 || ((signed char)(info.y) != info.y)
1021 || ((signed char)(info.xOff) != info.xOff));
1024 delete [] glyph_buffer;
1028 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1029 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1030 glyph_buffer_size = pitch * info.height;
1031 glyph_buffer = new uchar[glyph_buffer_size];
1033 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1035 bitmap.rows = info.height*vfactor;
1036 bitmap.width = hpixels;
1037 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1038 if (!hsubpixel && vfactor == 1)
1039 bitmap.buffer = glyph_buffer;
1041 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1042 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1043 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1045 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1046 matrix.yy = vfactor << 16;
1047 matrix.yx = matrix.xy = 0;
1049 FT_Outline_Transform(&slot->outline, &matrix);
1050 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1051 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1053 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1054 Q_ASSERT(antialias);
1055 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1056 bool useLegacyLcdFilter = false;
1057 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1058 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1060 uchar *buffer = bitmap.buffer;
1061 if (!useLegacyLcdFilter) {
1062 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1063 buffer = convoluted;
1065 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1066 delete [] convoluted;
1067 } else if (vfactor != 1) {
1068 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1071 if (bitmap.buffer != glyph_buffer)
1072 delete [] bitmap.buffer;
1073 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1074 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1075 uchar *src = slot->bitmap.buffer;
1076 uchar *dst = glyph_buffer;
1077 int h = slot->bitmap.rows;
1078 if (format == Format_Mono) {
1079 int bytes = ((info.width + 7) & ~7) >> 3;
1081 memcpy (dst, src, bytes);
1083 src += slot->bitmap.pitch;
1088 uint *dd = (uint *)dst;
1090 for (int x = 0; x < slot->bitmap.width; x++) {
1091 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1096 src += slot->bitmap.pitch;
1098 } else if (vfactor != 1) {
1100 uint *dd = (uint *)dst;
1101 for (int x = 0; x < slot->bitmap.width; x++) {
1102 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1106 src += slot->bitmap.pitch;
1110 for (int x = 0; x < slot->bitmap.width; x++) {
1111 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1115 src += slot->bitmap.pitch;
1120 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1121 delete [] glyph_buffer;
1129 g->uploadedToServer = false;
1133 g->linearAdvance = slot->linearHoriAdvance >> 10;
1134 g->width = info.width;
1135 g->height = info.height;
1138 g->advance = info.xOff;
1141 g->data = glyph_buffer;
1143 if (uploadToServer) {
1144 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1147 set->setGlyph(glyph, subPixelPosition, g);
1152 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1158 Q_UNUSED(glyphDataSize);
1162 QFontEngine::FaceId QFontEngineFT::faceId() const
1167 QFontEngine::Properties QFontEngineFT::properties() const
1169 Properties p = freetype->properties();
1170 if (p.postscriptName.isEmpty()) {
1171 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1174 return freetype->properties();
1177 QFixed QFontEngineFT::emSquareSize() const
1179 if (FT_IS_SCALABLE(freetype->face))
1180 return freetype->face->units_per_EM;
1182 return freetype->face->size->metrics.y_ppem;
1185 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1187 return freetype->getSfntTable(tag, buffer, length);
1190 int QFontEngineFT::synthesized() const
1193 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1194 s = SynthesizedItalic;
1195 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1196 s |= SynthesizedBold;
1197 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1198 s |= SynthesizedStretch;
1202 QFixed QFontEngineFT::ascent() const
1204 return QFixed::fromFixed(metrics.ascender);
1207 QFixed QFontEngineFT::descent() const
1209 // subtract a pixel to work around QFontMetrics's built-in + 1
1210 return QFixed::fromFixed(-metrics.descender - 64);
1213 QFixed QFontEngineFT::leading() const
1215 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1218 QFixed QFontEngineFT::xHeight() const
1220 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1221 if (os2 && os2->sxHeight) {
1223 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1227 return QFontEngine::xHeight();
1230 QFixed QFontEngineFT::averageCharWidth() const
1232 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1233 if (os2 && os2->xAvgCharWidth) {
1235 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1239 return QFontEngine::averageCharWidth();
1242 qreal QFontEngineFT::maxCharWidth() const
1244 return metrics.max_advance >> 6;
1247 static const ushort char_table[] = {
1268 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1271 qreal QFontEngineFT::minLeftBearing() const
1273 if (lbearing == SHRT_MIN)
1274 (void) minRightBearing(); // calculates both
1275 return lbearing.toReal();
1278 qreal QFontEngineFT::minRightBearing() const
1280 if (rbearing == SHRT_MIN) {
1281 lbearing = rbearing = 0;
1282 const QChar *ch = (const QChar *)(const void*)char_table;
1283 QGlyphLayoutArray<char_table_entries> glyphs;
1284 int ng = char_table_entries;
1285 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1287 if (glyphs.glyphs[ng]) {
1288 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1289 lbearing = qMin(lbearing, gi.x);
1290 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1294 return rbearing.toReal();
1297 QFixed QFontEngineFT::lineThickness() const
1299 return line_thickness;
1302 QFixed QFontEngineFT::underlinePosition() const
1304 return underline_position;
1307 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1309 if (!kerning_pairs_loaded) {
1310 kerning_pairs_loaded = true;
1312 if (freetype->face->size->metrics.x_ppem != 0) {
1313 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1315 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1320 QFontEngine::doKerning(g, flags);
1323 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1325 if (matrix.type() > QTransform::TxShear)
1328 // FT_Set_Transform only supports scalable fonts
1329 if (!FT_IS_SCALABLE(freetype->face))
1333 m.xx = FT_Fixed(matrix.m11() * 65536);
1334 m.xy = FT_Fixed(-matrix.m21() * 65536);
1335 m.yx = FT_Fixed(-matrix.m12() * 65536);
1336 m.yy = FT_Fixed(matrix.m22() * 65536);
1340 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1341 const QGlyphSet &g = transformedGlyphSets.at(i);
1342 if (g.transformationMatrix.xx == m.xx
1343 && g.transformationMatrix.xy == m.xy
1344 && g.transformationMatrix.yx == m.yx
1345 && g.transformationMatrix.yy == m.yy) {
1347 // found a match, move it to the front
1348 transformedGlyphSets.move(i, 0);
1349 gs = &transformedGlyphSets[0];
1355 // don't try to load huge fonts
1356 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1357 if (draw_as_outline)
1360 // don't cache more than 10 transformations
1361 if (transformedGlyphSets.count() >= 10) {
1362 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1363 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1365 transformedGlyphSets.prepend(QGlyphSet());
1367 gs = &transformedGlyphSets[0];
1371 gs->id = allocateServerGlyphSet();
1373 gs->transformationMatrix = m;
1374 gs->outline_drawing = draw_as_outline;
1380 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1381 const QFixedPoint *positions,
1386 for (int i = 0; i < num_glyphs; ++i) {
1387 QFixed spp = subPixelPositionForX(positions[i].x);
1388 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1389 if (glyph == 0 || glyph->format != format) {
1392 FT_Matrix m = matrix;
1393 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1394 FT_Set_Transform(face, &m, 0);
1395 freetype->matrix = m;
1397 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1410 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1412 FT_Face face = lockFace(Unscaled);
1413 FT_Set_Transform(face, 0, 0);
1414 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1416 int left = face->glyph->metrics.horiBearingX;
1417 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1418 int top = face->glyph->metrics.horiBearingY;
1419 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1425 metrics->width = QFixed::fromFixed(right-left);
1426 metrics->height = QFixed::fromFixed(top-bottom);
1427 metrics->x = QFixed::fromFixed(left);
1428 metrics->y = QFixed::fromFixed(-top);
1429 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1431 if (!FT_IS_SCALABLE(freetype->face))
1432 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1434 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1436 FT_Set_Transform(face, &freetype->matrix, 0);
1440 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1442 uint ucs4 = str[i].unicode();
1443 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1445 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1450 bool QFontEngineFT::canRender(const QChar *string, int len)
1452 FT_Face face = freetype->face;
1456 for ( int i = 0; i < len; i++ ) {
1457 unsigned int uc = getChar(string, i, len);
1458 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1467 for ( int i = 0; i < len; i++ ) {
1468 unsigned int uc = getChar(string, i, len);
1469 if (!FT_Get_Char_Index(face, uc))
1476 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1478 if (!glyphs.numGlyphs)
1481 if (FT_IS_SCALABLE(freetype->face)) {
1482 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1484 QVarLengthArray<QFixedPoint> positions;
1485 QVarLengthArray<glyph_t> positioned_glyphs;
1487 matrix.translate(x, y);
1488 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1490 FT_Face face = lockFace(Unscaled);
1491 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1492 FT_UInt glyph = positioned_glyphs[gl];
1493 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1494 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1500 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1501 QPainterPath *path, QTextItem::RenderFlags)
1503 FT_Face face = lockFace(Unscaled);
1505 for (int gl = 0; gl < numGlyphs; gl++) {
1506 FT_UInt glyph = glyphs[gl];
1508 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1510 FT_GlyphSlot g = face->glyph;
1511 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1513 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1514 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1515 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1520 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1521 QTextEngine::ShaperFlags flags) const
1523 if (*nglyphs < len) {
1528 #if !defined(QT_NO_FONTCONFIG)
1529 extern QMutex *qt_fontdatabase_mutex();
1533 bool mirrored = flags & QTextEngine::RightToLeft;
1535 if (freetype->symbol_map) {
1536 FT_Face face = freetype->face;
1537 for ( int i = 0; i < len; ++i ) {
1538 unsigned int uc = getChar(str, i, len);
1539 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1540 if ( !glyphs->glyphs[glyph_pos] ) {
1542 #if !defined(QT_NO_FONTCONFIG)
1544 mtx = qt_fontdatabase_mutex();
1548 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1553 glyph = FT_Get_Char_Index(face, uc);
1554 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1559 FT_Set_Charmap(face, freetype->symbol_map);
1560 glyph = FT_Get_Char_Index(face, uc);
1561 FT_Set_Charmap(face, freetype->unicode_map);
1563 glyphs->glyphs[glyph_pos] = glyph;
1564 if (uc < QFreetypeFace::cmapCacheSize)
1565 freetype->cmapCache[uc] = glyph;
1570 FT_Face face = freetype->face;
1571 for (int i = 0; i < len; ++i) {
1572 unsigned int uc = getChar(str, i, len);
1574 uc = QChar::mirroredChar(uc);
1575 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1576 if (!glyphs->glyphs[glyph_pos]) {
1577 #if !defined(QT_NO_FONTCONFIG)
1579 mtx = qt_fontdatabase_mutex();
1583 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1587 glyph_t glyph = FT_Get_Char_Index(face, uc);
1588 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1592 glyphs->glyphs[glyph_pos] = glyph;
1593 if (uc < QFreetypeFace::cmapCacheSize)
1594 freetype->cmapCache[uc] = glyph;
1601 *nglyphs = glyph_pos;
1602 glyphs->numGlyphs = glyph_pos;
1604 #if !defined(QT_NO_FONTCONFIG)
1609 if (flags & QTextEngine::GlyphIndicesOnly)
1612 recalcAdvances(glyphs, flags);
1617 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1620 bool design = (default_hint_style == HintNone ||
1621 default_hint_style == HintLight ||
1622 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1623 for (int i = 0; i < glyphs->numGlyphs; i++) {
1624 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1626 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1630 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1631 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1632 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1634 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1635 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1636 glyphs->advances_y[i] = 0;
1642 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1647 glyph_metrics_t overall;
1648 // initialize with line height, we get the same behaviour on all platforms
1649 overall.y = -ascent();
1650 overall.height = ascent() + descent() + 1;
1654 for (int i = 0; i < glyphs.numGlyphs; i++) {
1655 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1659 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1662 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1663 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1664 overall.x = qMin(overall.x, x);
1665 overall.y = qMin(overall.y, y);
1666 xmax = qMax(xmax, x + g->width);
1667 ymax = qMax(ymax, y + g->height);
1668 overall.xoff += g->advance;
1670 int left = FLOOR(face->glyph->metrics.horiBearingX);
1671 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1672 int top = CEIL(face->glyph->metrics.horiBearingY);
1673 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1675 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1676 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1677 overall.x = qMin(overall.x, x);
1678 overall.y = qMin(overall.y, y);
1679 xmax = qMax(xmax, x + TRUNC(right - left));
1680 ymax = qMax(ymax, y + TRUNC(top - bottom));
1681 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1684 overall.height = qMax(overall.height, ymax - overall.y);
1685 overall.width = xmax - overall.x;
1693 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1696 glyph_metrics_t overall;
1697 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1700 g = loadGlyph(glyph, 0, Format_None, true);
1705 overall.width = g->width;
1706 overall.height = g->height;
1707 overall.xoff = g->advance;
1708 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1709 overall.xoff = overall.xoff.round();
1711 int left = FLOOR(face->glyph->metrics.horiBearingX);
1712 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1713 int top = CEIL(face->glyph->metrics.horiBearingY);
1714 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1716 overall.width = TRUNC(right-left);
1717 overall.height = TRUNC(top-bottom);
1718 overall.x = TRUNC(left);
1719 overall.y = -TRUNC(top);
1720 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1727 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1729 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1732 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1735 glyph_metrics_t overall;
1736 QGlyphSet *glyphSet = 0;
1737 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1738 // TODO move everything here to a method of its own to access glyphSets
1739 // to be shared with a new method that will replace loadTransformedGlyphSet()
1741 m.xx = FT_Fixed(matrix.m11() * 65536);
1742 m.xy = FT_Fixed(-matrix.m21() * 65536);
1743 m.yx = FT_Fixed(-matrix.m12() * 65536);
1744 m.yy = FT_Fixed(matrix.m22() * 65536);
1745 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1746 const QGlyphSet &g = transformedGlyphSets.at(i);
1747 if (g.transformationMatrix.xx == m.xx
1748 && g.transformationMatrix.xy == m.xy
1749 && g.transformationMatrix.yx == m.yx
1750 && g.transformationMatrix.yy == m.yy) {
1752 // found a match, move it to the front
1753 transformedGlyphSets.move(i, 0);
1754 glyphSet = &transformedGlyphSets[0];
1760 // don't cache more than 10 transformations
1761 if (transformedGlyphSets.count() >= 10) {
1762 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1763 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1765 transformedGlyphSets.prepend(QGlyphSet());
1767 glyphSet = &transformedGlyphSets[0];
1769 glyphSet->id = allocateServerGlyphSet();
1770 glyphSet->transformationMatrix = m;
1774 glyphSet = &defaultGlyphSet;
1776 Glyph * g = glyphSet->getGlyph(glyph);
1777 if (!g || g->format != format) {
1779 FT_Matrix m = this->matrix;
1780 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1781 freetype->matrix = m;
1782 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1788 overall.width = g->width;
1789 overall.height = g->height;
1790 overall.xoff = g->advance;
1792 int left = FLOOR(face->glyph->metrics.horiBearingX);
1793 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1794 int top = CEIL(face->glyph->metrics.horiBearingY);
1795 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1797 overall.width = TRUNC(right-left);
1798 overall.height = TRUNC(top-bottom);
1799 overall.x = TRUNC(left);
1800 overall.y = -TRUNC(top);
1801 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1808 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1809 QFontEngine::GlyphFormat neededFormat,
1810 const QTransform &t, QPoint *offset)
1812 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1816 neededFormat = Format_Mono;
1817 else if (neededFormat == Format_None && defaultFormat != Format_None)
1818 neededFormat = defaultFormat;
1819 else if (neededFormat == Format_None)
1820 neededFormat = Format_A8;
1822 QFontEngineFT::QGlyphSet *gset = defaultGlyphs();
1823 if (t.type() >= QTransform::TxScale) {
1825 gset = loadTransformedGlyphSet(t);
1830 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1833 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1837 QImage::Format format;
1838 switch (neededFormat) {
1839 case QFontEngine::Format_Mono:
1840 format = QImage::Format_Mono;
1842 case QFontEngine::Format_A8:
1843 format = QImage::Format_Indexed8;
1845 case QFontEngine::Format_A32:
1846 format = QImage::Format_ARGB32;
1850 format = QImage::Format_Invalid;
1853 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1854 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1860 switch (neededFormat) {
1861 case QFontEngineFT::Format_Mono:
1862 pitch = ((glyph->width + 31) & ~31) >> 3;
1864 case QFontEngineFT::Format_A8:
1865 pitch = (glyph->width + 3) & ~3;
1867 case QFontEngineFT::Format_A32:
1868 pitch = glyph->width * 4;
1876 *offset = QPoint(glyph->x, -glyph->y);
1879 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1880 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1882 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1883 data->is_locked = true;
1885 return ¤tlyLockedAlphaMap;
1888 void QFontEngineFT::unlockAlphaMapForGlyph()
1890 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1892 currentlyLockedAlphaMap = QImage();
1895 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1899 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1901 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1904 return QFontEngine::alphaMapForGlyph(g);
1907 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1909 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1911 QVector<QRgb> colors(256);
1912 for (int i=0; i<256; ++i)
1913 colors[i] = qRgba(0, 0, 0, i);
1914 img.setColorTable(colors);
1916 QVector<QRgb> colors(2);
1917 colors[0] = qRgba(0, 0, 0, 0);
1918 colors[1] = qRgba(0, 0, 0, 255);
1919 img.setColorTable(colors);
1921 Q_ASSERT(img.bytesPerLine() == pitch);
1923 for (int y = 0; y < glyph->height; ++y)
1924 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1931 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1933 if (t.type() > QTransform::TxTranslate)
1934 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1938 GlyphFormat glyph_format = Format_A32;
1940 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1943 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1946 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1947 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1953 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1955 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1958 int QFontEngineFT::glyphCount() const
1961 FT_Face face = lockFace();
1963 count = face->num_glyphs;
1969 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1972 FT_Face face = freetype->face;
1973 if (scale == Unscaled) {
1974 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1975 freetype->xsize = face->units_per_EM << 6;
1976 freetype->ysize = face->units_per_EM << 6;
1977 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1978 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1979 freetype->xsize = xsize;
1980 freetype->ysize = ysize;
1982 if (freetype->matrix.xx != matrix.xx ||
1983 freetype->matrix.yy != matrix.yy ||
1984 freetype->matrix.xy != matrix.xy ||
1985 freetype->matrix.yx != matrix.yx) {
1986 freetype->matrix = matrix;
1987 FT_Set_Transform(face, &freetype->matrix, 0);
1993 void QFontEngineFT::unlockFace() const
1998 FT_Face QFontEngineFT::non_locked_face() const
2000 return freetype->face;
2004 QFontEngineFT::QGlyphSet::QGlyphSet()
2005 : id(0), outline_drawing(false)
2007 transformationMatrix.xx = 0x10000;
2008 transformationMatrix.yy = 0x10000;
2009 transformationMatrix.xy = 0;
2010 transformationMatrix.yx = 0;
2011 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2012 fast_glyph_count = 0;
2015 QFontEngineFT::QGlyphSet::~QGlyphSet()
2020 void QFontEngineFT::QGlyphSet::clear()
2022 if (fast_glyph_count > 0) {
2023 for (int i = 0; i < 256; ++i) {
2024 if (fast_glyph_data[i]) {
2025 delete fast_glyph_data[i];
2026 fast_glyph_data[i] = 0;
2029 fast_glyph_count = 0;
2031 qDeleteAll(glyph_data);
2035 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2037 if (useFastGlyphData(index, subPixelPosition)) {
2038 if (fast_glyph_data[index]) {
2039 delete fast_glyph_data[index];
2040 fast_glyph_data[index] = 0;
2041 if (fast_glyph_count > 0)
2045 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2049 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2051 if (useFastGlyphData(index, subPixelPosition)) {
2052 if (!fast_glyph_data[index])
2054 fast_glyph_data[index] = glyph;
2056 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2060 unsigned long QFontEngineFT::allocateServerGlyphSet()
2065 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
2070 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2073 bool hsubpixel = true;
2075 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2076 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2081 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2083 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2086 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2088 freetype->ref.ref();
2090 default_load_flags = fe->default_load_flags;
2091 default_hint_style = fe->default_hint_style;
2092 antialias = fe->antialias;
2093 transform = fe->transform;
2094 embolden = fe->embolden;
2095 obliquen = fe->obliquen;
2096 subpixelType = fe->subpixelType;
2097 lcdFilterType = fe->lcdFilterType;
2098 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2099 embeddedbitmap = fe->embeddedbitmap;
2104 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2107 fontDef.pixelSize = pixelSize;
2108 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2109 if (!fe->initFromFontEngine(this)) {
2119 #endif // QT_NO_FREETYPE