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"
48 #ifndef QT_NO_FREETYPE
51 #include "qabstractfileengine.h"
52 #include "qthreadstorage.h"
54 #include <private/qharfbuzz_p.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 #define FLOOR(x) ((x) & -64)
104 #define CEIL(x) (((x)+63) & -64)
105 #define TRUNC(x) ((x) >> 6)
106 #define ROUND(x) (((x)+32) & -64)
108 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
110 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
111 FT_Face face = (FT_Face)font;
112 FT_ULong ftlen = *length;
115 if ( !FT_IS_SFNT(face) )
116 return HB_Err_Invalid_Argument;
118 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
120 return (HB_Error)error;
122 return HB_Err_Invalid_Argument;
126 // -------------------------- Freetype support ------------------------------
136 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
140 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
142 QtFreetypeData *qt_getFreetypeData()
144 return theFreetypeData();
147 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
149 QtFreetypeData *qt_getFreetypeData()
151 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
153 freetypeData = new QtFreetypeData;
158 FT_Library qt_getFreetype()
160 QtFreetypeData *freetypeData = qt_getFreetypeData();
161 if (!freetypeData->library)
162 FT_Init_FreeType(&freetypeData->library);
163 return freetypeData->library;
166 int QFreetypeFace::fsType() const
169 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
171 fsType = os2->fsType;
175 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
177 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
180 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
181 return HB_Err_Invalid_SubTable;
183 *nPoints = face->glyph->outline.n_points;
187 if (point > *nPoints)
188 return HB_Err_Invalid_SubTable;
190 *xpos = face->glyph->outline.points[point].x;
191 *ypos = face->glyph->outline.points[point].y;
197 * One font file can contain more than one font (bold/italic for example)
198 * find the right one and return it.
200 * Returns the freetype face or 0 in case of an empty file or any other problems
201 * (like not being able to open the file)
203 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
204 const QByteArray &fontData)
206 if (face_id.filename.isEmpty() && fontData.isEmpty())
209 QtFreetypeData *freetypeData = qt_getFreetypeData();
210 if (!freetypeData->library)
211 FT_Init_FreeType(&freetypeData->library);
213 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
217 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
219 if (!face_id.filename.isEmpty()) {
220 QFile file(QString::fromUtf8(face_id.filename));
221 if (face_id.filename.startsWith(":qmemoryfonts/")) {
222 // from qfontdatabase.cpp
223 extern QByteArray qt_fontdata_from_index(int);
224 QByteArray idx = face_id.filename;
225 idx.remove(0, 14); // remove ':qmemoryfonts/'
227 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
229 newFreetype->fontData = QByteArray();
230 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
231 if (!file.open(QIODevice::ReadOnly)) {
234 newFreetype->fontData = file.readAll();
237 newFreetype->fontData = fontData;
239 if (!newFreetype->fontData.isEmpty()) {
240 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
243 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
246 newFreetype->face = face;
248 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
249 Q_CHECK_PTR(newFreetype->hbFace);
250 newFreetype->ref = 1;
251 newFreetype->xsize = 0;
252 newFreetype->ysize = 0;
253 newFreetype->matrix.xx = 0x10000;
254 newFreetype->matrix.yy = 0x10000;
255 newFreetype->matrix.xy = 0;
256 newFreetype->matrix.yx = 0;
257 newFreetype->unicode_map = 0;
258 newFreetype->symbol_map = 0;
259 #ifndef QT_NO_FONTCONFIG
260 newFreetype->charset = 0;
263 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
265 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
266 FT_CharMap cm = newFreetype->face->charmaps[i];
267 switch(cm->encoding) {
268 case FT_ENCODING_UNICODE:
269 newFreetype->unicode_map = cm;
271 case FT_ENCODING_APPLE_ROMAN:
272 case FT_ENCODING_ADOBE_LATIN_1:
273 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
274 newFreetype->unicode_map = cm;
276 case FT_ENCODING_ADOBE_CUSTOM:
277 case FT_ENCODING_MS_SYMBOL:
278 if (!newFreetype->symbol_map)
279 newFreetype->symbol_map = cm;
286 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
287 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
290 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
291 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
292 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
293 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
294 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
296 for (int i = 0; i < 256; i += 8)
297 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
298 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
299 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
300 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
301 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
304 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
306 freetypeData->faces.insert(face_id, newFreetype.data());
308 newFreetype.take()->release(face_id);
309 // we could return null in principle instead of throwing
312 freetype = newFreetype.take();
317 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
319 QtFreetypeData *freetypeData = qt_getFreetypeData();
323 #ifndef QT_NO_FONTCONFIG
325 FcCharSetDestroy(charset);
327 if(freetypeData->faces.contains(face_id))
328 freetypeData->faces.take(face_id);
331 if (freetypeData->faces.isEmpty()) {
332 FT_Done_FreeType(freetypeData->library);
333 freetypeData->library = 0;
338 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
340 *ysize = qRound(fontDef.pixelSize * 64);
341 *xsize = *ysize * fontDef.stretch / 100;
342 *outline_drawing = false;
345 * Bitmap only faces must match exactly, so find the closest
346 * one (height dominant search)
348 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
350 for (int i = 1; i < face->num_fixed_sizes; i++) {
351 if (qAbs(*ysize - Y_SIZE(face,i)) <
352 qAbs (*ysize - Y_SIZE(face, best)) ||
353 (qAbs (*ysize - Y_SIZE(face, i)) ==
354 qAbs (*ysize - Y_SIZE(face, best)) &&
355 qAbs (*xsize - X_SIZE(face, i)) <
356 qAbs (*xsize - X_SIZE(face, best)))) {
360 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
361 *xsize = X_SIZE(face, best);
362 *ysize = Y_SIZE(face, best);
365 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
366 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
367 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
368 if (err && face->num_fixed_sizes == 1)
369 err = 0; //even more of a workaround...
376 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
380 QFontEngine::Properties QFreetypeFace::properties() const
382 QFontEngine::Properties p;
383 p.postscriptName = FT_Get_Postscript_Name(face);
384 PS_FontInfoRec font_info;
385 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
386 p.copyright = font_info.notice;
387 if (FT_IS_SCALABLE(face)) {
388 p.ascent = face->ascender;
389 p.descent = -face->descender;
390 p.leading = face->height - face->ascender + face->descender;
391 p.emSquare = face->units_per_EM;
392 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
393 face->bbox.xMax - face->bbox.xMin,
394 face->bbox.yMax - face->bbox.yMin);
396 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
397 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
398 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
399 p.emSquare = face->size->metrics.y_ppem;
400 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
401 p.boundingBox = QRectF(0, -p.ascent.toReal(),
402 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
405 p.capHeight = p.ascent;
406 p.lineWidth = face->underline_thickness;
410 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
413 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
414 if (FT_IS_SFNT(face)) {
415 FT_ULong len = *length;
416 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
423 /* Some fonts (such as MingLiu rely on hinting to scale different
424 components to their correct sizes. While this is really broken (it
425 should be done in the component glyph itself, not the hinter) we
426 will have to live with it.
428 This means we can not use FT_LOAD_NO_HINTING to get the glyph
429 outline. All we can do is to load the unscaled glyph and scale it
430 down manually when required.
432 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
434 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
435 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
436 FT_Vector *p = g->outline.points;
437 const FT_Vector *e = p + g->outline.n_points;
439 p->x = FT_MulFix(p->x, x_scale);
440 p->y = FT_MulFix(p->y, y_scale);
445 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
447 const qreal factor = 1/64.;
448 scaleOutline(face, g, x_scale, y_scale);
450 QPointF cp = point.toPointF();
452 // convert the outline to a painter path
454 for (int j = 0; j < g->outline.n_contours; ++j) {
455 int last_point = g->outline.contours[j];
456 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
457 if(!(g->outline.tags[i] & 1)) {
458 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
461 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
462 // qDebug("first point at %f %f", start.x(), start.y());
468 while (i < last_point) {
470 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
471 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
473 switch (g->outline.tags[i] & 3) {
475 // cubic bezier element
478 c[3] = (c[3] + c[2])/2;
482 // quadratic bezier element
485 c[3] = (c[1] + c[2])/2;
486 c[2] = (2*c[1] + c[3])/3;
487 c[1] = (2*c[1] + c[0])/3;
493 // qDebug() << "lineTo" << c[1];
500 c[2] = (2*c[1] + c[3])/3;
501 c[1] = (2*c[1] + c[0])/3;
505 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
506 path->cubicTo(c[1], c[2], c[3]);
511 // qDebug() << "closeSubpath";
512 path->closeSubpath();
516 c[2] = (2*c[1] + c[3])/3;
517 c[1] = (2*c[1] + c[0])/3;
519 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
520 path->cubicTo(c[1], c[2], c[3]);
526 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
528 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
530 if (slot->format != FT_GLYPH_FORMAT_BITMAP
531 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
534 QPointF cp = point.toPointF();
535 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
536 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
539 QFontEngineFT::Glyph::~Glyph()
544 static const uint subpixel_filter[3][3] = {
550 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
554 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
555 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
556 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
557 res = (mid << 24) + (high << 16) + (mid << 8) + low;
560 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
565 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
568 const int offs = bgr ? -1 : 1;
569 const int w = width * 3;
572 for (int x = 0; x < w; x += 3) {
573 uint red = src[x+1-offs];
574 uint green = src[x+1];
575 uint blue = src[x+1+offs];
576 *dd = filterPixel(red, green, blue, legacyFilter);
584 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
587 const int offs = bgr ? -src_pitch : src_pitch;
589 for (int x = 0; x < width; x++) {
590 uint red = src[x+src_pitch-offs];
591 uint green = src[x+src_pitch];
592 uint blue = src[x+src_pitch+offs];
593 dst[x] = filterPixel(red, green, blue, legacyFilter);
600 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
602 // convolute the bitmap with a triangle filter to get rid of color fringes
603 // If we take account for a gamma value of 2, we end up with
604 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
605 // as this nicely sums up to 16 :)
610 for (int x = 2; x < width - 2; ++x) {
611 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
612 dst[x] = (uchar) (sum >> 4);
614 dst[width - 2] = dst[width - 1] = 0;
620 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
628 kerning_pairs_loaded = false;
633 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
634 default_hint_style = HintNone;
635 subpixelType = Subpixel_None;
637 #if defined(FT_LCD_FILTER_H)
638 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
640 defaultFormat = Format_None;
641 canUploadGlyphsToServer = false;
642 embeddedbitmap = false;
645 QFontEngineFT::~QFontEngineFT()
648 freetype->release(face_id);
649 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
652 void QFontEngineFT::freeGlyphSets()
654 freeServerGlyphSet(defaultGlyphSet.id);
655 for (int i = 0; i < transformedGlyphSets.count(); ++i)
656 freeServerGlyphSet(transformedGlyphSets.at(i).id);
659 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
660 const QByteArray &fontData)
662 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
665 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
666 QFreetypeFace *freetypeFace)
668 freetype = freetypeFace;
674 defaultFormat = format;
675 this->antialias = antialias;
678 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
679 else if (format == Format_A8)
680 glyphFormat = QFontEngineGlyphCache::Raster_A8;
681 else if (format == Format_A32)
682 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
686 symbol = freetype->symbol_map != 0;
687 PS_FontInfoRec psrec;
688 // don't assume that type1 fonts are symbol fonts by default
689 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
690 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
693 freetype->hbFace->isSymbolFont = symbol;
695 lbearing = rbearing = SHRT_MIN;
696 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
698 FT_Face face = lockFace();
700 if (FT_IS_SCALABLE(face)) {
701 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
703 matrix.xy = 0x10000*3/10;
704 FT_Set_Transform(face, &matrix, 0);
705 freetype->matrix = matrix;
709 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
712 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
713 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
715 // copied from QFontEngineQPF
717 int score = fontDef.weight * fontDef.pixelSize;
718 line_thickness = score / 700;
719 // looks better with thicker line for small pointsizes
720 if (line_thickness < 2 && score >= 1050)
722 underline_position = ((line_thickness * 2) + 3) / 6;
724 if (line_thickness < 1)
727 hbFont.x_ppem = face->size->metrics.x_ppem;
728 hbFont.y_ppem = face->size->metrics.y_ppem;
729 hbFont.x_scale = face->size->metrics.x_scale;
730 hbFont.y_scale = face->size->metrics.y_scale;
732 hbFace = freetype->hbFace;
734 metrics = face->size->metrics;
736 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
738 TrueType fonts with embedded bitmaps may have a bitmap font specific
739 ascent/descent in the EBLC table. There is no direct public API
740 to extract those values. The only way we've found is to trick freetype
741 into thinking that it's not a scalable font in FT_SelectSize so that
742 the metrics are retrieved from the bitmap strikes.
744 if (FT_IS_SCALABLE(face)) {
745 for (int i = 0; i < face->num_fixed_sizes; ++i) {
746 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
747 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
749 FT_Select_Size(face, i);
750 metrics.ascender = face->size->metrics.ascender;
751 metrics.descender = face->size->metrics.descender;
752 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
754 face->face_flags |= FT_FACE_FLAG_SCALABLE;
761 fontDef.styleName = QString::fromUtf8(face->style_name);
765 fsType = freetype->fsType();
766 defaultGlyphSet.id = allocateServerGlyphSet();
770 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
772 default_hint_style = style;
775 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
776 bool &hsubpixel, int &vfactor) const
778 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
779 int load_target = default_hint_style == HintLight
780 ? FT_LOAD_TARGET_LIGHT
781 : FT_LOAD_TARGET_NORMAL;
783 if (format == Format_Mono) {
784 load_target = FT_LOAD_TARGET_MONO;
785 } else if (format == Format_A32) {
786 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
787 if (default_hint_style == HintFull)
788 load_target = FT_LOAD_TARGET_LCD;
790 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
791 if (default_hint_style == HintFull)
792 load_target = FT_LOAD_TARGET_LCD_V;
797 if (set && set->outline_drawing)
798 load_flags = FT_LOAD_NO_BITMAP;
800 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || set->outline_drawing)
801 load_flags |= FT_LOAD_NO_HINTING;
803 load_flags |= load_target;
808 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
809 QFixed subPixelPosition,
811 bool fetchMetricsOnly) const
813 // Q_ASSERT(freetype->lock == 1);
815 bool uploadToServer = false;
816 if (format == Format_None) {
817 if (defaultFormat != Format_None) {
818 format = defaultFormat;
819 if (canUploadGlyphsToServer)
820 uploadToServer = true;
822 format = Format_Mono;
826 Glyph *g = set->getGlyph(glyph, subPixelPosition);
827 if (g && g->format == format) {
828 if (uploadToServer && !g->uploadedToServer) {
829 set->setGlyph(glyph, subPixelPosition, 0);
837 QFontEngineFT::GlyphInfo info;
839 Q_ASSERT(format != Format_None);
840 bool hsubpixel = false;
842 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
845 if (format != Format_Mono && !embeddedbitmap)
846 load_flags |= FT_LOAD_NO_BITMAP;
849 FT_Matrix matrix = freetype->matrix;
850 bool transform = matrix.xx != 0x10000
851 || matrix.yy != 0x10000
856 load_flags |= FT_LOAD_NO_BITMAP;
858 FT_Face face = freetype->face;
861 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
863 FT_Set_Transform(face, &freetype->matrix, &v);
865 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
866 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
867 load_flags &= ~FT_LOAD_NO_BITMAP;
868 err = FT_Load_Glyph(face, glyph, load_flags);
870 if (err == FT_Err_Too_Few_Arguments) {
871 // this is an error in the bytecode interpreter, just try to run without it
872 load_flags |= FT_LOAD_FORCE_AUTOHINT;
873 err = FT_Load_Glyph(face, glyph, load_flags);
875 if (err != FT_Err_Ok)
876 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
878 if (set->outline_drawing && fetchMetricsOnly)
881 FT_GlyphSlot slot = face->glyph;
882 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
883 FT_Library library = qt_getFreetype();
885 info.xOff = TRUNC(ROUND(slot->advance.x));
888 uchar *glyph_buffer = 0;
889 int glyph_buffer_size = 0;
890 #if defined(QT_USE_FREETYPE_LCDFILTER)
891 bool useFreetypeRenderGlyph = false;
892 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
893 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
894 if (err == FT_Err_Ok)
895 useFreetypeRenderGlyph = true;
898 if (useFreetypeRenderGlyph) {
899 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
901 if (err != FT_Err_Ok)
902 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
904 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
906 info.height = slot->bitmap.rows / vfactor;
907 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
908 info.x = -slot->bitmap_left;
909 info.y = slot->bitmap_top;
911 glyph_buffer_size = info.width * info.height * 4;
912 glyph_buffer = new uchar[glyph_buffer_size];
915 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
916 else if (vfactor != 1)
917 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
921 int left = slot->metrics.horiBearingX;
922 int right = slot->metrics.horiBearingX + slot->metrics.width;
923 int top = slot->metrics.horiBearingY;
924 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
925 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
930 FT_Vector_Transform(&vector, &matrix);
935 FT_Vector_Transform(&vector, &matrix);
936 if (l > vector.x) l = vector.x;
937 if (r < vector.x) r = vector.x;
938 if (t < vector.y) t = vector.y;
939 if (b > vector.y) b = vector.y;
942 FT_Vector_Transform(&vector, &matrix);
943 if (l > vector.x) l = vector.x;
944 if (r < vector.x) r = vector.x;
945 if (t < vector.y) t = vector.y;
946 if (b > vector.y) b = vector.y;
949 FT_Vector_Transform(&vector, &matrix);
950 if (l > vector.x) l = vector.x;
951 if (r < vector.x) r = vector.x;
952 if (t < vector.y) t = vector.y;
953 if (b > vector.y) b = vector.y;
961 bottom = FLOOR(bottom);
964 int hpixels = TRUNC(right - left);
965 // subpixel position requires one more pixel
966 if (subPixelPosition > 0 && format != Format_Mono)
970 hpixels = hpixels*3 + 8;
971 info.width = hpixels;
972 info.height = TRUNC(top - bottom);
973 info.x = -TRUNC(left);
980 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
981 || ((uchar)(info.width) != info.width)
982 || ((uchar)(info.height) != info.height)
983 || ((signed char)(info.x) != info.x)
984 || ((signed char)(info.y) != info.y)
985 || ((signed char)(info.xOff) != info.xOff));
988 delete [] glyph_buffer;
992 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
993 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
994 glyph_buffer_size = pitch * info.height;
995 glyph_buffer = new uchar[glyph_buffer_size];
997 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
999 bitmap.rows = info.height*vfactor;
1000 bitmap.width = hpixels;
1001 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1002 if (!hsubpixel && vfactor == 1)
1003 bitmap.buffer = glyph_buffer;
1005 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1006 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1007 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1009 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1010 matrix.yy = vfactor << 16;
1011 matrix.yx = matrix.xy = 0;
1013 FT_Outline_Transform(&slot->outline, &matrix);
1014 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1015 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1017 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1018 Q_ASSERT(antialias);
1019 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1020 bool useLegacyLcdFilter = false;
1021 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1022 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1024 uchar *buffer = bitmap.buffer;
1025 if (!useLegacyLcdFilter) {
1026 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1027 buffer = convoluted;
1029 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1030 delete [] convoluted;
1031 } else if (vfactor != 1) {
1032 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1035 if (bitmap.buffer != glyph_buffer)
1036 delete [] bitmap.buffer;
1037 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1038 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1039 uchar *src = slot->bitmap.buffer;
1040 uchar *dst = glyph_buffer;
1041 int h = slot->bitmap.rows;
1042 if (format == Format_Mono) {
1043 int bytes = ((info.width + 7) & ~7) >> 3;
1045 memcpy (dst, src, bytes);
1047 src += slot->bitmap.pitch;
1052 uint *dd = (uint *)dst;
1054 for (int x = 0; x < slot->bitmap.width; x++) {
1055 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1060 src += slot->bitmap.pitch;
1062 } else if (vfactor != 1) {
1064 uint *dd = (uint *)dst;
1065 for (int x = 0; x < slot->bitmap.width; x++) {
1066 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1070 src += slot->bitmap.pitch;
1074 for (int x = 0; x < slot->bitmap.width; x++) {
1075 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1079 src += slot->bitmap.pitch;
1084 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1085 delete [] glyph_buffer;
1093 g->uploadedToServer = false;
1097 g->linearAdvance = slot->linearHoriAdvance >> 10;
1098 g->width = info.width;
1099 g->height = info.height;
1102 g->advance = info.xOff;
1105 g->data = glyph_buffer;
1107 if (uploadToServer) {
1108 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1111 set->setGlyph(glyph, subPixelPosition, g);
1116 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1122 Q_UNUSED(glyphDataSize);
1126 QFontEngine::FaceId QFontEngineFT::faceId() const
1131 QFontEngine::Properties QFontEngineFT::properties() const
1133 Properties p = freetype->properties();
1134 if (p.postscriptName.isEmpty()) {
1135 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1138 return freetype->properties();
1141 QFixed QFontEngineFT::emSquareSize() const
1143 if (FT_IS_SCALABLE(freetype->face))
1144 return freetype->face->units_per_EM;
1146 return freetype->face->size->metrics.y_ppem;
1149 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1151 return freetype->getSfntTable(tag, buffer, length);
1154 int QFontEngineFT::synthesized() const
1157 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1158 s = SynthesizedItalic;
1159 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1160 s |= SynthesizedBold;
1161 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1162 s |= SynthesizedStretch;
1166 QFixed QFontEngineFT::ascent() const
1168 return QFixed::fromFixed(metrics.ascender);
1171 QFixed QFontEngineFT::descent() const
1173 // subtract a pixel to work around QFontMetrics's built-in + 1
1174 return QFixed::fromFixed(-metrics.descender - 64);
1177 QFixed QFontEngineFT::leading() const
1179 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1182 QFixed QFontEngineFT::xHeight() const
1184 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1185 if (os2 && os2->sxHeight) {
1187 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1191 return QFontEngine::xHeight();
1194 QFixed QFontEngineFT::averageCharWidth() const
1196 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1197 if (os2 && os2->xAvgCharWidth) {
1199 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1203 return QFontEngine::averageCharWidth();
1206 qreal QFontEngineFT::maxCharWidth() const
1208 return metrics.max_advance >> 6;
1211 static const ushort char_table[] = {
1232 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1235 qreal QFontEngineFT::minLeftBearing() const
1237 if (lbearing == SHRT_MIN)
1238 (void) minRightBearing(); // calculates both
1239 return lbearing.toReal();
1242 qreal QFontEngineFT::minRightBearing() const
1244 if (rbearing == SHRT_MIN) {
1245 lbearing = rbearing = 0;
1246 const QChar *ch = (const QChar *)(const void*)char_table;
1247 QGlyphLayoutArray<char_table_entries> glyphs;
1248 int ng = char_table_entries;
1249 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1251 if (glyphs.glyphs[ng]) {
1252 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1253 lbearing = qMin(lbearing, gi.x);
1254 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1258 return rbearing.toReal();
1261 QFixed QFontEngineFT::lineThickness() const
1263 return line_thickness;
1266 QFixed QFontEngineFT::underlinePosition() const
1268 return underline_position;
1271 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1273 if (!kerning_pairs_loaded) {
1274 kerning_pairs_loaded = true;
1276 if (freetype->face->size->metrics.x_ppem != 0) {
1277 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1279 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1284 QFontEngine::doKerning(g, flags);
1287 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1289 if (matrix.type() > QTransform::TxShear)
1292 // FT_Set_Transform only supports scalable fonts
1293 if (!FT_IS_SCALABLE(freetype->face))
1297 m.xx = FT_Fixed(matrix.m11() * 65536);
1298 m.xy = FT_Fixed(-matrix.m21() * 65536);
1299 m.yx = FT_Fixed(-matrix.m12() * 65536);
1300 m.yy = FT_Fixed(matrix.m22() * 65536);
1304 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1305 const QGlyphSet &g = transformedGlyphSets.at(i);
1306 if (g.transformationMatrix.xx == m.xx
1307 && g.transformationMatrix.xy == m.xy
1308 && g.transformationMatrix.yx == m.yx
1309 && g.transformationMatrix.yy == m.yy) {
1311 // found a match, move it to the front
1312 transformedGlyphSets.move(i, 0);
1313 gs = &transformedGlyphSets[0];
1319 // don't try to load huge fonts
1320 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1321 if (draw_as_outline)
1324 // don't cache more than 10 transformations
1325 if (transformedGlyphSets.count() >= 10) {
1326 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1327 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1329 transformedGlyphSets.prepend(QGlyphSet());
1331 gs = &transformedGlyphSets[0];
1335 gs->id = allocateServerGlyphSet();
1337 gs->transformationMatrix = m;
1338 gs->outline_drawing = draw_as_outline;
1344 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1346 int m_subPixelPositionCount = 4;
1347 if (!supportsSubPixelPositions())
1350 QFixed subPixelPosition;
1352 subPixelPosition = x - x.floor();
1353 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1354 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1356 return subPixelPosition;
1359 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1360 const QFixedPoint *positions,
1365 for (int i = 0; i < num_glyphs; ++i) {
1366 QFixed spp = subPixelPositionForX(positions[i].x);
1367 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1368 if (glyph == 0 || glyph->format != format) {
1371 FT_Matrix m = matrix;
1372 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1373 FT_Set_Transform(face, &m, 0);
1374 freetype->matrix = m;
1376 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1389 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1391 FT_Face face = lockFace(Unscaled);
1392 FT_Set_Transform(face, 0, 0);
1393 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1395 int left = face->glyph->metrics.horiBearingX;
1396 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1397 int top = face->glyph->metrics.horiBearingY;
1398 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1404 metrics->width = QFixed::fromFixed(right-left);
1405 metrics->height = QFixed::fromFixed(top-bottom);
1406 metrics->x = QFixed::fromFixed(left);
1407 metrics->y = QFixed::fromFixed(-top);
1408 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1410 if (!FT_IS_SCALABLE(freetype->face))
1411 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1413 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1415 FT_Set_Transform(face, &freetype->matrix, 0);
1419 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1421 unsigned int uc = str[i].unicode();
1422 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
1423 uint low = str[i+1].unicode();
1424 if (low >= 0xdc00 && low < 0xe000) {
1425 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
1432 bool QFontEngineFT::canRender(const QChar *string, int len)
1434 FT_Face face = freetype->face;
1438 for ( int i = 0; i < len; i++ ) {
1439 unsigned int uc = getChar(string, i, len);
1440 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1449 for ( int i = 0; i < len; i++ ) {
1450 unsigned int uc = getChar(string, i, len);
1451 if (!FT_Get_Char_Index(face, uc))
1458 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1460 if (!glyphs.numGlyphs)
1463 if (FT_IS_SCALABLE(freetype->face)) {
1464 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1466 QVarLengthArray<QFixedPoint> positions;
1467 QVarLengthArray<glyph_t> positioned_glyphs;
1469 matrix.translate(x, y);
1470 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1472 FT_Face face = lockFace(Unscaled);
1473 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1474 FT_UInt glyph = positioned_glyphs[gl];
1475 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1476 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1482 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1483 QPainterPath *path, QTextItem::RenderFlags)
1485 FT_Face face = lockFace(Unscaled);
1487 for (int gl = 0; gl < numGlyphs; gl++) {
1488 FT_UInt glyph = glyphs[gl];
1490 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1492 FT_GlyphSlot g = face->glyph;
1493 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1495 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1500 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1501 QTextEngine::ShaperFlags flags) const
1503 if (*nglyphs < len) {
1508 #if !defined(QT_NO_FONTCONFIG)
1509 extern QMutex *qt_fontdatabase_mutex();
1513 bool mirrored = flags & QTextEngine::RightToLeft;
1515 if (freetype->symbol_map) {
1516 FT_Face face = freetype->face;
1517 for ( int i = 0; i < len; ++i ) {
1518 unsigned int uc = getChar(str, i, len);
1519 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1520 if ( !glyphs->glyphs[glyph_pos] ) {
1522 #if !defined(QT_NO_FONTCONFIG)
1524 mtx = qt_fontdatabase_mutex();
1528 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1533 glyph = FT_Get_Char_Index(face, uc);
1534 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1539 FT_Set_Charmap(face, freetype->symbol_map);
1540 glyph = FT_Get_Char_Index(face, uc);
1541 FT_Set_Charmap(face, freetype->unicode_map);
1543 glyphs->glyphs[glyph_pos] = glyph;
1544 if (uc < QFreetypeFace::cmapCacheSize)
1545 freetype->cmapCache[uc] = glyph;
1550 FT_Face face = freetype->face;
1551 for (int i = 0; i < len; ++i) {
1552 unsigned int uc = getChar(str, i, len);
1554 uc = QChar::mirroredChar(uc);
1555 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1556 if (!glyphs->glyphs[glyph_pos]) {
1557 #if !defined(QT_NO_FONTCONFIG)
1559 mtx = qt_fontdatabase_mutex();
1563 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1567 glyph_t glyph = FT_Get_Char_Index(face, uc);
1568 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1572 glyphs->glyphs[glyph_pos] = glyph;
1573 if (uc < QFreetypeFace::cmapCacheSize)
1574 freetype->cmapCache[uc] = glyph;
1581 *nglyphs = glyph_pos;
1582 glyphs->numGlyphs = glyph_pos;
1584 #if !defined(QT_NO_FONTCONFIG)
1589 if (flags & QTextEngine::GlyphIndicesOnly)
1592 recalcAdvances(glyphs, flags);
1597 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1600 bool design = (default_hint_style == HintNone ||
1601 default_hint_style == HintLight ||
1602 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1603 for (int i = 0; i < glyphs->numGlyphs; i++) {
1604 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1606 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1610 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1611 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1612 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1614 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1615 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1616 glyphs->advances_y[i] = 0;
1622 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1627 glyph_metrics_t overall;
1628 // initialize with line height, we get the same behaviour on all platforms
1629 overall.y = -ascent();
1630 overall.height = ascent() + descent() + 1;
1634 for (int i = 0; i < glyphs.numGlyphs; i++) {
1635 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1639 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1642 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1643 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1644 overall.x = qMin(overall.x, x);
1645 overall.y = qMin(overall.y, y);
1646 xmax = qMax(xmax, x + g->width);
1647 ymax = qMax(ymax, y + g->height);
1648 overall.xoff += qRound(g->advance);
1650 int left = FLOOR(face->glyph->metrics.horiBearingX);
1651 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1652 int top = CEIL(face->glyph->metrics.horiBearingY);
1653 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1655 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1656 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1657 overall.x = qMin(overall.x, x);
1658 overall.y = qMin(overall.y, y);
1659 xmax = qMax(xmax, x + TRUNC(right - left));
1660 ymax = qMax(ymax, y + TRUNC(top - bottom));
1661 overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1664 overall.height = qMax(overall.height, ymax - overall.y);
1665 overall.width = xmax - overall.x;
1673 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1676 glyph_metrics_t overall;
1677 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1680 g = loadGlyph(glyph, 0, Format_None, true);
1685 overall.width = g->width;
1686 overall.height = g->height;
1687 overall.xoff = g->advance;
1688 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1689 overall.xoff = overall.xoff.round();
1691 int left = FLOOR(face->glyph->metrics.horiBearingX);
1692 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1693 int top = CEIL(face->glyph->metrics.horiBearingY);
1694 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1696 overall.width = TRUNC(right-left);
1697 overall.height = TRUNC(top-bottom);
1698 overall.x = TRUNC(left);
1699 overall.y = -TRUNC(top);
1700 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1707 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1709 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1712 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1715 glyph_metrics_t overall;
1716 QGlyphSet *glyphSet = 0;
1717 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1718 // TODO move everything here to a method of its own to access glyphSets
1719 // to be shared with a new method that will replace loadTransformedGlyphSet()
1721 m.xx = FT_Fixed(matrix.m11() * 65536);
1722 m.xy = FT_Fixed(-matrix.m21() * 65536);
1723 m.yx = FT_Fixed(-matrix.m12() * 65536);
1724 m.yy = FT_Fixed(matrix.m22() * 65536);
1725 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1726 const QGlyphSet &g = transformedGlyphSets.at(i);
1727 if (g.transformationMatrix.xx == m.xx
1728 && g.transformationMatrix.xy == m.xy
1729 && g.transformationMatrix.yx == m.yx
1730 && g.transformationMatrix.yy == m.yy) {
1732 // found a match, move it to the front
1733 transformedGlyphSets.move(i, 0);
1734 glyphSet = &transformedGlyphSets[0];
1740 // don't cache more than 10 transformations
1741 if (transformedGlyphSets.count() >= 10) {
1742 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1743 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1745 transformedGlyphSets.prepend(QGlyphSet());
1747 glyphSet = &transformedGlyphSets[0];
1749 glyphSet->id = allocateServerGlyphSet();
1750 glyphSet->transformationMatrix = m;
1754 glyphSet = &defaultGlyphSet;
1756 Glyph * g = glyphSet->getGlyph(glyph);
1757 if (!g || g->format != format) {
1759 FT_Matrix m = this->matrix;
1760 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1761 freetype->matrix = m;
1762 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1768 overall.width = g->width;
1769 overall.height = g->height;
1770 overall.xoff = g->advance;
1772 int left = FLOOR(face->glyph->metrics.horiBearingX);
1773 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1774 int top = CEIL(face->glyph->metrics.horiBearingY);
1775 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1777 overall.width = TRUNC(right-left);
1778 overall.height = TRUNC(top-bottom);
1779 overall.x = TRUNC(left);
1780 overall.y = -TRUNC(top);
1781 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1788 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1792 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1794 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1797 return QFontEngine::alphaMapForGlyph(g);
1800 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1802 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1804 QVector<QRgb> colors(256);
1805 for (int i=0; i<256; ++i)
1806 colors[i] = qRgba(0, 0, 0, i);
1807 img.setColorTable(colors);
1809 QVector<QRgb> colors(2);
1810 colors[0] = qRgba(0, 0, 0, 0);
1811 colors[1] = qRgba(0, 0, 0, 255);
1812 img.setColorTable(colors);
1814 Q_ASSERT(img.bytesPerLine() == pitch);
1816 for (int y = 0; y < glyph->height; ++y)
1817 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1824 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1826 if (t.type() > QTransform::TxTranslate)
1827 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1831 GlyphFormat glyph_format = Format_A32;
1833 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1836 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1839 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1840 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1846 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1848 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1851 int QFontEngineFT::glyphCount() const
1854 FT_Face face = lockFace();
1856 count = face->num_glyphs;
1862 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1865 FT_Face face = freetype->face;
1866 if (scale == Unscaled) {
1867 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1868 freetype->xsize = face->units_per_EM << 6;
1869 freetype->ysize = face->units_per_EM << 6;
1870 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1871 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1872 freetype->xsize = xsize;
1873 freetype->ysize = ysize;
1875 if (freetype->matrix.xx != matrix.xx ||
1876 freetype->matrix.yy != matrix.yy ||
1877 freetype->matrix.xy != matrix.xy ||
1878 freetype->matrix.yx != matrix.yx) {
1879 freetype->matrix = matrix;
1880 FT_Set_Transform(face, &freetype->matrix, 0);
1886 void QFontEngineFT::unlockFace() const
1891 FT_Face QFontEngineFT::non_locked_face() const
1893 return freetype->face;
1897 QFontEngineFT::QGlyphSet::QGlyphSet()
1898 : id(0), outline_drawing(false)
1900 transformationMatrix.xx = 0x10000;
1901 transformationMatrix.yy = 0x10000;
1902 transformationMatrix.xy = 0;
1903 transformationMatrix.yx = 0;
1904 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1905 fast_glyph_count = 0;
1908 QFontEngineFT::QGlyphSet::~QGlyphSet()
1913 void QFontEngineFT::QGlyphSet::clear()
1915 if (fast_glyph_count > 0) {
1916 for (int i = 0; i < 256; ++i) {
1917 if (fast_glyph_data[i]) {
1918 delete fast_glyph_data[i];
1919 fast_glyph_data[i] = 0;
1922 fast_glyph_count = 0;
1924 qDeleteAll(glyph_data);
1928 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1930 if (useFastGlyphData(index, subPixelPosition)) {
1931 if (fast_glyph_data[index]) {
1932 delete fast_glyph_data[index];
1933 fast_glyph_data[index] = 0;
1934 if (fast_glyph_count > 0)
1938 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1942 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1944 if (useFastGlyphData(index, subPixelPosition)) {
1945 if (!fast_glyph_data[index])
1947 fast_glyph_data[index] = glyph;
1949 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1953 unsigned long QFontEngineFT::allocateServerGlyphSet()
1958 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1963 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1966 bool hsubpixel = true;
1968 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1969 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1974 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
1976 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1979 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1981 freetype->ref.ref();
1983 default_load_flags = fe->default_load_flags;
1984 default_hint_style = fe->default_hint_style;
1985 antialias = fe->antialias;
1986 transform = fe->transform;
1987 embolden = fe->embolden;
1988 subpixelType = fe->subpixelType;
1989 lcdFilterType = fe->lcdFilterType;
1990 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
1991 embeddedbitmap = fe->embeddedbitmap;
1996 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
1999 fontDef.pixelSize = pixelSize;
2000 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2001 if (!fe->initFromFontEngine(this)) {
2011 #endif // QT_NO_FREETYPE