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 unsigned int uc = str[i].unicode();
1421 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
1422 uint low = str[i+1].unicode();
1423 if (low >= 0xdc00 && low < 0xe000) {
1424 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
1431 bool QFontEngineFT::canRender(const QChar *string, int len)
1433 FT_Face face = freetype->face;
1437 for ( int i = 0; i < len; i++ ) {
1438 unsigned int uc = getChar(string, i, len);
1439 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1448 for ( int i = 0; i < len; i++ ) {
1449 unsigned int uc = getChar(string, i, len);
1450 if (!FT_Get_Char_Index(face, uc))
1457 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1459 if (!glyphs.numGlyphs)
1462 if (FT_IS_SCALABLE(freetype->face)) {
1463 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1465 QVarLengthArray<QFixedPoint> positions;
1466 QVarLengthArray<glyph_t> positioned_glyphs;
1468 matrix.translate(x, y);
1469 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1471 FT_Face face = lockFace(Unscaled);
1472 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1473 FT_UInt glyph = positioned_glyphs[gl];
1474 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1475 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1481 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1482 QPainterPath *path, QTextItem::RenderFlags)
1484 FT_Face face = lockFace(Unscaled);
1486 for (int gl = 0; gl < numGlyphs; gl++) {
1487 FT_UInt glyph = glyphs[gl];
1489 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1491 FT_GlyphSlot g = face->glyph;
1492 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1494 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1499 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1500 QTextEngine::ShaperFlags flags) const
1502 if (*nglyphs < len) {
1507 #if !defined(QT_NO_FONTCONFIG)
1508 extern QMutex *qt_fontdatabase_mutex();
1512 bool mirrored = flags & QTextEngine::RightToLeft;
1514 if (freetype->symbol_map) {
1515 FT_Face face = freetype->face;
1516 for ( int i = 0; i < len; ++i ) {
1517 unsigned int uc = getChar(str, i, len);
1518 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1519 if ( !glyphs->glyphs[glyph_pos] ) {
1521 #if !defined(QT_NO_FONTCONFIG)
1523 mtx = qt_fontdatabase_mutex();
1527 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1532 glyph = FT_Get_Char_Index(face, uc);
1533 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1538 FT_Set_Charmap(face, freetype->symbol_map);
1539 glyph = FT_Get_Char_Index(face, uc);
1540 FT_Set_Charmap(face, freetype->unicode_map);
1542 glyphs->glyphs[glyph_pos] = glyph;
1543 if (uc < QFreetypeFace::cmapCacheSize)
1544 freetype->cmapCache[uc] = glyph;
1549 FT_Face face = freetype->face;
1550 for (int i = 0; i < len; ++i) {
1551 unsigned int uc = getChar(str, i, len);
1553 uc = QChar::mirroredChar(uc);
1554 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1555 if (!glyphs->glyphs[glyph_pos]) {
1556 #if !defined(QT_NO_FONTCONFIG)
1558 mtx = qt_fontdatabase_mutex();
1562 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1566 glyph_t glyph = FT_Get_Char_Index(face, uc);
1567 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1571 glyphs->glyphs[glyph_pos] = glyph;
1572 if (uc < QFreetypeFace::cmapCacheSize)
1573 freetype->cmapCache[uc] = glyph;
1580 *nglyphs = glyph_pos;
1581 glyphs->numGlyphs = glyph_pos;
1583 #if !defined(QT_NO_FONTCONFIG)
1588 if (flags & QTextEngine::GlyphIndicesOnly)
1591 recalcAdvances(glyphs, flags);
1596 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1599 bool design = (default_hint_style == HintNone ||
1600 default_hint_style == HintLight ||
1601 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1602 for (int i = 0; i < glyphs->numGlyphs; i++) {
1603 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1605 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1609 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1610 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1611 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1613 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1614 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1615 glyphs->advances_y[i] = 0;
1621 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1626 glyph_metrics_t overall;
1627 // initialize with line height, we get the same behaviour on all platforms
1628 overall.y = -ascent();
1629 overall.height = ascent() + descent() + 1;
1633 for (int i = 0; i < glyphs.numGlyphs; i++) {
1634 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1638 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1641 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1642 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1643 overall.x = qMin(overall.x, x);
1644 overall.y = qMin(overall.y, y);
1645 xmax = qMax(xmax, x + g->width);
1646 ymax = qMax(ymax, y + g->height);
1647 overall.xoff += g->advance;
1649 int left = FLOOR(face->glyph->metrics.horiBearingX);
1650 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1651 int top = CEIL(face->glyph->metrics.horiBearingY);
1652 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1654 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1655 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1656 overall.x = qMin(overall.x, x);
1657 overall.y = qMin(overall.y, y);
1658 xmax = qMax(xmax, x + TRUNC(right - left));
1659 ymax = qMax(ymax, y + TRUNC(top - bottom));
1660 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1663 overall.height = qMax(overall.height, ymax - overall.y);
1664 overall.width = xmax - overall.x;
1672 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1675 glyph_metrics_t overall;
1676 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1679 g = loadGlyph(glyph, 0, Format_None, true);
1684 overall.width = g->width;
1685 overall.height = g->height;
1686 overall.xoff = g->advance;
1687 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1688 overall.xoff = overall.xoff.round();
1690 int left = FLOOR(face->glyph->metrics.horiBearingX);
1691 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1692 int top = CEIL(face->glyph->metrics.horiBearingY);
1693 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1695 overall.width = TRUNC(right-left);
1696 overall.height = TRUNC(top-bottom);
1697 overall.x = TRUNC(left);
1698 overall.y = -TRUNC(top);
1699 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1706 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1708 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1711 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1714 glyph_metrics_t overall;
1715 QGlyphSet *glyphSet = 0;
1716 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1717 // TODO move everything here to a method of its own to access glyphSets
1718 // to be shared with a new method that will replace loadTransformedGlyphSet()
1720 m.xx = FT_Fixed(matrix.m11() * 65536);
1721 m.xy = FT_Fixed(-matrix.m21() * 65536);
1722 m.yx = FT_Fixed(-matrix.m12() * 65536);
1723 m.yy = FT_Fixed(matrix.m22() * 65536);
1724 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1725 const QGlyphSet &g = transformedGlyphSets.at(i);
1726 if (g.transformationMatrix.xx == m.xx
1727 && g.transformationMatrix.xy == m.xy
1728 && g.transformationMatrix.yx == m.yx
1729 && g.transformationMatrix.yy == m.yy) {
1731 // found a match, move it to the front
1732 transformedGlyphSets.move(i, 0);
1733 glyphSet = &transformedGlyphSets[0];
1739 // don't cache more than 10 transformations
1740 if (transformedGlyphSets.count() >= 10) {
1741 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1742 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1744 transformedGlyphSets.prepend(QGlyphSet());
1746 glyphSet = &transformedGlyphSets[0];
1748 glyphSet->id = allocateServerGlyphSet();
1749 glyphSet->transformationMatrix = m;
1753 glyphSet = &defaultGlyphSet;
1755 Glyph * g = glyphSet->getGlyph(glyph);
1756 if (!g || g->format != format) {
1758 FT_Matrix m = this->matrix;
1759 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1760 freetype->matrix = m;
1761 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1767 overall.width = g->width;
1768 overall.height = g->height;
1769 overall.xoff = g->advance;
1771 int left = FLOOR(face->glyph->metrics.horiBearingX);
1772 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1773 int top = CEIL(face->glyph->metrics.horiBearingY);
1774 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1776 overall.width = TRUNC(right-left);
1777 overall.height = TRUNC(top-bottom);
1778 overall.x = TRUNC(left);
1779 overall.y = -TRUNC(top);
1780 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1787 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1791 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1793 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1796 return QFontEngine::alphaMapForGlyph(g);
1799 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1801 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1803 QVector<QRgb> colors(256);
1804 for (int i=0; i<256; ++i)
1805 colors[i] = qRgba(0, 0, 0, i);
1806 img.setColorTable(colors);
1808 QVector<QRgb> colors(2);
1809 colors[0] = qRgba(0, 0, 0, 0);
1810 colors[1] = qRgba(0, 0, 0, 255);
1811 img.setColorTable(colors);
1813 Q_ASSERT(img.bytesPerLine() == pitch);
1815 for (int y = 0; y < glyph->height; ++y)
1816 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1823 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1825 if (t.type() > QTransform::TxTranslate)
1826 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1830 GlyphFormat glyph_format = Format_A32;
1832 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1835 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1838 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1839 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1845 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1847 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1850 int QFontEngineFT::glyphCount() const
1853 FT_Face face = lockFace();
1855 count = face->num_glyphs;
1861 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1864 FT_Face face = freetype->face;
1865 if (scale == Unscaled) {
1866 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1867 freetype->xsize = face->units_per_EM << 6;
1868 freetype->ysize = face->units_per_EM << 6;
1869 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1870 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1871 freetype->xsize = xsize;
1872 freetype->ysize = ysize;
1874 if (freetype->matrix.xx != matrix.xx ||
1875 freetype->matrix.yy != matrix.yy ||
1876 freetype->matrix.xy != matrix.xy ||
1877 freetype->matrix.yx != matrix.yx) {
1878 freetype->matrix = matrix;
1879 FT_Set_Transform(face, &freetype->matrix, 0);
1885 void QFontEngineFT::unlockFace() const
1890 FT_Face QFontEngineFT::non_locked_face() const
1892 return freetype->face;
1896 QFontEngineFT::QGlyphSet::QGlyphSet()
1897 : id(0), outline_drawing(false)
1899 transformationMatrix.xx = 0x10000;
1900 transformationMatrix.yy = 0x10000;
1901 transformationMatrix.xy = 0;
1902 transformationMatrix.yx = 0;
1903 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1904 fast_glyph_count = 0;
1907 QFontEngineFT::QGlyphSet::~QGlyphSet()
1912 void QFontEngineFT::QGlyphSet::clear()
1914 if (fast_glyph_count > 0) {
1915 for (int i = 0; i < 256; ++i) {
1916 if (fast_glyph_data[i]) {
1917 delete fast_glyph_data[i];
1918 fast_glyph_data[i] = 0;
1921 fast_glyph_count = 0;
1923 qDeleteAll(glyph_data);
1927 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1929 if (useFastGlyphData(index, subPixelPosition)) {
1930 if (fast_glyph_data[index]) {
1931 delete fast_glyph_data[index];
1932 fast_glyph_data[index] = 0;
1933 if (fast_glyph_count > 0)
1937 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1941 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1943 if (useFastGlyphData(index, subPixelPosition)) {
1944 if (!fast_glyph_data[index])
1946 fast_glyph_data[index] = glyph;
1948 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1952 unsigned long QFontEngineFT::allocateServerGlyphSet()
1957 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1962 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1965 bool hsubpixel = true;
1967 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1968 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1973 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
1975 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1978 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1980 freetype->ref.ref();
1982 default_load_flags = fe->default_load_flags;
1983 default_hint_style = fe->default_hint_style;
1984 antialias = fe->antialias;
1985 transform = fe->transform;
1986 embolden = fe->embolden;
1987 subpixelType = fe->subpixelType;
1988 lcdFilterType = fe->lcdFilterType;
1989 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
1990 embeddedbitmap = fe->embeddedbitmap;
1995 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
1998 fontDef.pixelSize = pixelSize;
1999 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2000 if (!fe->initFromFontEngine(this)) {
2010 #endif // QT_NO_FREETYPE