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 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
103 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
104 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
105 #define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
107 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
110 #define FLOOR(x) ((x) & -64)
111 #define CEIL(x) (((x)+63) & -64)
112 #define TRUNC(x) ((x) >> 6)
113 #define ROUND(x) (((x)+32) & -64)
115 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
117 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
118 FT_Face face = (FT_Face)font;
119 FT_ULong ftlen = *length;
122 if ( !FT_IS_SFNT(face) )
123 return HB_Err_Invalid_Argument;
125 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
127 return (HB_Error)error;
129 return HB_Err_Invalid_Argument;
133 // -------------------------- Freetype support ------------------------------
143 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
147 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
149 QtFreetypeData *qt_getFreetypeData()
151 return theFreetypeData();
154 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
156 QtFreetypeData *qt_getFreetypeData()
158 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
160 freetypeData = new QtFreetypeData;
165 FT_Library qt_getFreetype()
167 QtFreetypeData *freetypeData = qt_getFreetypeData();
168 if (!freetypeData->library)
169 FT_Init_FreeType(&freetypeData->library);
170 return freetypeData->library;
173 int QFreetypeFace::fsType() const
176 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
178 fsType = os2->fsType;
182 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
184 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
187 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
188 return HB_Err_Invalid_SubTable;
190 *nPoints = face->glyph->outline.n_points;
194 if (point > *nPoints)
195 return HB_Err_Invalid_SubTable;
197 *xpos = face->glyph->outline.points[point].x;
198 *ypos = face->glyph->outline.points[point].y;
204 * One font file can contain more than one font (bold/italic for example)
205 * find the right one and return it.
207 * Returns the freetype face or 0 in case of an empty file or any other problems
208 * (like not being able to open the file)
210 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
211 const QByteArray &fontData)
213 if (face_id.filename.isEmpty() && fontData.isEmpty())
216 QtFreetypeData *freetypeData = qt_getFreetypeData();
217 if (!freetypeData->library)
218 FT_Init_FreeType(&freetypeData->library);
220 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
224 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
226 if (!face_id.filename.isEmpty()) {
227 QFile file(QString::fromUtf8(face_id.filename));
228 if (face_id.filename.startsWith(":qmemoryfonts/")) {
229 // from qfontdatabase.cpp
230 extern QByteArray qt_fontdata_from_index(int);
231 QByteArray idx = face_id.filename;
232 idx.remove(0, 14); // remove ':qmemoryfonts/'
234 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
236 newFreetype->fontData = QByteArray();
237 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
238 if (!file.open(QIODevice::ReadOnly)) {
241 newFreetype->fontData = file.readAll();
244 newFreetype->fontData = fontData;
246 if (!newFreetype->fontData.isEmpty()) {
247 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
250 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
253 newFreetype->face = face;
255 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
256 Q_CHECK_PTR(newFreetype->hbFace);
257 newFreetype->ref = 1;
258 newFreetype->xsize = 0;
259 newFreetype->ysize = 0;
260 newFreetype->matrix.xx = 0x10000;
261 newFreetype->matrix.yy = 0x10000;
262 newFreetype->matrix.xy = 0;
263 newFreetype->matrix.yx = 0;
264 newFreetype->unicode_map = 0;
265 newFreetype->symbol_map = 0;
266 #ifndef QT_NO_FONTCONFIG
267 newFreetype->charset = 0;
270 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
272 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
273 FT_CharMap cm = newFreetype->face->charmaps[i];
274 switch(cm->encoding) {
275 case FT_ENCODING_UNICODE:
276 newFreetype->unicode_map = cm;
278 case FT_ENCODING_APPLE_ROMAN:
279 case FT_ENCODING_ADOBE_LATIN_1:
280 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
281 newFreetype->unicode_map = cm;
283 case FT_ENCODING_ADOBE_CUSTOM:
284 case FT_ENCODING_MS_SYMBOL:
285 if (!newFreetype->symbol_map)
286 newFreetype->symbol_map = cm;
293 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
294 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
297 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
298 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
299 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
300 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
301 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
303 for (int i = 0; i < 256; i += 8)
304 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
305 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
306 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
307 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
308 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
311 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
313 freetypeData->faces.insert(face_id, newFreetype.data());
315 newFreetype.take()->release(face_id);
316 // we could return null in principle instead of throwing
319 freetype = newFreetype.take();
324 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
326 QtFreetypeData *freetypeData = qt_getFreetypeData();
330 #ifndef QT_NO_FONTCONFIG
332 FcCharSetDestroy(charset);
334 if(freetypeData->faces.contains(face_id))
335 freetypeData->faces.take(face_id);
338 if (freetypeData->faces.isEmpty()) {
339 FT_Done_FreeType(freetypeData->library);
340 freetypeData->library = 0;
345 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
347 *ysize = qRound(fontDef.pixelSize * 64);
348 *xsize = *ysize * fontDef.stretch / 100;
349 *outline_drawing = false;
352 * Bitmap only faces must match exactly, so find the closest
353 * one (height dominant search)
355 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
357 for (int i = 1; i < face->num_fixed_sizes; i++) {
358 if (qAbs(*ysize - Y_SIZE(face,i)) <
359 qAbs (*ysize - Y_SIZE(face, best)) ||
360 (qAbs (*ysize - Y_SIZE(face, i)) ==
361 qAbs (*ysize - Y_SIZE(face, best)) &&
362 qAbs (*xsize - X_SIZE(face, i)) <
363 qAbs (*xsize - X_SIZE(face, best)))) {
367 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
368 *xsize = X_SIZE(face, best);
369 *ysize = Y_SIZE(face, best);
372 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
373 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
374 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
375 if (err && face->num_fixed_sizes == 1)
376 err = 0; //even more of a workaround...
383 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
387 QFontEngine::Properties QFreetypeFace::properties() const
389 QFontEngine::Properties p;
390 p.postscriptName = FT_Get_Postscript_Name(face);
391 PS_FontInfoRec font_info;
392 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
393 p.copyright = font_info.notice;
394 if (FT_IS_SCALABLE(face)) {
395 p.ascent = face->ascender;
396 p.descent = -face->descender;
397 p.leading = face->height - face->ascender + face->descender;
398 p.emSquare = face->units_per_EM;
399 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
400 face->bbox.xMax - face->bbox.xMin,
401 face->bbox.yMax - face->bbox.yMin);
403 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
404 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
405 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
406 p.emSquare = face->size->metrics.y_ppem;
407 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
408 p.boundingBox = QRectF(0, -p.ascent.toReal(),
409 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
412 p.capHeight = p.ascent;
413 p.lineWidth = face->underline_thickness;
417 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
420 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
421 if (FT_IS_SFNT(face)) {
422 FT_ULong len = *length;
423 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
430 /* Some fonts (such as MingLiu rely on hinting to scale different
431 components to their correct sizes. While this is really broken (it
432 should be done in the component glyph itself, not the hinter) we
433 will have to live with it.
435 This means we can not use FT_LOAD_NO_HINTING to get the glyph
436 outline. All we can do is to load the unscaled glyph and scale it
437 down manually when required.
439 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
441 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
442 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
443 FT_Vector *p = g->outline.points;
444 const FT_Vector *e = p + g->outline.n_points;
446 p->x = FT_MulFix(p->x, x_scale);
447 p->y = FT_MulFix(p->y, y_scale);
452 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
454 const qreal factor = 1/64.;
455 scaleOutline(face, g, x_scale, y_scale);
457 QPointF cp = point.toPointF();
459 // convert the outline to a painter path
461 for (int j = 0; j < g->outline.n_contours; ++j) {
462 int last_point = g->outline.contours[j];
463 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
464 if(!(g->outline.tags[i] & 1)) {
465 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
468 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
469 // qDebug("first point at %f %f", start.x(), start.y());
475 while (i < last_point) {
477 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
478 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
480 switch (g->outline.tags[i] & 3) {
482 // cubic bezier element
485 c[3] = (c[3] + c[2])/2;
489 // quadratic bezier element
492 c[3] = (c[1] + c[2])/2;
493 c[2] = (2*c[1] + c[3])/3;
494 c[1] = (2*c[1] + c[0])/3;
500 // qDebug() << "lineTo" << c[1];
507 c[2] = (2*c[1] + c[3])/3;
508 c[1] = (2*c[1] + c[0])/3;
512 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
513 path->cubicTo(c[1], c[2], c[3]);
518 // qDebug() << "closeSubpath";
519 path->closeSubpath();
523 c[2] = (2*c[1] + c[3])/3;
524 c[1] = (2*c[1] + c[0])/3;
526 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
527 path->cubicTo(c[1], c[2], c[3]);
533 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
535 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
537 if (slot->format != FT_GLYPH_FORMAT_BITMAP
538 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
541 QPointF cp = point.toPointF();
542 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
543 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
546 QFontEngineFT::Glyph::~Glyph()
551 static const uint subpixel_filter[3][3] = {
557 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
561 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
562 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
563 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
564 res = (mid << 24) + (high << 16) + (mid << 8) + low;
567 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
572 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
575 const int offs = bgr ? -1 : 1;
576 const int w = width * 3;
579 for (int x = 0; x < w; x += 3) {
580 uint red = src[x+1-offs];
581 uint green = src[x+1];
582 uint blue = src[x+1+offs];
583 *dd = filterPixel(red, green, blue, legacyFilter);
591 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
594 const int offs = bgr ? -src_pitch : src_pitch;
596 for (int x = 0; x < width; x++) {
597 uint red = src[x+src_pitch-offs];
598 uint green = src[x+src_pitch];
599 uint blue = src[x+src_pitch+offs];
600 dst[x] = filterPixel(red, green, blue, legacyFilter);
607 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
609 // convolute the bitmap with a triangle filter to get rid of color fringes
610 // If we take account for a gamma value of 2, we end up with
611 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
612 // as this nicely sums up to 16 :)
617 for (int x = 2; x < width - 2; ++x) {
618 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
619 dst[x] = (uchar) (sum >> 4);
621 dst[width - 2] = dst[width - 1] = 0;
627 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
635 kerning_pairs_loaded = false;
641 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
642 default_hint_style = HintNone;
643 subpixelType = Subpixel_None;
645 #if defined(FT_LCD_FILTER_H)
646 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
648 defaultFormat = Format_None;
649 canUploadGlyphsToServer = false;
650 embeddedbitmap = false;
653 QFontEngineFT::~QFontEngineFT()
656 freetype->release(face_id);
657 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
660 void QFontEngineFT::freeGlyphSets()
662 freeServerGlyphSet(defaultGlyphSet.id);
663 for (int i = 0; i < transformedGlyphSets.count(); ++i)
664 freeServerGlyphSet(transformedGlyphSets.at(i).id);
667 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
668 const QByteArray &fontData)
670 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
673 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
674 QFreetypeFace *freetypeFace)
676 freetype = freetypeFace;
682 defaultFormat = format;
683 this->antialias = antialias;
686 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
687 else if (format == Format_A8)
688 glyphFormat = QFontEngineGlyphCache::Raster_A8;
689 else if (format == Format_A32)
690 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
694 symbol = freetype->symbol_map != 0;
695 PS_FontInfoRec psrec;
696 // don't assume that type1 fonts are symbol fonts by default
697 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
698 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
701 freetype->hbFace->isSymbolFont = symbol;
703 lbearing = rbearing = SHRT_MIN;
704 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
706 FT_Face face = lockFace();
708 if (FT_IS_SCALABLE(face)) {
709 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
711 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
712 matrix.xy = 0x10000*3/10;
718 FT_Set_Transform(face, &matrix, 0);
719 freetype->matrix = matrix;
721 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
724 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
725 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
727 // copied from QFontEngineQPF
729 int score = fontDef.weight * fontDef.pixelSize;
730 line_thickness = score / 700;
731 // looks better with thicker line for small pointsizes
732 if (line_thickness < 2 && score >= 1050)
734 underline_position = ((line_thickness * 2) + 3) / 6;
736 if (line_thickness < 1)
739 hbFont.x_ppem = face->size->metrics.x_ppem;
740 hbFont.y_ppem = face->size->metrics.y_ppem;
741 hbFont.x_scale = face->size->metrics.x_scale;
742 hbFont.y_scale = face->size->metrics.y_scale;
744 hbFace = freetype->hbFace;
746 metrics = face->size->metrics;
748 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
750 TrueType fonts with embedded bitmaps may have a bitmap font specific
751 ascent/descent in the EBLC table. There is no direct public API
752 to extract those values. The only way we've found is to trick freetype
753 into thinking that it's not a scalable font in FT_SelectSize so that
754 the metrics are retrieved from the bitmap strikes.
756 if (FT_IS_SCALABLE(face)) {
757 for (int i = 0; i < face->num_fixed_sizes; ++i) {
758 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
759 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
761 FT_Select_Size(face, i);
762 metrics.ascender = face->size->metrics.ascender;
763 metrics.descender = face->size->metrics.descender;
764 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
766 face->face_flags |= FT_FACE_FLAG_SCALABLE;
773 fontDef.styleName = QString::fromUtf8(face->style_name);
777 fsType = freetype->fsType();
778 defaultGlyphSet.id = allocateServerGlyphSet();
782 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
784 default_hint_style = style;
787 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
788 bool &hsubpixel, int &vfactor) const
790 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
791 int load_target = default_hint_style == HintLight
792 ? FT_LOAD_TARGET_LIGHT
793 : FT_LOAD_TARGET_NORMAL;
795 if (format == Format_Mono) {
796 load_target = FT_LOAD_TARGET_MONO;
797 } else if (format == Format_A32) {
798 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
799 if (default_hint_style == HintFull)
800 load_target = FT_LOAD_TARGET_LCD;
802 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
803 if (default_hint_style == HintFull)
804 load_target = FT_LOAD_TARGET_LCD_V;
809 if (set && set->outline_drawing)
810 load_flags = FT_LOAD_NO_BITMAP;
812 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || set->outline_drawing)
813 load_flags |= FT_LOAD_NO_HINTING;
815 load_flags |= load_target;
820 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
821 QFixed subPixelPosition,
823 bool fetchMetricsOnly) const
825 // Q_ASSERT(freetype->lock == 1);
827 bool uploadToServer = false;
828 if (format == Format_None) {
829 if (defaultFormat != Format_None) {
830 format = defaultFormat;
831 if (canUploadGlyphsToServer)
832 uploadToServer = true;
834 format = Format_Mono;
838 Glyph *g = set->getGlyph(glyph, subPixelPosition);
839 if (g && g->format == format) {
840 if (uploadToServer && !g->uploadedToServer) {
841 set->setGlyph(glyph, subPixelPosition, 0);
849 QFontEngineFT::GlyphInfo info;
851 Q_ASSERT(format != Format_None);
852 bool hsubpixel = false;
854 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
857 if (format != Format_Mono && !embeddedbitmap)
858 load_flags |= FT_LOAD_NO_BITMAP;
861 FT_Matrix matrix = freetype->matrix;
862 bool transform = matrix.xx != 0x10000
863 || matrix.yy != 0x10000
868 load_flags |= FT_LOAD_NO_BITMAP;
870 FT_Face face = freetype->face;
873 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
875 FT_Set_Transform(face, &freetype->matrix, &v);
877 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
878 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
879 load_flags &= ~FT_LOAD_NO_BITMAP;
880 err = FT_Load_Glyph(face, glyph, load_flags);
882 if (err == FT_Err_Too_Few_Arguments) {
883 // this is an error in the bytecode interpreter, just try to run without it
884 load_flags |= FT_LOAD_FORCE_AUTOHINT;
885 err = FT_Load_Glyph(face, glyph, load_flags);
887 if (err != FT_Err_Ok)
888 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
890 if (set->outline_drawing && fetchMetricsOnly)
893 FT_GlyphSlot slot = face->glyph;
894 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
896 Q_FT_GLYPHSLOT_OBLIQUE(slot);
898 // While Embolden alters the metrics of the slot, oblique does not, so we need
899 // to fix this ourselves.
907 FT_Matrix_Multiply(&m, &matrix);
910 FT_Library library = qt_getFreetype();
912 info.xOff = TRUNC(ROUND(slot->advance.x));
915 uchar *glyph_buffer = 0;
916 int glyph_buffer_size = 0;
917 #if defined(QT_USE_FREETYPE_LCDFILTER)
918 bool useFreetypeRenderGlyph = false;
919 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
920 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
921 if (err == FT_Err_Ok)
922 useFreetypeRenderGlyph = true;
925 if (useFreetypeRenderGlyph) {
926 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
928 if (err != FT_Err_Ok)
929 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
931 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
933 info.height = slot->bitmap.rows / vfactor;
934 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
935 info.x = -slot->bitmap_left;
936 info.y = slot->bitmap_top;
938 glyph_buffer_size = info.width * info.height * 4;
939 glyph_buffer = new uchar[glyph_buffer_size];
942 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
943 else if (vfactor != 1)
944 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
948 int left = slot->metrics.horiBearingX;
949 int right = slot->metrics.horiBearingX + slot->metrics.width;
950 int top = slot->metrics.horiBearingY;
951 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
952 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
957 FT_Vector_Transform(&vector, &matrix);
962 FT_Vector_Transform(&vector, &matrix);
963 if (l > vector.x) l = vector.x;
964 if (r < vector.x) r = vector.x;
965 if (t < vector.y) t = vector.y;
966 if (b > vector.y) b = vector.y;
969 FT_Vector_Transform(&vector, &matrix);
970 if (l > vector.x) l = vector.x;
971 if (r < vector.x) r = vector.x;
972 if (t < vector.y) t = vector.y;
973 if (b > vector.y) b = vector.y;
976 FT_Vector_Transform(&vector, &matrix);
977 if (l > vector.x) l = vector.x;
978 if (r < vector.x) r = vector.x;
979 if (t < vector.y) t = vector.y;
980 if (b > vector.y) b = vector.y;
988 bottom = FLOOR(bottom);
991 int hpixels = TRUNC(right - left);
992 // subpixel position requires one more pixel
993 if (subPixelPosition > 0 && format != Format_Mono)
997 hpixels = hpixels*3 + 8;
998 info.width = hpixels;
999 info.height = TRUNC(top - bottom);
1000 info.x = -TRUNC(left);
1001 info.y = TRUNC(top);
1007 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1008 || ((uchar)(info.width) != info.width)
1009 || ((uchar)(info.height) != info.height)
1010 || ((signed char)(info.x) != info.x)
1011 || ((signed char)(info.y) != info.y)
1012 || ((signed char)(info.xOff) != info.xOff));
1015 delete [] glyph_buffer;
1019 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1020 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1021 glyph_buffer_size = pitch * info.height;
1022 glyph_buffer = new uchar[glyph_buffer_size];
1024 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1026 bitmap.rows = info.height*vfactor;
1027 bitmap.width = hpixels;
1028 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1029 if (!hsubpixel && vfactor == 1)
1030 bitmap.buffer = glyph_buffer;
1032 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1033 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1034 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1036 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1037 matrix.yy = vfactor << 16;
1038 matrix.yx = matrix.xy = 0;
1040 FT_Outline_Transform(&slot->outline, &matrix);
1041 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1042 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1044 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1045 Q_ASSERT(antialias);
1046 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1047 bool useLegacyLcdFilter = false;
1048 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1049 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1051 uchar *buffer = bitmap.buffer;
1052 if (!useLegacyLcdFilter) {
1053 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1054 buffer = convoluted;
1056 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1057 delete [] convoluted;
1058 } else if (vfactor != 1) {
1059 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1062 if (bitmap.buffer != glyph_buffer)
1063 delete [] bitmap.buffer;
1064 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1065 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1066 uchar *src = slot->bitmap.buffer;
1067 uchar *dst = glyph_buffer;
1068 int h = slot->bitmap.rows;
1069 if (format == Format_Mono) {
1070 int bytes = ((info.width + 7) & ~7) >> 3;
1072 memcpy (dst, src, bytes);
1074 src += slot->bitmap.pitch;
1079 uint *dd = (uint *)dst;
1081 for (int x = 0; x < slot->bitmap.width; x++) {
1082 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1087 src += slot->bitmap.pitch;
1089 } else if (vfactor != 1) {
1091 uint *dd = (uint *)dst;
1092 for (int x = 0; x < slot->bitmap.width; x++) {
1093 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1097 src += slot->bitmap.pitch;
1101 for (int x = 0; x < slot->bitmap.width; x++) {
1102 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1106 src += slot->bitmap.pitch;
1111 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1112 delete [] glyph_buffer;
1120 g->uploadedToServer = false;
1124 g->linearAdvance = slot->linearHoriAdvance >> 10;
1125 g->width = info.width;
1126 g->height = info.height;
1129 g->advance = info.xOff;
1132 g->data = glyph_buffer;
1134 if (uploadToServer) {
1135 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1138 set->setGlyph(glyph, subPixelPosition, g);
1143 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1149 Q_UNUSED(glyphDataSize);
1153 QFontEngine::FaceId QFontEngineFT::faceId() const
1158 QFontEngine::Properties QFontEngineFT::properties() const
1160 Properties p = freetype->properties();
1161 if (p.postscriptName.isEmpty()) {
1162 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1165 return freetype->properties();
1168 QFixed QFontEngineFT::emSquareSize() const
1170 if (FT_IS_SCALABLE(freetype->face))
1171 return freetype->face->units_per_EM;
1173 return freetype->face->size->metrics.y_ppem;
1176 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1178 return freetype->getSfntTable(tag, buffer, length);
1181 int QFontEngineFT::synthesized() const
1184 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1185 s = SynthesizedItalic;
1186 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1187 s |= SynthesizedBold;
1188 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1189 s |= SynthesizedStretch;
1193 QFixed QFontEngineFT::ascent() const
1195 return QFixed::fromFixed(metrics.ascender);
1198 QFixed QFontEngineFT::descent() const
1200 // subtract a pixel to work around QFontMetrics's built-in + 1
1201 return QFixed::fromFixed(-metrics.descender - 64);
1204 QFixed QFontEngineFT::leading() const
1206 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1209 QFixed QFontEngineFT::xHeight() const
1211 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1212 if (os2 && os2->sxHeight) {
1214 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1218 return QFontEngine::xHeight();
1221 QFixed QFontEngineFT::averageCharWidth() const
1223 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1224 if (os2 && os2->xAvgCharWidth) {
1226 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1230 return QFontEngine::averageCharWidth();
1233 qreal QFontEngineFT::maxCharWidth() const
1235 return metrics.max_advance >> 6;
1238 static const ushort char_table[] = {
1259 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1262 qreal QFontEngineFT::minLeftBearing() const
1264 if (lbearing == SHRT_MIN)
1265 (void) minRightBearing(); // calculates both
1266 return lbearing.toReal();
1269 qreal QFontEngineFT::minRightBearing() const
1271 if (rbearing == SHRT_MIN) {
1272 lbearing = rbearing = 0;
1273 const QChar *ch = (const QChar *)(const void*)char_table;
1274 QGlyphLayoutArray<char_table_entries> glyphs;
1275 int ng = char_table_entries;
1276 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1278 if (glyphs.glyphs[ng]) {
1279 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1280 lbearing = qMin(lbearing, gi.x);
1281 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1285 return rbearing.toReal();
1288 QFixed QFontEngineFT::lineThickness() const
1290 return line_thickness;
1293 QFixed QFontEngineFT::underlinePosition() const
1295 return underline_position;
1298 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1300 if (!kerning_pairs_loaded) {
1301 kerning_pairs_loaded = true;
1303 if (freetype->face->size->metrics.x_ppem != 0) {
1304 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1306 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1311 QFontEngine::doKerning(g, flags);
1314 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1316 if (matrix.type() > QTransform::TxShear)
1319 // FT_Set_Transform only supports scalable fonts
1320 if (!FT_IS_SCALABLE(freetype->face))
1324 m.xx = FT_Fixed(matrix.m11() * 65536);
1325 m.xy = FT_Fixed(-matrix.m21() * 65536);
1326 m.yx = FT_Fixed(-matrix.m12() * 65536);
1327 m.yy = FT_Fixed(matrix.m22() * 65536);
1331 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1332 const QGlyphSet &g = transformedGlyphSets.at(i);
1333 if (g.transformationMatrix.xx == m.xx
1334 && g.transformationMatrix.xy == m.xy
1335 && g.transformationMatrix.yx == m.yx
1336 && g.transformationMatrix.yy == m.yy) {
1338 // found a match, move it to the front
1339 transformedGlyphSets.move(i, 0);
1340 gs = &transformedGlyphSets[0];
1346 // don't try to load huge fonts
1347 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1348 if (draw_as_outline)
1351 // don't cache more than 10 transformations
1352 if (transformedGlyphSets.count() >= 10) {
1353 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1354 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1356 transformedGlyphSets.prepend(QGlyphSet());
1358 gs = &transformedGlyphSets[0];
1362 gs->id = allocateServerGlyphSet();
1364 gs->transformationMatrix = m;
1365 gs->outline_drawing = draw_as_outline;
1371 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1373 int m_subPixelPositionCount = 4;
1374 if (!supportsSubPixelPositions())
1377 QFixed subPixelPosition;
1379 subPixelPosition = x - x.floor();
1380 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1381 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1383 return subPixelPosition;
1386 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1387 const QFixedPoint *positions,
1392 for (int i = 0; i < num_glyphs; ++i) {
1393 QFixed spp = subPixelPositionForX(positions[i].x);
1394 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1395 if (glyph == 0 || glyph->format != format) {
1398 FT_Matrix m = matrix;
1399 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1400 FT_Set_Transform(face, &m, 0);
1401 freetype->matrix = m;
1403 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1416 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1418 FT_Face face = lockFace(Unscaled);
1419 FT_Set_Transform(face, 0, 0);
1420 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1422 int left = face->glyph->metrics.horiBearingX;
1423 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1424 int top = face->glyph->metrics.horiBearingY;
1425 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1431 metrics->width = QFixed::fromFixed(right-left);
1432 metrics->height = QFixed::fromFixed(top-bottom);
1433 metrics->x = QFixed::fromFixed(left);
1434 metrics->y = QFixed::fromFixed(-top);
1435 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1437 if (!FT_IS_SCALABLE(freetype->face))
1438 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1440 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1442 FT_Set_Transform(face, &freetype->matrix, 0);
1446 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1448 uint ucs4 = str[i].unicode();
1449 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1451 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1456 bool QFontEngineFT::canRender(const QChar *string, int len)
1458 FT_Face face = freetype->face;
1462 for ( int i = 0; i < len; i++ ) {
1463 unsigned int uc = getChar(string, i, len);
1464 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1473 for ( int i = 0; i < len; i++ ) {
1474 unsigned int uc = getChar(string, i, len);
1475 if (!FT_Get_Char_Index(face, uc))
1482 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1484 if (!glyphs.numGlyphs)
1487 if (FT_IS_SCALABLE(freetype->face)) {
1488 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1490 QVarLengthArray<QFixedPoint> positions;
1491 QVarLengthArray<glyph_t> positioned_glyphs;
1493 matrix.translate(x, y);
1494 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1496 FT_Face face = lockFace(Unscaled);
1497 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1498 FT_UInt glyph = positioned_glyphs[gl];
1499 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1500 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1506 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1507 QPainterPath *path, QTextItem::RenderFlags)
1509 FT_Face face = lockFace(Unscaled);
1511 for (int gl = 0; gl < numGlyphs; gl++) {
1512 FT_UInt glyph = glyphs[gl];
1514 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1516 FT_GlyphSlot g = face->glyph;
1517 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1519 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1520 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1521 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1526 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1527 QTextEngine::ShaperFlags flags) const
1529 if (*nglyphs < len) {
1534 #if !defined(QT_NO_FONTCONFIG)
1535 extern QMutex *qt_fontdatabase_mutex();
1539 bool mirrored = flags & QTextEngine::RightToLeft;
1541 if (freetype->symbol_map) {
1542 FT_Face face = freetype->face;
1543 for ( int i = 0; i < len; ++i ) {
1544 unsigned int uc = getChar(str, i, len);
1545 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1546 if ( !glyphs->glyphs[glyph_pos] ) {
1548 #if !defined(QT_NO_FONTCONFIG)
1550 mtx = qt_fontdatabase_mutex();
1554 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1559 glyph = FT_Get_Char_Index(face, uc);
1560 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1565 FT_Set_Charmap(face, freetype->symbol_map);
1566 glyph = FT_Get_Char_Index(face, uc);
1567 FT_Set_Charmap(face, freetype->unicode_map);
1569 glyphs->glyphs[glyph_pos] = glyph;
1570 if (uc < QFreetypeFace::cmapCacheSize)
1571 freetype->cmapCache[uc] = glyph;
1576 FT_Face face = freetype->face;
1577 for (int i = 0; i < len; ++i) {
1578 unsigned int uc = getChar(str, i, len);
1580 uc = QChar::mirroredChar(uc);
1581 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1582 if (!glyphs->glyphs[glyph_pos]) {
1583 #if !defined(QT_NO_FONTCONFIG)
1585 mtx = qt_fontdatabase_mutex();
1589 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1593 glyph_t glyph = FT_Get_Char_Index(face, uc);
1594 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1598 glyphs->glyphs[glyph_pos] = glyph;
1599 if (uc < QFreetypeFace::cmapCacheSize)
1600 freetype->cmapCache[uc] = glyph;
1607 *nglyphs = glyph_pos;
1608 glyphs->numGlyphs = glyph_pos;
1610 #if !defined(QT_NO_FONTCONFIG)
1615 if (flags & QTextEngine::GlyphIndicesOnly)
1618 recalcAdvances(glyphs, flags);
1623 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1626 bool design = (default_hint_style == HintNone ||
1627 default_hint_style == HintLight ||
1628 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1629 for (int i = 0; i < glyphs->numGlyphs; i++) {
1630 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1632 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1636 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1637 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1638 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1640 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1641 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1642 glyphs->advances_y[i] = 0;
1648 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1653 glyph_metrics_t overall;
1654 // initialize with line height, we get the same behaviour on all platforms
1655 overall.y = -ascent();
1656 overall.height = ascent() + descent() + 1;
1660 for (int i = 0; i < glyphs.numGlyphs; i++) {
1661 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1665 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1668 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1669 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1670 overall.x = qMin(overall.x, x);
1671 overall.y = qMin(overall.y, y);
1672 xmax = qMax(xmax, x + g->width);
1673 ymax = qMax(ymax, y + g->height);
1674 overall.xoff += g->advance;
1676 int left = FLOOR(face->glyph->metrics.horiBearingX);
1677 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1678 int top = CEIL(face->glyph->metrics.horiBearingY);
1679 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1681 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1682 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1683 overall.x = qMin(overall.x, x);
1684 overall.y = qMin(overall.y, y);
1685 xmax = qMax(xmax, x + TRUNC(right - left));
1686 ymax = qMax(ymax, y + TRUNC(top - bottom));
1687 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1690 overall.height = qMax(overall.height, ymax - overall.y);
1691 overall.width = xmax - overall.x;
1699 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1702 glyph_metrics_t overall;
1703 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1706 g = loadGlyph(glyph, 0, Format_None, true);
1711 overall.width = g->width;
1712 overall.height = g->height;
1713 overall.xoff = g->advance;
1714 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1715 overall.xoff = overall.xoff.round();
1717 int left = FLOOR(face->glyph->metrics.horiBearingX);
1718 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1719 int top = CEIL(face->glyph->metrics.horiBearingY);
1720 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1722 overall.width = TRUNC(right-left);
1723 overall.height = TRUNC(top-bottom);
1724 overall.x = TRUNC(left);
1725 overall.y = -TRUNC(top);
1726 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1733 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1735 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1738 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1741 glyph_metrics_t overall;
1742 QGlyphSet *glyphSet = 0;
1743 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1744 // TODO move everything here to a method of its own to access glyphSets
1745 // to be shared with a new method that will replace loadTransformedGlyphSet()
1747 m.xx = FT_Fixed(matrix.m11() * 65536);
1748 m.xy = FT_Fixed(-matrix.m21() * 65536);
1749 m.yx = FT_Fixed(-matrix.m12() * 65536);
1750 m.yy = FT_Fixed(matrix.m22() * 65536);
1751 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1752 const QGlyphSet &g = transformedGlyphSets.at(i);
1753 if (g.transformationMatrix.xx == m.xx
1754 && g.transformationMatrix.xy == m.xy
1755 && g.transformationMatrix.yx == m.yx
1756 && g.transformationMatrix.yy == m.yy) {
1758 // found a match, move it to the front
1759 transformedGlyphSets.move(i, 0);
1760 glyphSet = &transformedGlyphSets[0];
1766 // don't cache more than 10 transformations
1767 if (transformedGlyphSets.count() >= 10) {
1768 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1769 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1771 transformedGlyphSets.prepend(QGlyphSet());
1773 glyphSet = &transformedGlyphSets[0];
1775 glyphSet->id = allocateServerGlyphSet();
1776 glyphSet->transformationMatrix = m;
1780 glyphSet = &defaultGlyphSet;
1782 Glyph * g = glyphSet->getGlyph(glyph);
1783 if (!g || g->format != format) {
1785 FT_Matrix m = this->matrix;
1786 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1787 freetype->matrix = m;
1788 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1794 overall.width = g->width;
1795 overall.height = g->height;
1796 overall.xoff = g->advance;
1798 int left = FLOOR(face->glyph->metrics.horiBearingX);
1799 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1800 int top = CEIL(face->glyph->metrics.horiBearingY);
1801 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1803 overall.width = TRUNC(right-left);
1804 overall.height = TRUNC(top-bottom);
1805 overall.x = TRUNC(left);
1806 overall.y = -TRUNC(top);
1807 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1814 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1818 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1820 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1823 return QFontEngine::alphaMapForGlyph(g);
1826 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1828 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1830 QVector<QRgb> colors(256);
1831 for (int i=0; i<256; ++i)
1832 colors[i] = qRgba(0, 0, 0, i);
1833 img.setColorTable(colors);
1835 QVector<QRgb> colors(2);
1836 colors[0] = qRgba(0, 0, 0, 0);
1837 colors[1] = qRgba(0, 0, 0, 255);
1838 img.setColorTable(colors);
1840 Q_ASSERT(img.bytesPerLine() == pitch);
1842 for (int y = 0; y < glyph->height; ++y)
1843 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1850 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1852 if (t.type() > QTransform::TxTranslate)
1853 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1857 GlyphFormat glyph_format = Format_A32;
1859 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1862 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1865 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1866 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1872 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1874 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1877 int QFontEngineFT::glyphCount() const
1880 FT_Face face = lockFace();
1882 count = face->num_glyphs;
1888 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1891 FT_Face face = freetype->face;
1892 if (scale == Unscaled) {
1893 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1894 freetype->xsize = face->units_per_EM << 6;
1895 freetype->ysize = face->units_per_EM << 6;
1896 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1897 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1898 freetype->xsize = xsize;
1899 freetype->ysize = ysize;
1901 if (freetype->matrix.xx != matrix.xx ||
1902 freetype->matrix.yy != matrix.yy ||
1903 freetype->matrix.xy != matrix.xy ||
1904 freetype->matrix.yx != matrix.yx) {
1905 freetype->matrix = matrix;
1906 FT_Set_Transform(face, &freetype->matrix, 0);
1912 void QFontEngineFT::unlockFace() const
1917 FT_Face QFontEngineFT::non_locked_face() const
1919 return freetype->face;
1923 QFontEngineFT::QGlyphSet::QGlyphSet()
1924 : id(0), outline_drawing(false)
1926 transformationMatrix.xx = 0x10000;
1927 transformationMatrix.yy = 0x10000;
1928 transformationMatrix.xy = 0;
1929 transformationMatrix.yx = 0;
1930 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1931 fast_glyph_count = 0;
1934 QFontEngineFT::QGlyphSet::~QGlyphSet()
1939 void QFontEngineFT::QGlyphSet::clear()
1941 if (fast_glyph_count > 0) {
1942 for (int i = 0; i < 256; ++i) {
1943 if (fast_glyph_data[i]) {
1944 delete fast_glyph_data[i];
1945 fast_glyph_data[i] = 0;
1948 fast_glyph_count = 0;
1950 qDeleteAll(glyph_data);
1954 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1956 if (useFastGlyphData(index, subPixelPosition)) {
1957 if (fast_glyph_data[index]) {
1958 delete fast_glyph_data[index];
1959 fast_glyph_data[index] = 0;
1960 if (fast_glyph_count > 0)
1964 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1968 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1970 if (useFastGlyphData(index, subPixelPosition)) {
1971 if (!fast_glyph_data[index])
1973 fast_glyph_data[index] = glyph;
1975 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1979 unsigned long QFontEngineFT::allocateServerGlyphSet()
1984 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1989 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1992 bool hsubpixel = true;
1994 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1995 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2000 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2002 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2005 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2007 freetype->ref.ref();
2009 default_load_flags = fe->default_load_flags;
2010 default_hint_style = fe->default_hint_style;
2011 antialias = fe->antialias;
2012 transform = fe->transform;
2013 embolden = fe->embolden;
2014 obliquen = fe->obliquen;
2015 subpixelType = fe->subpixelType;
2016 lcdFilterType = fe->lcdFilterType;
2017 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2018 embeddedbitmap = fe->embeddedbitmap;
2023 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2026 fontDef.pixelSize = pixelSize;
2027 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2028 if (!fe->initFromFontEngine(this)) {
2038 #endif // QT_NO_FREETYPE