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
84 * Freetype 2.1.7 and earlier used width/height
85 * for matching sizes in the BDF and PCF loaders.
86 * This has been fixed for 2.1.8.
88 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
89 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
90 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
92 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
93 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
96 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
97 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
98 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
100 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
103 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
104 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
105 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
106 #define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
108 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
111 #define FLOOR(x) ((x) & -64)
112 #define CEIL(x) (((x)+63) & -64)
113 #define TRUNC(x) ((x) >> 6)
114 #define ROUND(x) (((x)+32) & -64)
116 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
118 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
119 FT_Face face = (FT_Face)font;
120 FT_ULong ftlen = *length;
123 if ( !FT_IS_SFNT(face) )
124 return HB_Err_Invalid_Argument;
126 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
128 return (HB_Error)error;
130 return HB_Err_Invalid_Argument;
134 // -------------------------- Freetype support ------------------------------
144 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
148 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
150 QtFreetypeData *qt_getFreetypeData()
152 return theFreetypeData();
155 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
157 QtFreetypeData *qt_getFreetypeData()
159 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
161 freetypeData = new QtFreetypeData;
166 FT_Library qt_getFreetype()
168 QtFreetypeData *freetypeData = qt_getFreetypeData();
169 if (!freetypeData->library)
170 FT_Init_FreeType(&freetypeData->library);
171 return freetypeData->library;
174 int QFreetypeFace::fsType() const
177 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
179 fsType = os2->fsType;
183 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
185 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
188 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
189 return HB_Err_Invalid_SubTable;
191 *nPoints = face->glyph->outline.n_points;
195 if (point > *nPoints)
196 return HB_Err_Invalid_SubTable;
198 *xpos = face->glyph->outline.points[point].x;
199 *ypos = face->glyph->outline.points[point].y;
205 * One font file can contain more than one font (bold/italic for example)
206 * find the right one and return it.
208 * Returns the freetype face or 0 in case of an empty file or any other problems
209 * (like not being able to open the file)
211 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
212 const QByteArray &fontData)
214 if (face_id.filename.isEmpty() && fontData.isEmpty())
217 QtFreetypeData *freetypeData = qt_getFreetypeData();
218 if (!freetypeData->library)
219 FT_Init_FreeType(&freetypeData->library);
221 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
225 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
227 if (!face_id.filename.isEmpty()) {
228 QFile file(QString::fromUtf8(face_id.filename));
229 if (face_id.filename.startsWith(":qmemoryfonts/")) {
230 // from qfontdatabase.cpp
231 extern QByteArray qt_fontdata_from_index(int);
232 QByteArray idx = face_id.filename;
233 idx.remove(0, 14); // remove ':qmemoryfonts/'
235 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
237 newFreetype->fontData = QByteArray();
238 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
239 if (!file.open(QIODevice::ReadOnly)) {
242 newFreetype->fontData = file.readAll();
245 newFreetype->fontData = fontData;
247 if (!newFreetype->fontData.isEmpty()) {
248 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
251 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
254 newFreetype->face = face;
256 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
257 Q_CHECK_PTR(newFreetype->hbFace);
258 newFreetype->ref = 1;
259 newFreetype->xsize = 0;
260 newFreetype->ysize = 0;
261 newFreetype->matrix.xx = 0x10000;
262 newFreetype->matrix.yy = 0x10000;
263 newFreetype->matrix.xy = 0;
264 newFreetype->matrix.yx = 0;
265 newFreetype->unicode_map = 0;
266 newFreetype->symbol_map = 0;
267 #ifndef QT_NO_FONTCONFIG
268 newFreetype->charset = 0;
271 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
273 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
274 FT_CharMap cm = newFreetype->face->charmaps[i];
275 switch(cm->encoding) {
276 case FT_ENCODING_UNICODE:
277 newFreetype->unicode_map = cm;
279 case FT_ENCODING_APPLE_ROMAN:
280 case FT_ENCODING_ADOBE_LATIN_1:
281 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
282 newFreetype->unicode_map = cm;
284 case FT_ENCODING_ADOBE_CUSTOM:
285 case FT_ENCODING_MS_SYMBOL:
286 if (!newFreetype->symbol_map)
287 newFreetype->symbol_map = cm;
294 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
295 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
298 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
299 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
300 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
301 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
302 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
304 for (int i = 0; i < 256; i += 8)
305 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
306 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
307 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
308 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
309 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
312 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
314 freetypeData->faces.insert(face_id, newFreetype.data());
316 newFreetype.take()->release(face_id);
317 // we could return null in principle instead of throwing
320 freetype = newFreetype.take();
325 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
327 QtFreetypeData *freetypeData = qt_getFreetypeData();
331 #ifndef QT_NO_FONTCONFIG
333 FcCharSetDestroy(charset);
335 if(freetypeData->faces.contains(face_id))
336 freetypeData->faces.take(face_id);
339 if (freetypeData->faces.isEmpty()) {
340 FT_Done_FreeType(freetypeData->library);
341 freetypeData->library = 0;
346 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
348 *ysize = qRound(fontDef.pixelSize * 64);
349 *xsize = *ysize * fontDef.stretch / 100;
350 *outline_drawing = false;
353 * Bitmap only faces must match exactly, so find the closest
354 * one (height dominant search)
356 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
358 for (int i = 1; i < face->num_fixed_sizes; i++) {
359 if (qAbs(*ysize - Y_SIZE(face,i)) <
360 qAbs (*ysize - Y_SIZE(face, best)) ||
361 (qAbs (*ysize - Y_SIZE(face, i)) ==
362 qAbs (*ysize - Y_SIZE(face, best)) &&
363 qAbs (*xsize - X_SIZE(face, i)) <
364 qAbs (*xsize - X_SIZE(face, best)))) {
368 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
369 *xsize = X_SIZE(face, best);
370 *ysize = Y_SIZE(face, best);
373 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
374 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
375 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
376 if (err && face->num_fixed_sizes == 1)
377 err = 0; //even more of a workaround...
384 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
388 QFontEngine::Properties QFreetypeFace::properties() const
390 QFontEngine::Properties p;
391 p.postscriptName = FT_Get_Postscript_Name(face);
392 PS_FontInfoRec font_info;
393 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
394 p.copyright = font_info.notice;
395 if (FT_IS_SCALABLE(face)) {
396 p.ascent = face->ascender;
397 p.descent = -face->descender;
398 p.leading = face->height - face->ascender + face->descender;
399 p.emSquare = face->units_per_EM;
400 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
401 face->bbox.xMax - face->bbox.xMin,
402 face->bbox.yMax - face->bbox.yMin);
404 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
405 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
406 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
407 p.emSquare = face->size->metrics.y_ppem;
408 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
409 p.boundingBox = QRectF(0, -p.ascent.toReal(),
410 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
413 p.capHeight = p.ascent;
414 p.lineWidth = face->underline_thickness;
418 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
421 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
422 if (FT_IS_SFNT(face)) {
423 FT_ULong len = *length;
424 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
431 /* Some fonts (such as MingLiu rely on hinting to scale different
432 components to their correct sizes. While this is really broken (it
433 should be done in the component glyph itself, not the hinter) we
434 will have to live with it.
436 This means we can not use FT_LOAD_NO_HINTING to get the glyph
437 outline. All we can do is to load the unscaled glyph and scale it
438 down manually when required.
440 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
442 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
443 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
444 FT_Vector *p = g->outline.points;
445 const FT_Vector *e = p + g->outline.n_points;
447 p->x = FT_MulFix(p->x, x_scale);
448 p->y = FT_MulFix(p->y, y_scale);
453 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
455 const qreal factor = 1/64.;
456 scaleOutline(face, g, x_scale, y_scale);
458 QPointF cp = point.toPointF();
460 // convert the outline to a painter path
462 for (int j = 0; j < g->outline.n_contours; ++j) {
463 int last_point = g->outline.contours[j];
464 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
465 if(!(g->outline.tags[i] & 1)) {
466 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
469 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
470 // qDebug("first point at %f %f", start.x(), start.y());
476 while (i < last_point) {
478 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
479 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
481 switch (g->outline.tags[i] & 3) {
483 // cubic bezier element
486 c[3] = (c[3] + c[2])/2;
490 // quadratic bezier element
493 c[3] = (c[1] + c[2])/2;
494 c[2] = (2*c[1] + c[3])/3;
495 c[1] = (2*c[1] + c[0])/3;
501 // qDebug() << "lineTo" << c[1];
508 c[2] = (2*c[1] + c[3])/3;
509 c[1] = (2*c[1] + c[0])/3;
513 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
514 path->cubicTo(c[1], c[2], c[3]);
519 // qDebug() << "closeSubpath";
520 path->closeSubpath();
524 c[2] = (2*c[1] + c[3])/3;
525 c[1] = (2*c[1] + c[0])/3;
527 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
528 path->cubicTo(c[1], c[2], c[3]);
534 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
536 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
538 if (slot->format != FT_GLYPH_FORMAT_BITMAP
539 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
542 QPointF cp = point.toPointF();
543 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
544 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
547 QFontEngineFT::Glyph::~Glyph()
552 static const uint subpixel_filter[3][3] = {
558 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
562 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
563 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
564 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
565 res = (mid << 24) + (high << 16) + (mid << 8) + low;
568 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
573 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
576 const int offs = bgr ? -1 : 1;
577 const int w = width * 3;
580 for (int x = 0; x < w; x += 3) {
581 uint red = src[x+1-offs];
582 uint green = src[x+1];
583 uint blue = src[x+1+offs];
584 *dd = filterPixel(red, green, blue, legacyFilter);
592 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
595 const int offs = bgr ? -src_pitch : src_pitch;
597 for (int x = 0; x < width; x++) {
598 uint red = src[x+src_pitch-offs];
599 uint green = src[x+src_pitch];
600 uint blue = src[x+src_pitch+offs];
601 dst[x] = filterPixel(red, green, blue, legacyFilter);
608 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
610 // convolute the bitmap with a triangle filter to get rid of color fringes
611 // If we take account for a gamma value of 2, we end up with
612 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
613 // as this nicely sums up to 16 :)
618 for (int x = 2; x < width - 2; ++x) {
619 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
620 dst[x] = (uchar) (sum >> 4);
622 dst[width - 2] = dst[width - 1] = 0;
628 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
636 kerning_pairs_loaded = false;
642 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
643 default_hint_style = HintNone;
644 subpixelType = Subpixel_None;
646 #if defined(FT_LCD_FILTER_H)
647 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
649 defaultFormat = Format_None;
650 canUploadGlyphsToServer = false;
651 embeddedbitmap = false;
654 QFontEngineFT::~QFontEngineFT()
657 freetype->release(face_id);
658 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
661 void QFontEngineFT::freeGlyphSets()
663 freeServerGlyphSet(defaultGlyphSet.id);
664 for (int i = 0; i < transformedGlyphSets.count(); ++i)
665 freeServerGlyphSet(transformedGlyphSets.at(i).id);
668 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
669 const QByteArray &fontData)
671 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
674 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
675 QFreetypeFace *freetypeFace)
677 freetype = freetypeFace;
683 defaultFormat = format;
684 this->antialias = antialias;
687 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
688 else if (format == Format_A8)
689 glyphFormat = QFontEngineGlyphCache::Raster_A8;
690 else if (format == Format_A32)
691 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
695 symbol = freetype->symbol_map != 0;
696 PS_FontInfoRec psrec;
697 // don't assume that type1 fonts are symbol fonts by default
698 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
699 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
702 freetype->hbFace->isSymbolFont = symbol;
704 lbearing = rbearing = SHRT_MIN;
705 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
707 FT_Face face = lockFace();
709 if (FT_IS_SCALABLE(face)) {
710 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
712 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
713 matrix.xy = 0x10000*3/10;
719 FT_Set_Transform(face, &matrix, 0);
720 freetype->matrix = matrix;
722 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
725 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
726 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
728 // copied from QFontEngineQPF
730 int score = fontDef.weight * fontDef.pixelSize;
731 line_thickness = score / 700;
732 // looks better with thicker line for small pointsizes
733 if (line_thickness < 2 && score >= 1050)
735 underline_position = ((line_thickness * 2) + 3) / 6;
737 if (line_thickness < 1)
740 hbFont.x_ppem = face->size->metrics.x_ppem;
741 hbFont.y_ppem = face->size->metrics.y_ppem;
742 hbFont.x_scale = face->size->metrics.x_scale;
743 hbFont.y_scale = face->size->metrics.y_scale;
745 hbFace = freetype->hbFace;
747 metrics = face->size->metrics;
749 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
751 TrueType fonts with embedded bitmaps may have a bitmap font specific
752 ascent/descent in the EBLC table. There is no direct public API
753 to extract those values. The only way we've found is to trick freetype
754 into thinking that it's not a scalable font in FT_SelectSize so that
755 the metrics are retrieved from the bitmap strikes.
757 if (FT_IS_SCALABLE(face)) {
758 for (int i = 0; i < face->num_fixed_sizes; ++i) {
759 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
760 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
762 FT_Select_Size(face, i);
763 metrics.ascender = face->size->metrics.ascender;
764 metrics.descender = face->size->metrics.descender;
765 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
767 face->face_flags |= FT_FACE_FLAG_SCALABLE;
774 fontDef.styleName = QString::fromUtf8(face->style_name);
778 fsType = freetype->fsType();
779 defaultGlyphSet.id = allocateServerGlyphSet();
783 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
785 default_hint_style = style;
788 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
789 bool &hsubpixel, int &vfactor) const
791 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
792 int load_target = default_hint_style == HintLight
793 ? FT_LOAD_TARGET_LIGHT
794 : FT_LOAD_TARGET_NORMAL;
796 if (format == Format_Mono) {
797 load_target = FT_LOAD_TARGET_MONO;
798 } else if (format == Format_A32) {
799 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
800 if (default_hint_style == HintFull)
801 load_target = FT_LOAD_TARGET_LCD;
803 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
804 if (default_hint_style == HintFull)
805 load_target = FT_LOAD_TARGET_LCD_V;
810 if (set && set->outline_drawing)
811 load_flags = FT_LOAD_NO_BITMAP;
813 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || set->outline_drawing)
814 load_flags |= FT_LOAD_NO_HINTING;
816 load_flags |= load_target;
821 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
822 QFixed subPixelPosition,
824 bool fetchMetricsOnly) const
826 // Q_ASSERT(freetype->lock == 1);
828 bool uploadToServer = false;
829 if (format == Format_None) {
830 if (defaultFormat != Format_None) {
831 format = defaultFormat;
832 if (canUploadGlyphsToServer)
833 uploadToServer = true;
835 format = Format_Mono;
839 Glyph *g = set->getGlyph(glyph, subPixelPosition);
840 if (g && g->format == format) {
841 if (uploadToServer && !g->uploadedToServer) {
842 set->setGlyph(glyph, subPixelPosition, 0);
850 QFontEngineFT::GlyphInfo info;
852 Q_ASSERT(format != Format_None);
853 bool hsubpixel = false;
855 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
858 if (format != Format_Mono && !embeddedbitmap)
859 load_flags |= FT_LOAD_NO_BITMAP;
862 FT_Matrix matrix = freetype->matrix;
863 bool transform = matrix.xx != 0x10000
864 || matrix.yy != 0x10000
869 load_flags |= FT_LOAD_NO_BITMAP;
871 FT_Face face = freetype->face;
874 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
876 FT_Set_Transform(face, &freetype->matrix, &v);
878 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
879 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
880 load_flags &= ~FT_LOAD_NO_BITMAP;
881 err = FT_Load_Glyph(face, glyph, load_flags);
883 if (err == FT_Err_Too_Few_Arguments) {
884 // this is an error in the bytecode interpreter, just try to run without it
885 load_flags |= FT_LOAD_FORCE_AUTOHINT;
886 err = FT_Load_Glyph(face, glyph, load_flags);
888 if (err != FT_Err_Ok)
889 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
891 if (set->outline_drawing && fetchMetricsOnly)
894 FT_GlyphSlot slot = face->glyph;
895 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
897 Q_FT_GLYPHSLOT_OBLIQUE(slot);
899 // While Embolden alters the metrics of the slot, oblique does not, so we need
900 // to fix this ourselves.
908 FT_Matrix_Multiply(&m, &matrix);
911 FT_Library library = qt_getFreetype();
913 info.xOff = TRUNC(ROUND(slot->advance.x));
916 uchar *glyph_buffer = 0;
917 int glyph_buffer_size = 0;
918 #if defined(QT_USE_FREETYPE_LCDFILTER)
919 bool useFreetypeRenderGlyph = false;
920 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
921 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
922 if (err == FT_Err_Ok)
923 useFreetypeRenderGlyph = true;
926 if (useFreetypeRenderGlyph) {
927 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
929 if (err != FT_Err_Ok)
930 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
932 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
934 info.height = slot->bitmap.rows / vfactor;
935 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
936 info.x = -slot->bitmap_left;
937 info.y = slot->bitmap_top;
939 glyph_buffer_size = info.width * info.height * 4;
940 glyph_buffer = new uchar[glyph_buffer_size];
943 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
944 else if (vfactor != 1)
945 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
949 int left = slot->metrics.horiBearingX;
950 int right = slot->metrics.horiBearingX + slot->metrics.width;
951 int top = slot->metrics.horiBearingY;
952 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
953 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
958 FT_Vector_Transform(&vector, &matrix);
963 FT_Vector_Transform(&vector, &matrix);
964 if (l > vector.x) l = vector.x;
965 if (r < vector.x) r = vector.x;
966 if (t < vector.y) t = vector.y;
967 if (b > vector.y) b = vector.y;
970 FT_Vector_Transform(&vector, &matrix);
971 if (l > vector.x) l = vector.x;
972 if (r < vector.x) r = vector.x;
973 if (t < vector.y) t = vector.y;
974 if (b > vector.y) b = vector.y;
977 FT_Vector_Transform(&vector, &matrix);
978 if (l > vector.x) l = vector.x;
979 if (r < vector.x) r = vector.x;
980 if (t < vector.y) t = vector.y;
981 if (b > vector.y) b = vector.y;
989 bottom = FLOOR(bottom);
992 int hpixels = TRUNC(right - left);
993 // subpixel position requires one more pixel
994 if (subPixelPosition > 0 && format != Format_Mono)
998 hpixels = hpixels*3 + 8;
999 info.width = hpixels;
1000 info.height = TRUNC(top - bottom);
1001 info.x = -TRUNC(left);
1002 info.y = TRUNC(top);
1008 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1009 || ((uchar)(info.width) != info.width)
1010 || ((uchar)(info.height) != info.height)
1011 || ((signed char)(info.x) != info.x)
1012 || ((signed char)(info.y) != info.y)
1013 || ((signed char)(info.xOff) != info.xOff));
1016 delete [] glyph_buffer;
1020 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1021 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1022 glyph_buffer_size = pitch * info.height;
1023 glyph_buffer = new uchar[glyph_buffer_size];
1025 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1027 bitmap.rows = info.height*vfactor;
1028 bitmap.width = hpixels;
1029 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1030 if (!hsubpixel && vfactor == 1)
1031 bitmap.buffer = glyph_buffer;
1033 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1034 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1035 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1037 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1038 matrix.yy = vfactor << 16;
1039 matrix.yx = matrix.xy = 0;
1041 FT_Outline_Transform(&slot->outline, &matrix);
1042 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1043 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1045 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1046 Q_ASSERT(antialias);
1047 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1048 bool useLegacyLcdFilter = false;
1049 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1050 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1052 uchar *buffer = bitmap.buffer;
1053 if (!useLegacyLcdFilter) {
1054 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1055 buffer = convoluted;
1057 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1058 delete [] convoluted;
1059 } else if (vfactor != 1) {
1060 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1063 if (bitmap.buffer != glyph_buffer)
1064 delete [] bitmap.buffer;
1065 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1066 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1067 uchar *src = slot->bitmap.buffer;
1068 uchar *dst = glyph_buffer;
1069 int h = slot->bitmap.rows;
1070 if (format == Format_Mono) {
1071 int bytes = ((info.width + 7) & ~7) >> 3;
1073 memcpy (dst, src, bytes);
1075 src += slot->bitmap.pitch;
1080 uint *dd = (uint *)dst;
1082 for (int x = 0; x < slot->bitmap.width; x++) {
1083 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1088 src += slot->bitmap.pitch;
1090 } else if (vfactor != 1) {
1092 uint *dd = (uint *)dst;
1093 for (int x = 0; x < slot->bitmap.width; x++) {
1094 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1098 src += slot->bitmap.pitch;
1102 for (int x = 0; x < slot->bitmap.width; x++) {
1103 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1107 src += slot->bitmap.pitch;
1112 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1113 delete [] glyph_buffer;
1121 g->uploadedToServer = false;
1125 g->linearAdvance = slot->linearHoriAdvance >> 10;
1126 g->width = info.width;
1127 g->height = info.height;
1130 g->advance = info.xOff;
1133 g->data = glyph_buffer;
1135 if (uploadToServer) {
1136 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1139 set->setGlyph(glyph, subPixelPosition, g);
1144 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1150 Q_UNUSED(glyphDataSize);
1154 QFontEngine::FaceId QFontEngineFT::faceId() const
1159 QFontEngine::Properties QFontEngineFT::properties() const
1161 Properties p = freetype->properties();
1162 if (p.postscriptName.isEmpty()) {
1163 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1166 return freetype->properties();
1169 QFixed QFontEngineFT::emSquareSize() const
1171 if (FT_IS_SCALABLE(freetype->face))
1172 return freetype->face->units_per_EM;
1174 return freetype->face->size->metrics.y_ppem;
1177 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1179 return freetype->getSfntTable(tag, buffer, length);
1182 int QFontEngineFT::synthesized() const
1185 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1186 s = SynthesizedItalic;
1187 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1188 s |= SynthesizedBold;
1189 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1190 s |= SynthesizedStretch;
1194 QFixed QFontEngineFT::ascent() const
1196 return QFixed::fromFixed(metrics.ascender);
1199 QFixed QFontEngineFT::descent() const
1201 // subtract a pixel to work around QFontMetrics's built-in + 1
1202 return QFixed::fromFixed(-metrics.descender - 64);
1205 QFixed QFontEngineFT::leading() const
1207 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1210 QFixed QFontEngineFT::xHeight() const
1212 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1213 if (os2 && os2->sxHeight) {
1215 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1219 return QFontEngine::xHeight();
1222 QFixed QFontEngineFT::averageCharWidth() const
1224 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1225 if (os2 && os2->xAvgCharWidth) {
1227 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1231 return QFontEngine::averageCharWidth();
1234 qreal QFontEngineFT::maxCharWidth() const
1236 return metrics.max_advance >> 6;
1239 static const ushort char_table[] = {
1260 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1263 qreal QFontEngineFT::minLeftBearing() const
1265 if (lbearing == SHRT_MIN)
1266 (void) minRightBearing(); // calculates both
1267 return lbearing.toReal();
1270 qreal QFontEngineFT::minRightBearing() const
1272 if (rbearing == SHRT_MIN) {
1273 lbearing = rbearing = 0;
1274 const QChar *ch = (const QChar *)(const void*)char_table;
1275 QGlyphLayoutArray<char_table_entries> glyphs;
1276 int ng = char_table_entries;
1277 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1279 if (glyphs.glyphs[ng]) {
1280 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1281 lbearing = qMin(lbearing, gi.x);
1282 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1286 return rbearing.toReal();
1289 QFixed QFontEngineFT::lineThickness() const
1291 return line_thickness;
1294 QFixed QFontEngineFT::underlinePosition() const
1296 return underline_position;
1299 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1301 if (!kerning_pairs_loaded) {
1302 kerning_pairs_loaded = true;
1304 if (freetype->face->size->metrics.x_ppem != 0) {
1305 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1307 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1312 QFontEngine::doKerning(g, flags);
1315 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1317 if (matrix.type() > QTransform::TxShear)
1320 // FT_Set_Transform only supports scalable fonts
1321 if (!FT_IS_SCALABLE(freetype->face))
1325 m.xx = FT_Fixed(matrix.m11() * 65536);
1326 m.xy = FT_Fixed(-matrix.m21() * 65536);
1327 m.yx = FT_Fixed(-matrix.m12() * 65536);
1328 m.yy = FT_Fixed(matrix.m22() * 65536);
1332 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1333 const QGlyphSet &g = transformedGlyphSets.at(i);
1334 if (g.transformationMatrix.xx == m.xx
1335 && g.transformationMatrix.xy == m.xy
1336 && g.transformationMatrix.yx == m.yx
1337 && g.transformationMatrix.yy == m.yy) {
1339 // found a match, move it to the front
1340 transformedGlyphSets.move(i, 0);
1341 gs = &transformedGlyphSets[0];
1347 // don't try to load huge fonts
1348 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1349 if (draw_as_outline)
1352 // don't cache more than 10 transformations
1353 if (transformedGlyphSets.count() >= 10) {
1354 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1355 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1357 transformedGlyphSets.prepend(QGlyphSet());
1359 gs = &transformedGlyphSets[0];
1363 gs->id = allocateServerGlyphSet();
1365 gs->transformationMatrix = m;
1366 gs->outline_drawing = draw_as_outline;
1372 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1373 const QFixedPoint *positions,
1378 for (int i = 0; i < num_glyphs; ++i) {
1379 QFixed spp = subPixelPositionForX(positions[i].x);
1380 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1381 if (glyph == 0 || glyph->format != format) {
1384 FT_Matrix m = matrix;
1385 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1386 FT_Set_Transform(face, &m, 0);
1387 freetype->matrix = m;
1389 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1402 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1404 FT_Face face = lockFace(Unscaled);
1405 FT_Set_Transform(face, 0, 0);
1406 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1408 int left = face->glyph->metrics.horiBearingX;
1409 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1410 int top = face->glyph->metrics.horiBearingY;
1411 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1417 metrics->width = QFixed::fromFixed(right-left);
1418 metrics->height = QFixed::fromFixed(top-bottom);
1419 metrics->x = QFixed::fromFixed(left);
1420 metrics->y = QFixed::fromFixed(-top);
1421 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1423 if (!FT_IS_SCALABLE(freetype->face))
1424 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1426 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1428 FT_Set_Transform(face, &freetype->matrix, 0);
1432 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1434 uint ucs4 = str[i].unicode();
1435 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1437 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1442 bool QFontEngineFT::canRender(const QChar *string, int len)
1444 FT_Face face = freetype->face;
1448 for ( int i = 0; i < len; i++ ) {
1449 unsigned int uc = getChar(string, i, len);
1450 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1459 for ( int i = 0; i < len; i++ ) {
1460 unsigned int uc = getChar(string, i, len);
1461 if (!FT_Get_Char_Index(face, uc))
1468 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1470 if (!glyphs.numGlyphs)
1473 if (FT_IS_SCALABLE(freetype->face)) {
1474 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1476 QVarLengthArray<QFixedPoint> positions;
1477 QVarLengthArray<glyph_t> positioned_glyphs;
1479 matrix.translate(x, y);
1480 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1482 FT_Face face = lockFace(Unscaled);
1483 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1484 FT_UInt glyph = positioned_glyphs[gl];
1485 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1486 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1492 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1493 QPainterPath *path, QTextItem::RenderFlags)
1495 FT_Face face = lockFace(Unscaled);
1497 for (int gl = 0; gl < numGlyphs; gl++) {
1498 FT_UInt glyph = glyphs[gl];
1500 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1502 FT_GlyphSlot g = face->glyph;
1503 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1505 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1506 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1507 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1512 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1513 QTextEngine::ShaperFlags flags) const
1515 if (*nglyphs < len) {
1520 #if !defined(QT_NO_FONTCONFIG)
1521 extern QMutex *qt_fontdatabase_mutex();
1525 bool mirrored = flags & QTextEngine::RightToLeft;
1527 if (freetype->symbol_map) {
1528 FT_Face face = freetype->face;
1529 for ( int i = 0; i < len; ++i ) {
1530 unsigned int uc = getChar(str, i, len);
1531 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1532 if ( !glyphs->glyphs[glyph_pos] ) {
1534 #if !defined(QT_NO_FONTCONFIG)
1536 mtx = qt_fontdatabase_mutex();
1540 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1545 glyph = FT_Get_Char_Index(face, uc);
1546 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1551 FT_Set_Charmap(face, freetype->symbol_map);
1552 glyph = FT_Get_Char_Index(face, uc);
1553 FT_Set_Charmap(face, freetype->unicode_map);
1555 glyphs->glyphs[glyph_pos] = glyph;
1556 if (uc < QFreetypeFace::cmapCacheSize)
1557 freetype->cmapCache[uc] = glyph;
1562 FT_Face face = freetype->face;
1563 for (int i = 0; i < len; ++i) {
1564 unsigned int uc = getChar(str, i, len);
1566 uc = QChar::mirroredChar(uc);
1567 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1568 if (!glyphs->glyphs[glyph_pos]) {
1569 #if !defined(QT_NO_FONTCONFIG)
1571 mtx = qt_fontdatabase_mutex();
1575 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1579 glyph_t glyph = FT_Get_Char_Index(face, uc);
1580 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1584 glyphs->glyphs[glyph_pos] = glyph;
1585 if (uc < QFreetypeFace::cmapCacheSize)
1586 freetype->cmapCache[uc] = glyph;
1593 *nglyphs = glyph_pos;
1594 glyphs->numGlyphs = glyph_pos;
1596 #if !defined(QT_NO_FONTCONFIG)
1601 if (flags & QTextEngine::GlyphIndicesOnly)
1604 recalcAdvances(glyphs, flags);
1609 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1612 bool design = (default_hint_style == HintNone ||
1613 default_hint_style == HintLight ||
1614 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1615 for (int i = 0; i < glyphs->numGlyphs; i++) {
1616 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1618 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1622 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1623 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1624 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1626 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1627 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1628 glyphs->advances_y[i] = 0;
1634 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1639 glyph_metrics_t overall;
1640 // initialize with line height, we get the same behaviour on all platforms
1641 overall.y = -ascent();
1642 overall.height = ascent() + descent() + 1;
1646 for (int i = 0; i < glyphs.numGlyphs; i++) {
1647 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1651 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1654 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1655 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1656 overall.x = qMin(overall.x, x);
1657 overall.y = qMin(overall.y, y);
1658 xmax = qMax(xmax, x + g->width);
1659 ymax = qMax(ymax, y + g->height);
1660 overall.xoff += g->advance;
1662 int left = FLOOR(face->glyph->metrics.horiBearingX);
1663 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1664 int top = CEIL(face->glyph->metrics.horiBearingY);
1665 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1667 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1668 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1669 overall.x = qMin(overall.x, x);
1670 overall.y = qMin(overall.y, y);
1671 xmax = qMax(xmax, x + TRUNC(right - left));
1672 ymax = qMax(ymax, y + TRUNC(top - bottom));
1673 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1676 overall.height = qMax(overall.height, ymax - overall.y);
1677 overall.width = xmax - overall.x;
1685 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1688 glyph_metrics_t overall;
1689 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1692 g = loadGlyph(glyph, 0, Format_None, true);
1697 overall.width = g->width;
1698 overall.height = g->height;
1699 overall.xoff = g->advance;
1700 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1701 overall.xoff = overall.xoff.round();
1703 int left = FLOOR(face->glyph->metrics.horiBearingX);
1704 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1705 int top = CEIL(face->glyph->metrics.horiBearingY);
1706 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1708 overall.width = TRUNC(right-left);
1709 overall.height = TRUNC(top-bottom);
1710 overall.x = TRUNC(left);
1711 overall.y = -TRUNC(top);
1712 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1719 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1721 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1724 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1727 glyph_metrics_t overall;
1728 QGlyphSet *glyphSet = 0;
1729 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1730 // TODO move everything here to a method of its own to access glyphSets
1731 // to be shared with a new method that will replace loadTransformedGlyphSet()
1733 m.xx = FT_Fixed(matrix.m11() * 65536);
1734 m.xy = FT_Fixed(-matrix.m21() * 65536);
1735 m.yx = FT_Fixed(-matrix.m12() * 65536);
1736 m.yy = FT_Fixed(matrix.m22() * 65536);
1737 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1738 const QGlyphSet &g = transformedGlyphSets.at(i);
1739 if (g.transformationMatrix.xx == m.xx
1740 && g.transformationMatrix.xy == m.xy
1741 && g.transformationMatrix.yx == m.yx
1742 && g.transformationMatrix.yy == m.yy) {
1744 // found a match, move it to the front
1745 transformedGlyphSets.move(i, 0);
1746 glyphSet = &transformedGlyphSets[0];
1752 // don't cache more than 10 transformations
1753 if (transformedGlyphSets.count() >= 10) {
1754 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1755 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1757 transformedGlyphSets.prepend(QGlyphSet());
1759 glyphSet = &transformedGlyphSets[0];
1761 glyphSet->id = allocateServerGlyphSet();
1762 glyphSet->transformationMatrix = m;
1766 glyphSet = &defaultGlyphSet;
1768 Glyph * g = glyphSet->getGlyph(glyph);
1769 if (!g || g->format != format) {
1771 FT_Matrix m = this->matrix;
1772 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1773 freetype->matrix = m;
1774 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1780 overall.width = g->width;
1781 overall.height = g->height;
1782 overall.xoff = g->advance;
1784 int left = FLOOR(face->glyph->metrics.horiBearingX);
1785 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1786 int top = CEIL(face->glyph->metrics.horiBearingY);
1787 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1789 overall.width = TRUNC(right-left);
1790 overall.height = TRUNC(top-bottom);
1791 overall.x = TRUNC(left);
1792 overall.y = -TRUNC(top);
1793 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1800 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1801 QFontEngine::GlyphFormat neededFormat,
1802 const QTransform &t, QPoint *offset)
1804 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1808 neededFormat = Format_Mono;
1809 else if (neededFormat == Format_None)
1810 neededFormat = defaultFormat;
1812 QFontEngineFT::QGlyphSet *gset = defaultGlyphs();
1813 if (t.type() >= QTransform::TxScale) {
1815 gset = loadTransformedGlyphSet(t);
1820 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1823 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1827 QImage::Format format;
1828 switch (neededFormat) {
1829 case QFontEngine::Format_Mono:
1830 format = QImage::Format_Mono;
1832 case QFontEngine::Format_A8:
1833 format = QImage::Format_Indexed8;
1835 case QFontEngine::Format_A32:
1836 format = QImage::Format_ARGB32;
1840 format = QImage::Format_Invalid;
1843 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1844 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1850 switch (neededFormat) {
1851 case QFontEngineFT::Format_Mono:
1852 pitch = ((glyph->width + 31) & ~31) >> 3;
1854 case QFontEngineFT::Format_A8:
1855 pitch = (glyph->width + 3) & ~3;
1857 case QFontEngineFT::Format_A32:
1858 pitch = glyph->width * 4;
1866 *offset = QPoint(glyph->x, -glyph->y);
1869 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1870 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1872 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1873 data->is_locked = true;
1875 return ¤tlyLockedAlphaMap;
1878 void QFontEngineFT::unlockAlphaMapForGlyph()
1880 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1882 currentlyLockedAlphaMap = QImage();
1885 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1889 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1891 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1894 return QFontEngine::alphaMapForGlyph(g);
1897 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1899 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1901 QVector<QRgb> colors(256);
1902 for (int i=0; i<256; ++i)
1903 colors[i] = qRgba(0, 0, 0, i);
1904 img.setColorTable(colors);
1906 QVector<QRgb> colors(2);
1907 colors[0] = qRgba(0, 0, 0, 0);
1908 colors[1] = qRgba(0, 0, 0, 255);
1909 img.setColorTable(colors);
1911 Q_ASSERT(img.bytesPerLine() == pitch);
1913 for (int y = 0; y < glyph->height; ++y)
1914 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1921 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1923 if (t.type() > QTransform::TxTranslate)
1924 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1928 GlyphFormat glyph_format = Format_A32;
1930 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1933 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1936 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1937 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1943 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1945 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1948 int QFontEngineFT::glyphCount() const
1951 FT_Face face = lockFace();
1953 count = face->num_glyphs;
1959 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1962 FT_Face face = freetype->face;
1963 if (scale == Unscaled) {
1964 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1965 freetype->xsize = face->units_per_EM << 6;
1966 freetype->ysize = face->units_per_EM << 6;
1967 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1968 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1969 freetype->xsize = xsize;
1970 freetype->ysize = ysize;
1972 if (freetype->matrix.xx != matrix.xx ||
1973 freetype->matrix.yy != matrix.yy ||
1974 freetype->matrix.xy != matrix.xy ||
1975 freetype->matrix.yx != matrix.yx) {
1976 freetype->matrix = matrix;
1977 FT_Set_Transform(face, &freetype->matrix, 0);
1983 void QFontEngineFT::unlockFace() const
1988 FT_Face QFontEngineFT::non_locked_face() const
1990 return freetype->face;
1994 QFontEngineFT::QGlyphSet::QGlyphSet()
1995 : id(0), outline_drawing(false)
1997 transformationMatrix.xx = 0x10000;
1998 transformationMatrix.yy = 0x10000;
1999 transformationMatrix.xy = 0;
2000 transformationMatrix.yx = 0;
2001 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2002 fast_glyph_count = 0;
2005 QFontEngineFT::QGlyphSet::~QGlyphSet()
2010 void QFontEngineFT::QGlyphSet::clear()
2012 if (fast_glyph_count > 0) {
2013 for (int i = 0; i < 256; ++i) {
2014 if (fast_glyph_data[i]) {
2015 delete fast_glyph_data[i];
2016 fast_glyph_data[i] = 0;
2019 fast_glyph_count = 0;
2021 qDeleteAll(glyph_data);
2025 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2027 if (useFastGlyphData(index, subPixelPosition)) {
2028 if (fast_glyph_data[index]) {
2029 delete fast_glyph_data[index];
2030 fast_glyph_data[index] = 0;
2031 if (fast_glyph_count > 0)
2035 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2039 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2041 if (useFastGlyphData(index, subPixelPosition)) {
2042 if (!fast_glyph_data[index])
2044 fast_glyph_data[index] = glyph;
2046 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2050 unsigned long QFontEngineFT::allocateServerGlyphSet()
2055 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
2060 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2063 bool hsubpixel = true;
2065 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2066 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2071 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2073 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2076 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2078 freetype->ref.ref();
2080 default_load_flags = fe->default_load_flags;
2081 default_hint_style = fe->default_hint_style;
2082 antialias = fe->antialias;
2083 transform = fe->transform;
2084 embolden = fe->embolden;
2085 obliquen = fe->obliquen;
2086 subpixelType = fe->subpixelType;
2087 lcdFilterType = fe->lcdFilterType;
2088 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2089 embeddedbitmap = fe->embeddedbitmap;
2094 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2097 fontDef.pixelSize = pixelSize;
2098 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2099 if (!fe->initFromFontEngine(this)) {
2109 #endif // QT_NO_FREETYPE