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"
55 #include "qfontengine_ft_p.h"
57 #include FT_FREETYPE_H
59 #include FT_SYNTHESIS_H
60 #include FT_TRUETYPE_TABLES_H
61 #include FT_TYPE1_TABLES_H
64 #if defined(FT_LCD_FILTER_H)
65 #include FT_LCD_FILTER_H
68 #if defined(FT_CONFIG_OPTIONS_H)
69 #include FT_CONFIG_OPTIONS_H
72 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
73 #define QT_USE_FREETYPE_LCDFILTER
83 * Freetype 2.1.7 and earlier used width/height
84 * for matching sizes in the BDF and PCF loaders.
85 * This has been fixed for 2.1.8.
87 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
88 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
89 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
91 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
92 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
95 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
96 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
97 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
99 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
102 #define FLOOR(x) ((x) & -64)
103 #define CEIL(x) (((x)+63) & -64)
104 #define TRUNC(x) ((x) >> 6)
105 #define ROUND(x) (((x)+32) & -64)
107 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
109 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
110 FT_Face face = (FT_Face)font;
111 FT_ULong ftlen = *length;
114 if ( !FT_IS_SFNT(face) )
115 return HB_Err_Invalid_Argument;
117 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
119 return (HB_Error)error;
121 return HB_Err_Invalid_Argument;
125 // -------------------------- Freetype support ------------------------------
135 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
139 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
141 QtFreetypeData *qt_getFreetypeData()
143 return theFreetypeData();
146 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
148 QtFreetypeData *qt_getFreetypeData()
150 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
152 freetypeData = new QtFreetypeData;
157 FT_Library qt_getFreetype()
159 QtFreetypeData *freetypeData = qt_getFreetypeData();
160 if (!freetypeData->library)
161 FT_Init_FreeType(&freetypeData->library);
162 return freetypeData->library;
165 int QFreetypeFace::fsType() const
168 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
170 fsType = os2->fsType;
174 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
176 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
179 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
180 return HB_Err_Invalid_SubTable;
182 *nPoints = face->glyph->outline.n_points;
186 if (point > *nPoints)
187 return HB_Err_Invalid_SubTable;
189 *xpos = face->glyph->outline.points[point].x;
190 *ypos = face->glyph->outline.points[point].y;
196 * One font file can contain more than one font (bold/italic for example)
197 * find the right one and return it.
199 * Returns the freetype face or 0 in case of an empty file or any other problems
200 * (like not being able to open the file)
202 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
203 const QByteArray &fontData)
205 if (face_id.filename.isEmpty() && fontData.isEmpty())
208 QtFreetypeData *freetypeData = qt_getFreetypeData();
209 if (!freetypeData->library)
210 FT_Init_FreeType(&freetypeData->library);
212 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
216 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
218 if (!face_id.filename.isEmpty()) {
219 QFile file(QString::fromUtf8(face_id.filename));
220 if (face_id.filename.startsWith(":qmemoryfonts/")) {
221 // from qfontdatabase.cpp
222 extern QByteArray qt_fontdata_from_index(int);
223 QByteArray idx = face_id.filename;
224 idx.remove(0, 14); // remove ':qmemoryfonts/'
226 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
228 newFreetype->fontData = QByteArray();
229 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
230 if (!file.open(QIODevice::ReadOnly)) {
233 newFreetype->fontData = file.readAll();
236 newFreetype->fontData = fontData;
238 if (!newFreetype->fontData.isEmpty()) {
239 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
242 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
245 newFreetype->face = face;
247 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
248 Q_CHECK_PTR(newFreetype->hbFace);
249 newFreetype->ref = 1;
250 newFreetype->xsize = 0;
251 newFreetype->ysize = 0;
252 newFreetype->matrix.xx = 0x10000;
253 newFreetype->matrix.yy = 0x10000;
254 newFreetype->matrix.xy = 0;
255 newFreetype->matrix.yx = 0;
256 newFreetype->unicode_map = 0;
257 newFreetype->symbol_map = 0;
258 #ifndef QT_NO_FONTCONFIG
259 newFreetype->charset = 0;
262 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
264 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
265 FT_CharMap cm = newFreetype->face->charmaps[i];
266 switch(cm->encoding) {
267 case FT_ENCODING_UNICODE:
268 newFreetype->unicode_map = cm;
270 case FT_ENCODING_APPLE_ROMAN:
271 case FT_ENCODING_ADOBE_LATIN_1:
272 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
273 newFreetype->unicode_map = cm;
275 case FT_ENCODING_ADOBE_CUSTOM:
276 case FT_ENCODING_MS_SYMBOL:
277 if (!newFreetype->symbol_map)
278 newFreetype->symbol_map = cm;
285 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
286 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
289 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
290 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
291 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
292 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
293 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
295 for (int i = 0; i < 256; i += 8)
296 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
297 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, 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));
303 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
305 freetypeData->faces.insert(face_id, newFreetype.data());
307 newFreetype.take()->release(face_id);
308 // we could return null in principle instead of throwing
311 freetype = newFreetype.take();
316 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
318 QtFreetypeData *freetypeData = qt_getFreetypeData();
322 #ifndef QT_NO_FONTCONFIG
324 FcCharSetDestroy(charset);
326 if(freetypeData->faces.contains(face_id))
327 freetypeData->faces.take(face_id);
330 if (freetypeData->faces.isEmpty()) {
331 FT_Done_FreeType(freetypeData->library);
332 freetypeData->library = 0;
337 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
339 *ysize = qRound(fontDef.pixelSize * 64);
340 *xsize = *ysize * fontDef.stretch / 100;
341 *outline_drawing = false;
344 * Bitmap only faces must match exactly, so find the closest
345 * one (height dominant search)
347 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
349 for (int i = 1; i < face->num_fixed_sizes; i++) {
350 if (qAbs(*ysize - Y_SIZE(face,i)) <
351 qAbs (*ysize - Y_SIZE(face, best)) ||
352 (qAbs (*ysize - Y_SIZE(face, i)) ==
353 qAbs (*ysize - Y_SIZE(face, best)) &&
354 qAbs (*xsize - X_SIZE(face, i)) <
355 qAbs (*xsize - X_SIZE(face, best)))) {
359 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
360 *xsize = X_SIZE(face, best);
361 *ysize = Y_SIZE(face, best);
364 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
365 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
366 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
367 if (err && face->num_fixed_sizes == 1)
368 err = 0; //even more of a workaround...
375 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
379 QFontEngine::Properties QFreetypeFace::properties() const
381 QFontEngine::Properties p;
382 p.postscriptName = FT_Get_Postscript_Name(face);
383 PS_FontInfoRec font_info;
384 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
385 p.copyright = font_info.notice;
386 if (FT_IS_SCALABLE(face)) {
387 p.ascent = face->ascender;
388 p.descent = -face->descender;
389 p.leading = face->height - face->ascender + face->descender;
390 p.emSquare = face->units_per_EM;
391 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
392 face->bbox.xMax - face->bbox.xMin,
393 face->bbox.yMax - face->bbox.yMin);
395 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
396 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
397 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
398 p.emSquare = face->size->metrics.y_ppem;
399 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
400 p.boundingBox = QRectF(0, -p.ascent.toReal(),
401 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
404 p.capHeight = p.ascent;
405 p.lineWidth = face->underline_thickness;
409 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
412 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
413 if (FT_IS_SFNT(face)) {
414 FT_ULong len = *length;
415 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
422 /* Some fonts (such as MingLiu rely on hinting to scale different
423 components to their correct sizes. While this is really broken (it
424 should be done in the component glyph itself, not the hinter) we
425 will have to live with it.
427 This means we can not use FT_LOAD_NO_HINTING to get the glyph
428 outline. All we can do is to load the unscaled glyph and scale it
429 down manually when required.
431 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
433 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
434 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
435 FT_Vector *p = g->outline.points;
436 const FT_Vector *e = p + g->outline.n_points;
438 p->x = FT_MulFix(p->x, x_scale);
439 p->y = FT_MulFix(p->y, y_scale);
444 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
446 const qreal factor = 1/64.;
447 scaleOutline(face, g, x_scale, y_scale);
449 QPointF cp = point.toPointF();
451 // convert the outline to a painter path
453 for (int j = 0; j < g->outline.n_contours; ++j) {
454 int last_point = g->outline.contours[j];
455 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
456 if(!(g->outline.tags[i] & 1)) {
457 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
460 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
461 // qDebug("first point at %f %f", start.x(), start.y());
467 while (i < last_point) {
469 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
470 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
472 switch (g->outline.tags[i] & 3) {
474 // cubic bezier element
477 c[3] = (c[3] + c[2])/2;
481 // quadratic bezier element
484 c[3] = (c[1] + c[2])/2;
485 c[2] = (2*c[1] + c[3])/3;
486 c[1] = (2*c[1] + c[0])/3;
492 // qDebug() << "lineTo" << c[1];
499 c[2] = (2*c[1] + c[3])/3;
500 c[1] = (2*c[1] + c[0])/3;
504 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
505 path->cubicTo(c[1], c[2], c[3]);
510 // qDebug() << "closeSubpath";
511 path->closeSubpath();
515 c[2] = (2*c[1] + c[3])/3;
516 c[1] = (2*c[1] + c[0])/3;
518 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
519 path->cubicTo(c[1], c[2], c[3]);
525 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
527 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
529 if (slot->format != FT_GLYPH_FORMAT_BITMAP
530 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
533 QPointF cp = point.toPointF();
534 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
535 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
538 QFontEngineFT::Glyph::~Glyph()
543 static const uint subpixel_filter[3][3] = {
549 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
553 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
554 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
555 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
556 res = (mid << 24) + (high << 16) + (mid << 8) + low;
559 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
564 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
567 const int offs = bgr ? -1 : 1;
568 const int w = width * 3;
571 for (int x = 0; x < w; x += 3) {
572 uint red = src[x+1-offs];
573 uint green = src[x+1];
574 uint blue = src[x+1+offs];
575 *dd = filterPixel(red, green, blue, legacyFilter);
583 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
586 const int offs = bgr ? -src_pitch : src_pitch;
588 for (int x = 0; x < width; x++) {
589 uint red = src[x+src_pitch-offs];
590 uint green = src[x+src_pitch];
591 uint blue = src[x+src_pitch+offs];
592 dst[x] = filterPixel(red, green, blue, legacyFilter);
599 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
601 // convolute the bitmap with a triangle filter to get rid of color fringes
602 // If we take account for a gamma value of 2, we end up with
603 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
604 // as this nicely sums up to 16 :)
609 for (int x = 2; x < width - 2; ++x) {
610 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
611 dst[x] = (uchar) (sum >> 4);
613 dst[width - 2] = dst[width - 1] = 0;
619 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
627 kerning_pairs_loaded = false;
632 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
633 default_hint_style = HintNone;
634 subpixelType = Subpixel_None;
636 #if defined(FT_LCD_FILTER_H)
637 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
639 defaultFormat = Format_None;
640 canUploadGlyphsToServer = false;
641 embeddedbitmap = false;
644 QFontEngineFT::~QFontEngineFT()
647 freetype->release(face_id);
648 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
651 void QFontEngineFT::freeGlyphSets()
653 freeServerGlyphSet(defaultGlyphSet.id);
654 for (int i = 0; i < transformedGlyphSets.count(); ++i)
655 freeServerGlyphSet(transformedGlyphSets.at(i).id);
658 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
659 const QByteArray &fontData)
661 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
664 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
665 QFreetypeFace *freetypeFace)
667 freetype = freetypeFace;
673 defaultFormat = format;
674 this->antialias = antialias;
677 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
678 else if (format == Format_A8)
679 glyphFormat = QFontEngineGlyphCache::Raster_A8;
680 else if (format == Format_A32)
681 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
685 symbol = freetype->symbol_map != 0;
686 PS_FontInfoRec psrec;
687 // don't assume that type1 fonts are symbol fonts by default
688 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
689 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
692 freetype->hbFace->isSymbolFont = symbol;
694 lbearing = rbearing = SHRT_MIN;
695 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
697 FT_Face face = lockFace();
699 if (FT_IS_SCALABLE(face)) {
700 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
702 matrix.xy = 0x10000*3/10;
703 FT_Set_Transform(face, &matrix, 0);
704 freetype->matrix = matrix;
708 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
711 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
712 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
714 // copied from QFontEngineQPF
716 int score = fontDef.weight * fontDef.pixelSize;
717 line_thickness = score / 700;
718 // looks better with thicker line for small pointsizes
719 if (line_thickness < 2 && score >= 1050)
721 underline_position = ((line_thickness * 2) + 3) / 6;
723 if (line_thickness < 1)
726 hbFont.x_ppem = face->size->metrics.x_ppem;
727 hbFont.y_ppem = face->size->metrics.y_ppem;
728 hbFont.x_scale = face->size->metrics.x_scale;
729 hbFont.y_scale = face->size->metrics.y_scale;
731 hbFace = freetype->hbFace;
733 metrics = face->size->metrics;
735 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
737 TrueType fonts with embedded bitmaps may have a bitmap font specific
738 ascent/descent in the EBLC table. There is no direct public API
739 to extract those values. The only way we've found is to trick freetype
740 into thinking that it's not a scalable font in FT_SelectSize so that
741 the metrics are retrieved from the bitmap strikes.
743 if (FT_IS_SCALABLE(face)) {
744 for (int i = 0; i < face->num_fixed_sizes; ++i) {
745 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
746 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
748 FT_Select_Size(face, i);
749 metrics.ascender = face->size->metrics.ascender;
750 metrics.descender = face->size->metrics.descender;
751 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
753 face->face_flags |= FT_FACE_FLAG_SCALABLE;
760 fontDef.styleName = QString::fromUtf8(face->style_name);
764 fsType = freetype->fsType();
765 defaultGlyphSet.id = allocateServerGlyphSet();
769 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
771 default_hint_style = style;
774 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
775 bool &hsubpixel, int &vfactor) const
777 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
778 int load_target = default_hint_style == HintLight
779 ? FT_LOAD_TARGET_LIGHT
780 : FT_LOAD_TARGET_NORMAL;
782 if (format == Format_Mono) {
783 load_target = FT_LOAD_TARGET_MONO;
784 } else if (format == Format_A32) {
785 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
786 if (default_hint_style == HintFull)
787 load_target = FT_LOAD_TARGET_LCD;
789 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
790 if (default_hint_style == HintFull)
791 load_target = FT_LOAD_TARGET_LCD_V;
796 if (set && set->outline_drawing)
797 load_flags = FT_LOAD_NO_BITMAP;
799 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || set->outline_drawing)
800 load_flags |= FT_LOAD_NO_HINTING;
802 load_flags |= load_target;
807 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
808 QFixed subPixelPosition,
810 bool fetchMetricsOnly) const
812 // Q_ASSERT(freetype->lock == 1);
814 bool uploadToServer = false;
815 if (format == Format_None) {
816 if (defaultFormat != Format_None) {
817 format = defaultFormat;
818 if (canUploadGlyphsToServer)
819 uploadToServer = true;
821 format = Format_Mono;
825 Glyph *g = set->getGlyph(glyph, subPixelPosition);
826 if (g && g->format == format) {
827 if (uploadToServer && !g->uploadedToServer) {
828 set->setGlyph(glyph, subPixelPosition, 0);
836 QFontEngineFT::GlyphInfo info;
838 Q_ASSERT(format != Format_None);
839 bool hsubpixel = false;
841 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
844 if (format != Format_Mono && !embeddedbitmap)
845 load_flags |= FT_LOAD_NO_BITMAP;
848 FT_Matrix matrix = freetype->matrix;
849 bool transform = matrix.xx != 0x10000
850 || matrix.yy != 0x10000
855 load_flags |= FT_LOAD_NO_BITMAP;
857 FT_Face face = freetype->face;
860 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
862 FT_Set_Transform(face, &freetype->matrix, &v);
864 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
865 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
866 load_flags &= ~FT_LOAD_NO_BITMAP;
867 err = FT_Load_Glyph(face, glyph, load_flags);
869 if (err == FT_Err_Too_Few_Arguments) {
870 // this is an error in the bytecode interpreter, just try to run without it
871 load_flags |= FT_LOAD_FORCE_AUTOHINT;
872 err = FT_Load_Glyph(face, glyph, load_flags);
874 if (err != FT_Err_Ok)
875 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
877 if (set->outline_drawing && fetchMetricsOnly)
880 FT_GlyphSlot slot = face->glyph;
881 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
882 FT_Library library = qt_getFreetype();
884 info.xOff = TRUNC(ROUND(slot->advance.x));
887 uchar *glyph_buffer = 0;
888 int glyph_buffer_size = 0;
889 #if defined(QT_USE_FREETYPE_LCDFILTER)
890 bool useFreetypeRenderGlyph = false;
891 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
892 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
893 if (err == FT_Err_Ok)
894 useFreetypeRenderGlyph = true;
897 if (useFreetypeRenderGlyph) {
898 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
900 if (err != FT_Err_Ok)
901 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
903 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
905 info.height = slot->bitmap.rows / vfactor;
906 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
907 info.x = -slot->bitmap_left;
908 info.y = slot->bitmap_top;
910 glyph_buffer_size = info.width * info.height * 4;
911 glyph_buffer = new uchar[glyph_buffer_size];
914 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
915 else if (vfactor != 1)
916 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
920 int left = slot->metrics.horiBearingX;
921 int right = slot->metrics.horiBearingX + slot->metrics.width;
922 int top = slot->metrics.horiBearingY;
923 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
924 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
929 FT_Vector_Transform(&vector, &matrix);
934 FT_Vector_Transform(&vector, &matrix);
935 if (l > vector.x) l = vector.x;
936 if (r < vector.x) r = vector.x;
937 if (t < vector.y) t = vector.y;
938 if (b > vector.y) b = vector.y;
941 FT_Vector_Transform(&vector, &matrix);
942 if (l > vector.x) l = vector.x;
943 if (r < vector.x) r = vector.x;
944 if (t < vector.y) t = vector.y;
945 if (b > vector.y) b = vector.y;
948 FT_Vector_Transform(&vector, &matrix);
949 if (l > vector.x) l = vector.x;
950 if (r < vector.x) r = vector.x;
951 if (t < vector.y) t = vector.y;
952 if (b > vector.y) b = vector.y;
960 bottom = FLOOR(bottom);
963 int hpixels = TRUNC(right - left);
964 // subpixel position requires one more pixel
965 if (subPixelPosition > 0 && format != Format_Mono)
969 hpixels = hpixels*3 + 8;
970 info.width = hpixels;
971 info.height = TRUNC(top - bottom);
972 info.x = -TRUNC(left);
979 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
980 || ((uchar)(info.width) != info.width)
981 || ((uchar)(info.height) != info.height)
982 || ((signed char)(info.x) != info.x)
983 || ((signed char)(info.y) != info.y)
984 || ((signed char)(info.xOff) != info.xOff));
987 delete [] glyph_buffer;
991 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
992 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
993 glyph_buffer_size = pitch * info.height;
994 glyph_buffer = new uchar[glyph_buffer_size];
996 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
998 bitmap.rows = info.height*vfactor;
999 bitmap.width = hpixels;
1000 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1001 if (!hsubpixel && vfactor == 1)
1002 bitmap.buffer = glyph_buffer;
1004 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1005 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1006 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1008 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1009 matrix.yy = vfactor << 16;
1010 matrix.yx = matrix.xy = 0;
1012 FT_Outline_Transform(&slot->outline, &matrix);
1013 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1014 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1016 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1017 Q_ASSERT(antialias);
1018 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1019 bool useLegacyLcdFilter = false;
1020 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1021 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1023 uchar *buffer = bitmap.buffer;
1024 if (!useLegacyLcdFilter) {
1025 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1026 buffer = convoluted;
1028 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1029 delete [] convoluted;
1030 } else if (vfactor != 1) {
1031 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1034 if (bitmap.buffer != glyph_buffer)
1035 delete [] bitmap.buffer;
1036 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1037 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1038 uchar *src = slot->bitmap.buffer;
1039 uchar *dst = glyph_buffer;
1040 int h = slot->bitmap.rows;
1041 if (format == Format_Mono) {
1042 int bytes = ((info.width + 7) & ~7) >> 3;
1044 memcpy (dst, src, bytes);
1046 src += slot->bitmap.pitch;
1051 uint *dd = (uint *)dst;
1053 for (int x = 0; x < slot->bitmap.width; x++) {
1054 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1059 src += slot->bitmap.pitch;
1061 } else if (vfactor != 1) {
1063 uint *dd = (uint *)dst;
1064 for (int x = 0; x < slot->bitmap.width; x++) {
1065 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1069 src += slot->bitmap.pitch;
1073 for (int x = 0; x < slot->bitmap.width; x++) {
1074 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1078 src += slot->bitmap.pitch;
1083 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1084 delete [] glyph_buffer;
1092 g->uploadedToServer = false;
1096 g->linearAdvance = slot->linearHoriAdvance >> 10;
1097 g->width = info.width;
1098 g->height = info.height;
1101 g->advance = info.xOff;
1104 g->data = glyph_buffer;
1106 if (uploadToServer) {
1107 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1110 set->setGlyph(glyph, subPixelPosition, g);
1115 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1121 Q_UNUSED(glyphDataSize);
1125 QFontEngine::FaceId QFontEngineFT::faceId() const
1130 QFontEngine::Properties QFontEngineFT::properties() const
1132 Properties p = freetype->properties();
1133 if (p.postscriptName.isEmpty()) {
1134 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1137 return freetype->properties();
1140 QFixed QFontEngineFT::emSquareSize() const
1142 if (FT_IS_SCALABLE(freetype->face))
1143 return freetype->face->units_per_EM;
1145 return freetype->face->size->metrics.y_ppem;
1148 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1150 return freetype->getSfntTable(tag, buffer, length);
1153 int QFontEngineFT::synthesized() const
1156 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1157 s = SynthesizedItalic;
1158 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1159 s |= SynthesizedBold;
1160 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1161 s |= SynthesizedStretch;
1165 QFixed QFontEngineFT::ascent() const
1167 return QFixed::fromFixed(metrics.ascender);
1170 QFixed QFontEngineFT::descent() const
1172 // subtract a pixel to work around QFontMetrics's built-in + 1
1173 return QFixed::fromFixed(-metrics.descender - 64);
1176 QFixed QFontEngineFT::leading() const
1178 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1181 QFixed QFontEngineFT::xHeight() const
1183 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1184 if (os2 && os2->sxHeight) {
1186 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1190 return QFontEngine::xHeight();
1193 QFixed QFontEngineFT::averageCharWidth() const
1195 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1196 if (os2 && os2->xAvgCharWidth) {
1198 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1202 return QFontEngine::averageCharWidth();
1205 qreal QFontEngineFT::maxCharWidth() const
1207 return metrics.max_advance >> 6;
1210 static const ushort char_table[] = {
1231 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1234 qreal QFontEngineFT::minLeftBearing() const
1236 if (lbearing == SHRT_MIN)
1237 (void) minRightBearing(); // calculates both
1238 return lbearing.toReal();
1241 qreal QFontEngineFT::minRightBearing() const
1243 if (rbearing == SHRT_MIN) {
1244 lbearing = rbearing = 0;
1245 const QChar *ch = (const QChar *)(const void*)char_table;
1246 QGlyphLayoutArray<char_table_entries> glyphs;
1247 int ng = char_table_entries;
1248 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1250 if (glyphs.glyphs[ng]) {
1251 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1252 lbearing = qMin(lbearing, gi.x);
1253 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1257 return rbearing.toReal();
1260 QFixed QFontEngineFT::lineThickness() const
1262 return line_thickness;
1265 QFixed QFontEngineFT::underlinePosition() const
1267 return underline_position;
1270 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1272 if (!kerning_pairs_loaded) {
1273 kerning_pairs_loaded = true;
1275 if (freetype->face->size->metrics.x_ppem != 0) {
1276 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1278 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1283 QFontEngine::doKerning(g, flags);
1286 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1288 if (matrix.type() > QTransform::TxShear)
1291 // FT_Set_Transform only supports scalable fonts
1292 if (!FT_IS_SCALABLE(freetype->face))
1296 m.xx = FT_Fixed(matrix.m11() * 65536);
1297 m.xy = FT_Fixed(-matrix.m21() * 65536);
1298 m.yx = FT_Fixed(-matrix.m12() * 65536);
1299 m.yy = FT_Fixed(matrix.m22() * 65536);
1303 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1304 const QGlyphSet &g = transformedGlyphSets.at(i);
1305 if (g.transformationMatrix.xx == m.xx
1306 && g.transformationMatrix.xy == m.xy
1307 && g.transformationMatrix.yx == m.yx
1308 && g.transformationMatrix.yy == m.yy) {
1310 // found a match, move it to the front
1311 transformedGlyphSets.move(i, 0);
1312 gs = &transformedGlyphSets[0];
1318 // don't try to load huge fonts
1319 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1320 if (draw_as_outline)
1323 // don't cache more than 10 transformations
1324 if (transformedGlyphSets.count() >= 10) {
1325 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1326 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1328 transformedGlyphSets.prepend(QGlyphSet());
1330 gs = &transformedGlyphSets[0];
1334 gs->id = allocateServerGlyphSet();
1336 gs->transformationMatrix = m;
1337 gs->outline_drawing = draw_as_outline;
1343 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1345 int m_subPixelPositionCount = 4;
1346 if (!supportsSubPixelPositions())
1349 QFixed subPixelPosition;
1351 subPixelPosition = x - x.floor();
1352 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1353 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1355 return subPixelPosition;
1358 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1359 const QFixedPoint *positions,
1364 for (int i = 0; i < num_glyphs; ++i) {
1365 QFixed spp = subPixelPositionForX(positions[i].x);
1366 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1367 if (glyph == 0 || glyph->format != format) {
1370 FT_Matrix m = matrix;
1371 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1372 FT_Set_Transform(face, &m, 0);
1373 freetype->matrix = m;
1375 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1388 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1390 FT_Face face = lockFace(Unscaled);
1391 FT_Set_Transform(face, 0, 0);
1392 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1394 int left = face->glyph->metrics.horiBearingX;
1395 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1396 int top = face->glyph->metrics.horiBearingY;
1397 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1403 metrics->width = QFixed::fromFixed(right-left);
1404 metrics->height = QFixed::fromFixed(top-bottom);
1405 metrics->x = QFixed::fromFixed(left);
1406 metrics->y = QFixed::fromFixed(-top);
1407 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1409 if (!FT_IS_SCALABLE(freetype->face))
1410 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1412 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1414 FT_Set_Transform(face, &freetype->matrix, 0);
1418 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1420 uint ucs4 = str[i].unicode();
1421 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1423 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1428 bool QFontEngineFT::canRender(const QChar *string, int len)
1430 FT_Face face = freetype->face;
1434 for ( int i = 0; i < len; i++ ) {
1435 unsigned int uc = getChar(string, i, len);
1436 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1445 for ( int i = 0; i < len; i++ ) {
1446 unsigned int uc = getChar(string, i, len);
1447 if (!FT_Get_Char_Index(face, uc))
1454 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1456 if (!glyphs.numGlyphs)
1459 if (FT_IS_SCALABLE(freetype->face)) {
1460 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1462 QVarLengthArray<QFixedPoint> positions;
1463 QVarLengthArray<glyph_t> positioned_glyphs;
1465 matrix.translate(x, y);
1466 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1468 FT_Face face = lockFace(Unscaled);
1469 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1470 FT_UInt glyph = positioned_glyphs[gl];
1471 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1472 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1478 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1479 QPainterPath *path, QTextItem::RenderFlags)
1481 FT_Face face = lockFace(Unscaled);
1483 for (int gl = 0; gl < numGlyphs; gl++) {
1484 FT_UInt glyph = glyphs[gl];
1486 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1488 FT_GlyphSlot g = face->glyph;
1489 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1491 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1496 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1497 QTextEngine::ShaperFlags flags) const
1499 if (*nglyphs < len) {
1504 #if !defined(QT_NO_FONTCONFIG)
1505 extern QMutex *qt_fontdatabase_mutex();
1509 bool mirrored = flags & QTextEngine::RightToLeft;
1511 if (freetype->symbol_map) {
1512 FT_Face face = freetype->face;
1513 for ( int i = 0; i < len; ++i ) {
1514 unsigned int uc = getChar(str, i, len);
1515 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1516 if ( !glyphs->glyphs[glyph_pos] ) {
1518 #if !defined(QT_NO_FONTCONFIG)
1520 mtx = qt_fontdatabase_mutex();
1524 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1529 glyph = FT_Get_Char_Index(face, uc);
1530 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1535 FT_Set_Charmap(face, freetype->symbol_map);
1536 glyph = FT_Get_Char_Index(face, uc);
1537 FT_Set_Charmap(face, freetype->unicode_map);
1539 glyphs->glyphs[glyph_pos] = glyph;
1540 if (uc < QFreetypeFace::cmapCacheSize)
1541 freetype->cmapCache[uc] = glyph;
1546 FT_Face face = freetype->face;
1547 for (int i = 0; i < len; ++i) {
1548 unsigned int uc = getChar(str, i, len);
1550 uc = QChar::mirroredChar(uc);
1551 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1552 if (!glyphs->glyphs[glyph_pos]) {
1553 #if !defined(QT_NO_FONTCONFIG)
1555 mtx = qt_fontdatabase_mutex();
1559 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1563 glyph_t glyph = FT_Get_Char_Index(face, uc);
1564 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1568 glyphs->glyphs[glyph_pos] = glyph;
1569 if (uc < QFreetypeFace::cmapCacheSize)
1570 freetype->cmapCache[uc] = glyph;
1577 *nglyphs = glyph_pos;
1578 glyphs->numGlyphs = glyph_pos;
1580 #if !defined(QT_NO_FONTCONFIG)
1585 if (flags & QTextEngine::GlyphIndicesOnly)
1588 recalcAdvances(glyphs, flags);
1593 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1596 bool design = (default_hint_style == HintNone ||
1597 default_hint_style == HintLight ||
1598 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1599 for (int i = 0; i < glyphs->numGlyphs; i++) {
1600 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1602 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1606 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1607 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1608 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1610 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1611 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1612 glyphs->advances_y[i] = 0;
1618 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1623 glyph_metrics_t overall;
1624 // initialize with line height, we get the same behaviour on all platforms
1625 overall.y = -ascent();
1626 overall.height = ascent() + descent() + 1;
1630 for (int i = 0; i < glyphs.numGlyphs; i++) {
1631 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1635 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1638 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1639 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1640 overall.x = qMin(overall.x, x);
1641 overall.y = qMin(overall.y, y);
1642 xmax = qMax(xmax, x + g->width);
1643 ymax = qMax(ymax, y + g->height);
1644 overall.xoff += g->advance;
1646 int left = FLOOR(face->glyph->metrics.horiBearingX);
1647 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1648 int top = CEIL(face->glyph->metrics.horiBearingY);
1649 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1651 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1652 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1653 overall.x = qMin(overall.x, x);
1654 overall.y = qMin(overall.y, y);
1655 xmax = qMax(xmax, x + TRUNC(right - left));
1656 ymax = qMax(ymax, y + TRUNC(top - bottom));
1657 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1660 overall.height = qMax(overall.height, ymax - overall.y);
1661 overall.width = xmax - overall.x;
1669 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1672 glyph_metrics_t overall;
1673 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1676 g = loadGlyph(glyph, 0, Format_None, true);
1681 overall.width = g->width;
1682 overall.height = g->height;
1683 overall.xoff = g->advance;
1684 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1685 overall.xoff = overall.xoff.round();
1687 int left = FLOOR(face->glyph->metrics.horiBearingX);
1688 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1689 int top = CEIL(face->glyph->metrics.horiBearingY);
1690 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1692 overall.width = TRUNC(right-left);
1693 overall.height = TRUNC(top-bottom);
1694 overall.x = TRUNC(left);
1695 overall.y = -TRUNC(top);
1696 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1703 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1705 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1708 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1711 glyph_metrics_t overall;
1712 QGlyphSet *glyphSet = 0;
1713 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1714 // TODO move everything here to a method of its own to access glyphSets
1715 // to be shared with a new method that will replace loadTransformedGlyphSet()
1717 m.xx = FT_Fixed(matrix.m11() * 65536);
1718 m.xy = FT_Fixed(-matrix.m21() * 65536);
1719 m.yx = FT_Fixed(-matrix.m12() * 65536);
1720 m.yy = FT_Fixed(matrix.m22() * 65536);
1721 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1722 const QGlyphSet &g = transformedGlyphSets.at(i);
1723 if (g.transformationMatrix.xx == m.xx
1724 && g.transformationMatrix.xy == m.xy
1725 && g.transformationMatrix.yx == m.yx
1726 && g.transformationMatrix.yy == m.yy) {
1728 // found a match, move it to the front
1729 transformedGlyphSets.move(i, 0);
1730 glyphSet = &transformedGlyphSets[0];
1736 // don't cache more than 10 transformations
1737 if (transformedGlyphSets.count() >= 10) {
1738 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1739 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1741 transformedGlyphSets.prepend(QGlyphSet());
1743 glyphSet = &transformedGlyphSets[0];
1745 glyphSet->id = allocateServerGlyphSet();
1746 glyphSet->transformationMatrix = m;
1750 glyphSet = &defaultGlyphSet;
1752 Glyph * g = glyphSet->getGlyph(glyph);
1753 if (!g || g->format != format) {
1755 FT_Matrix m = this->matrix;
1756 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1757 freetype->matrix = m;
1758 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1764 overall.width = g->width;
1765 overall.height = g->height;
1766 overall.xoff = g->advance;
1768 int left = FLOOR(face->glyph->metrics.horiBearingX);
1769 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1770 int top = CEIL(face->glyph->metrics.horiBearingY);
1771 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1773 overall.width = TRUNC(right-left);
1774 overall.height = TRUNC(top-bottom);
1775 overall.x = TRUNC(left);
1776 overall.y = -TRUNC(top);
1777 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1784 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1788 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1790 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1793 return QFontEngine::alphaMapForGlyph(g);
1796 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1798 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1800 QVector<QRgb> colors(256);
1801 for (int i=0; i<256; ++i)
1802 colors[i] = qRgba(0, 0, 0, i);
1803 img.setColorTable(colors);
1805 QVector<QRgb> colors(2);
1806 colors[0] = qRgba(0, 0, 0, 0);
1807 colors[1] = qRgba(0, 0, 0, 255);
1808 img.setColorTable(colors);
1810 Q_ASSERT(img.bytesPerLine() == pitch);
1812 for (int y = 0; y < glyph->height; ++y)
1813 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1820 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1822 if (t.type() > QTransform::TxTranslate)
1823 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1827 GlyphFormat glyph_format = Format_A32;
1829 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1832 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1835 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1836 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1842 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1844 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1847 int QFontEngineFT::glyphCount() const
1850 FT_Face face = lockFace();
1852 count = face->num_glyphs;
1858 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1861 FT_Face face = freetype->face;
1862 if (scale == Unscaled) {
1863 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1864 freetype->xsize = face->units_per_EM << 6;
1865 freetype->ysize = face->units_per_EM << 6;
1866 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1867 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1868 freetype->xsize = xsize;
1869 freetype->ysize = ysize;
1871 if (freetype->matrix.xx != matrix.xx ||
1872 freetype->matrix.yy != matrix.yy ||
1873 freetype->matrix.xy != matrix.xy ||
1874 freetype->matrix.yx != matrix.yx) {
1875 freetype->matrix = matrix;
1876 FT_Set_Transform(face, &freetype->matrix, 0);
1882 void QFontEngineFT::unlockFace() const
1887 FT_Face QFontEngineFT::non_locked_face() const
1889 return freetype->face;
1893 QFontEngineFT::QGlyphSet::QGlyphSet()
1894 : id(0), outline_drawing(false)
1896 transformationMatrix.xx = 0x10000;
1897 transformationMatrix.yy = 0x10000;
1898 transformationMatrix.xy = 0;
1899 transformationMatrix.yx = 0;
1900 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1901 fast_glyph_count = 0;
1904 QFontEngineFT::QGlyphSet::~QGlyphSet()
1909 void QFontEngineFT::QGlyphSet::clear()
1911 if (fast_glyph_count > 0) {
1912 for (int i = 0; i < 256; ++i) {
1913 if (fast_glyph_data[i]) {
1914 delete fast_glyph_data[i];
1915 fast_glyph_data[i] = 0;
1918 fast_glyph_count = 0;
1920 qDeleteAll(glyph_data);
1924 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1926 if (useFastGlyphData(index, subPixelPosition)) {
1927 if (fast_glyph_data[index]) {
1928 delete fast_glyph_data[index];
1929 fast_glyph_data[index] = 0;
1930 if (fast_glyph_count > 0)
1934 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1938 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1940 if (useFastGlyphData(index, subPixelPosition)) {
1941 if (!fast_glyph_data[index])
1943 fast_glyph_data[index] = glyph;
1945 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1949 unsigned long QFontEngineFT::allocateServerGlyphSet()
1954 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1959 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1962 bool hsubpixel = true;
1964 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1965 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1970 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
1972 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1975 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1977 freetype->ref.ref();
1979 default_load_flags = fe->default_load_flags;
1980 default_hint_style = fe->default_hint_style;
1981 antialias = fe->antialias;
1982 transform = fe->transform;
1983 embolden = fe->embolden;
1984 subpixelType = fe->subpixelType;
1985 lcdFilterType = fe->lcdFilterType;
1986 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
1987 embeddedbitmap = fe->embeddedbitmap;
1992 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
1995 fontDef.pixelSize = pixelSize;
1996 QFontEngineFT *fe = new QFontEngineFT(fontDef);
1997 if (!fe->initFromFontEngine(this)) {
2007 #endif // QT_NO_FREETYPE