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);
895 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(slot);
896 FT_Library library = qt_getFreetype();
898 info.xOff = TRUNC(ROUND(slot->advance.x));
901 uchar *glyph_buffer = 0;
902 int glyph_buffer_size = 0;
903 #if defined(QT_USE_FREETYPE_LCDFILTER)
904 bool useFreetypeRenderGlyph = false;
905 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
906 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
907 if (err == FT_Err_Ok)
908 useFreetypeRenderGlyph = true;
911 if (useFreetypeRenderGlyph) {
912 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
914 if (err != FT_Err_Ok)
915 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
917 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
919 info.height = slot->bitmap.rows / vfactor;
920 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
921 info.x = -slot->bitmap_left;
922 info.y = slot->bitmap_top;
924 glyph_buffer_size = info.width * info.height * 4;
925 glyph_buffer = new uchar[glyph_buffer_size];
928 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
929 else if (vfactor != 1)
930 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
934 int left = slot->metrics.horiBearingX;
935 int right = slot->metrics.horiBearingX + slot->metrics.width;
936 int top = slot->metrics.horiBearingY;
937 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
938 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
943 FT_Vector_Transform(&vector, &matrix);
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;
955 FT_Vector_Transform(&vector, &matrix);
956 if (l > vector.x) l = vector.x;
957 if (r < vector.x) r = vector.x;
958 if (t < vector.y) t = vector.y;
959 if (b > vector.y) b = vector.y;
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;
974 bottom = FLOOR(bottom);
977 int hpixels = TRUNC(right - left);
978 // subpixel position requires one more pixel
979 if (subPixelPosition > 0 && format != Format_Mono)
983 hpixels = hpixels*3 + 8;
984 info.width = hpixels;
985 info.height = TRUNC(top - bottom);
986 info.x = -TRUNC(left);
993 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
994 || ((uchar)(info.width) != info.width)
995 || ((uchar)(info.height) != info.height)
996 || ((signed char)(info.x) != info.x)
997 || ((signed char)(info.y) != info.y)
998 || ((signed char)(info.xOff) != info.xOff));
1001 delete [] glyph_buffer;
1005 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1006 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1007 glyph_buffer_size = pitch * info.height;
1008 glyph_buffer = new uchar[glyph_buffer_size];
1010 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1012 bitmap.rows = info.height*vfactor;
1013 bitmap.width = hpixels;
1014 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1015 if (!hsubpixel && vfactor == 1)
1016 bitmap.buffer = glyph_buffer;
1018 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1019 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1020 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1022 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1023 matrix.yy = vfactor << 16;
1024 matrix.yx = matrix.xy = 0;
1026 FT_Outline_Transform(&slot->outline, &matrix);
1027 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1028 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1030 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1031 Q_ASSERT(antialias);
1032 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1033 bool useLegacyLcdFilter = false;
1034 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1035 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1037 uchar *buffer = bitmap.buffer;
1038 if (!useLegacyLcdFilter) {
1039 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1040 buffer = convoluted;
1042 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1043 delete [] convoluted;
1044 } else if (vfactor != 1) {
1045 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1048 if (bitmap.buffer != glyph_buffer)
1049 delete [] bitmap.buffer;
1050 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1051 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1052 uchar *src = slot->bitmap.buffer;
1053 uchar *dst = glyph_buffer;
1054 int h = slot->bitmap.rows;
1055 if (format == Format_Mono) {
1056 int bytes = ((info.width + 7) & ~7) >> 3;
1058 memcpy (dst, src, bytes);
1060 src += slot->bitmap.pitch;
1065 uint *dd = (uint *)dst;
1067 for (int x = 0; x < slot->bitmap.width; x++) {
1068 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1073 src += slot->bitmap.pitch;
1075 } else if (vfactor != 1) {
1077 uint *dd = (uint *)dst;
1078 for (int x = 0; x < slot->bitmap.width; x++) {
1079 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1083 src += slot->bitmap.pitch;
1087 for (int x = 0; x < slot->bitmap.width; x++) {
1088 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1092 src += slot->bitmap.pitch;
1097 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1098 delete [] glyph_buffer;
1106 g->uploadedToServer = false;
1110 g->linearAdvance = slot->linearHoriAdvance >> 10;
1111 g->width = info.width;
1112 g->height = info.height;
1115 g->advance = info.xOff;
1118 g->data = glyph_buffer;
1120 if (uploadToServer) {
1121 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1124 set->setGlyph(glyph, subPixelPosition, g);
1129 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1135 Q_UNUSED(glyphDataSize);
1139 QFontEngine::FaceId QFontEngineFT::faceId() const
1144 QFontEngine::Properties QFontEngineFT::properties() const
1146 Properties p = freetype->properties();
1147 if (p.postscriptName.isEmpty()) {
1148 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1151 return freetype->properties();
1154 QFixed QFontEngineFT::emSquareSize() const
1156 if (FT_IS_SCALABLE(freetype->face))
1157 return freetype->face->units_per_EM;
1159 return freetype->face->size->metrics.y_ppem;
1162 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1164 return freetype->getSfntTable(tag, buffer, length);
1167 int QFontEngineFT::synthesized() const
1170 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1171 s = SynthesizedItalic;
1172 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1173 s |= SynthesizedBold;
1174 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1175 s |= SynthesizedStretch;
1179 QFixed QFontEngineFT::ascent() const
1181 return QFixed::fromFixed(metrics.ascender);
1184 QFixed QFontEngineFT::descent() const
1186 // subtract a pixel to work around QFontMetrics's built-in + 1
1187 return QFixed::fromFixed(-metrics.descender - 64);
1190 QFixed QFontEngineFT::leading() const
1192 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1195 QFixed QFontEngineFT::xHeight() const
1197 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1198 if (os2 && os2->sxHeight) {
1200 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1204 return QFontEngine::xHeight();
1207 QFixed QFontEngineFT::averageCharWidth() const
1209 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1210 if (os2 && os2->xAvgCharWidth) {
1212 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1216 return QFontEngine::averageCharWidth();
1219 qreal QFontEngineFT::maxCharWidth() const
1221 return metrics.max_advance >> 6;
1224 static const ushort char_table[] = {
1245 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1248 qreal QFontEngineFT::minLeftBearing() const
1250 if (lbearing == SHRT_MIN)
1251 (void) minRightBearing(); // calculates both
1252 return lbearing.toReal();
1255 qreal QFontEngineFT::minRightBearing() const
1257 if (rbearing == SHRT_MIN) {
1258 lbearing = rbearing = 0;
1259 const QChar *ch = (const QChar *)(const void*)char_table;
1260 QGlyphLayoutArray<char_table_entries> glyphs;
1261 int ng = char_table_entries;
1262 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1264 if (glyphs.glyphs[ng]) {
1265 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1266 lbearing = qMin(lbearing, gi.x);
1267 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1271 return rbearing.toReal();
1274 QFixed QFontEngineFT::lineThickness() const
1276 return line_thickness;
1279 QFixed QFontEngineFT::underlinePosition() const
1281 return underline_position;
1284 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1286 if (!kerning_pairs_loaded) {
1287 kerning_pairs_loaded = true;
1289 if (freetype->face->size->metrics.x_ppem != 0) {
1290 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1292 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1297 QFontEngine::doKerning(g, flags);
1300 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1302 if (matrix.type() > QTransform::TxShear)
1305 // FT_Set_Transform only supports scalable fonts
1306 if (!FT_IS_SCALABLE(freetype->face))
1310 m.xx = FT_Fixed(matrix.m11() * 65536);
1311 m.xy = FT_Fixed(-matrix.m21() * 65536);
1312 m.yx = FT_Fixed(-matrix.m12() * 65536);
1313 m.yy = FT_Fixed(matrix.m22() * 65536);
1317 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1318 const QGlyphSet &g = transformedGlyphSets.at(i);
1319 if (g.transformationMatrix.xx == m.xx
1320 && g.transformationMatrix.xy == m.xy
1321 && g.transformationMatrix.yx == m.yx
1322 && g.transformationMatrix.yy == m.yy) {
1324 // found a match, move it to the front
1325 transformedGlyphSets.move(i, 0);
1326 gs = &transformedGlyphSets[0];
1332 // don't try to load huge fonts
1333 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1334 if (draw_as_outline)
1337 // don't cache more than 10 transformations
1338 if (transformedGlyphSets.count() >= 10) {
1339 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1340 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1342 transformedGlyphSets.prepend(QGlyphSet());
1344 gs = &transformedGlyphSets[0];
1348 gs->id = allocateServerGlyphSet();
1350 gs->transformationMatrix = m;
1351 gs->outline_drawing = draw_as_outline;
1357 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1359 int m_subPixelPositionCount = 4;
1360 if (!supportsSubPixelPositions())
1363 QFixed subPixelPosition;
1365 subPixelPosition = x - x.floor();
1366 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1367 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1369 return subPixelPosition;
1372 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1373 const QFixedPoint *positions,
1378 for (int i = 0; i < num_glyphs; ++i) {
1379 QFixed spp = subPixelPositionForX(positions[i].x);
1380 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1381 if (glyph == 0 || glyph->format != format) {
1384 FT_Matrix m = matrix;
1385 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1386 FT_Set_Transform(face, &m, 0);
1387 freetype->matrix = m;
1389 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1402 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1404 FT_Face face = lockFace(Unscaled);
1405 FT_Set_Transform(face, 0, 0);
1406 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1408 int left = face->glyph->metrics.horiBearingX;
1409 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1410 int top = face->glyph->metrics.horiBearingY;
1411 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1417 metrics->width = QFixed::fromFixed(right-left);
1418 metrics->height = QFixed::fromFixed(top-bottom);
1419 metrics->x = QFixed::fromFixed(left);
1420 metrics->y = QFixed::fromFixed(-top);
1421 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1423 if (!FT_IS_SCALABLE(freetype->face))
1424 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1426 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1428 FT_Set_Transform(face, &freetype->matrix, 0);
1432 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1434 uint ucs4 = str[i].unicode();
1435 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1437 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1442 bool QFontEngineFT::canRender(const QChar *string, int len)
1444 FT_Face face = freetype->face;
1448 for ( int i = 0; i < len; i++ ) {
1449 unsigned int uc = getChar(string, i, len);
1450 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1459 for ( int i = 0; i < len; i++ ) {
1460 unsigned int uc = getChar(string, i, len);
1461 if (!FT_Get_Char_Index(face, uc))
1468 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1470 if (!glyphs.numGlyphs)
1473 if (FT_IS_SCALABLE(freetype->face)) {
1474 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1476 QVarLengthArray<QFixedPoint> positions;
1477 QVarLengthArray<glyph_t> positioned_glyphs;
1479 matrix.translate(x, y);
1480 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1482 FT_Face face = lockFace(Unscaled);
1483 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1484 FT_UInt glyph = positioned_glyphs[gl];
1485 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1486 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1492 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1493 QPainterPath *path, QTextItem::RenderFlags)
1495 FT_Face face = lockFace(Unscaled);
1497 for (int gl = 0; gl < numGlyphs; gl++) {
1498 FT_UInt glyph = glyphs[gl];
1500 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1502 FT_GlyphSlot g = face->glyph;
1503 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1505 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1506 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1507 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1512 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1513 QTextEngine::ShaperFlags flags) const
1515 if (*nglyphs < len) {
1520 #if !defined(QT_NO_FONTCONFIG)
1521 extern QMutex *qt_fontdatabase_mutex();
1525 bool mirrored = flags & QTextEngine::RightToLeft;
1527 if (freetype->symbol_map) {
1528 FT_Face face = freetype->face;
1529 for ( int i = 0; i < len; ++i ) {
1530 unsigned int uc = getChar(str, i, len);
1531 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1532 if ( !glyphs->glyphs[glyph_pos] ) {
1534 #if !defined(QT_NO_FONTCONFIG)
1536 mtx = qt_fontdatabase_mutex();
1540 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1545 glyph = FT_Get_Char_Index(face, uc);
1546 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1551 FT_Set_Charmap(face, freetype->symbol_map);
1552 glyph = FT_Get_Char_Index(face, uc);
1553 FT_Set_Charmap(face, freetype->unicode_map);
1555 glyphs->glyphs[glyph_pos] = glyph;
1556 if (uc < QFreetypeFace::cmapCacheSize)
1557 freetype->cmapCache[uc] = glyph;
1562 FT_Face face = freetype->face;
1563 for (int i = 0; i < len; ++i) {
1564 unsigned int uc = getChar(str, i, len);
1566 uc = QChar::mirroredChar(uc);
1567 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1568 if (!glyphs->glyphs[glyph_pos]) {
1569 #if !defined(QT_NO_FONTCONFIG)
1571 mtx = qt_fontdatabase_mutex();
1575 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1579 glyph_t glyph = FT_Get_Char_Index(face, uc);
1580 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1584 glyphs->glyphs[glyph_pos] = glyph;
1585 if (uc < QFreetypeFace::cmapCacheSize)
1586 freetype->cmapCache[uc] = glyph;
1593 *nglyphs = glyph_pos;
1594 glyphs->numGlyphs = glyph_pos;
1596 #if !defined(QT_NO_FONTCONFIG)
1601 if (flags & QTextEngine::GlyphIndicesOnly)
1604 recalcAdvances(glyphs, flags);
1609 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1612 bool design = (default_hint_style == HintNone ||
1613 default_hint_style == HintLight ||
1614 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1615 for (int i = 0; i < glyphs->numGlyphs; i++) {
1616 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1618 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1622 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1623 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1624 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1626 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1627 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1628 glyphs->advances_y[i] = 0;
1634 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1639 glyph_metrics_t overall;
1640 // initialize with line height, we get the same behaviour on all platforms
1641 overall.y = -ascent();
1642 overall.height = ascent() + descent() + 1;
1646 for (int i = 0; i < glyphs.numGlyphs; i++) {
1647 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1651 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1654 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1655 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1656 overall.x = qMin(overall.x, x);
1657 overall.y = qMin(overall.y, y);
1658 xmax = qMax(xmax, x + g->width);
1659 ymax = qMax(ymax, y + g->height);
1660 overall.xoff += g->advance;
1662 int left = FLOOR(face->glyph->metrics.horiBearingX);
1663 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1664 int top = CEIL(face->glyph->metrics.horiBearingY);
1665 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1667 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1668 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1669 overall.x = qMin(overall.x, x);
1670 overall.y = qMin(overall.y, y);
1671 xmax = qMax(xmax, x + TRUNC(right - left));
1672 ymax = qMax(ymax, y + TRUNC(top - bottom));
1673 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1676 overall.height = qMax(overall.height, ymax - overall.y);
1677 overall.width = xmax - overall.x;
1685 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1688 glyph_metrics_t overall;
1689 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1692 g = loadGlyph(glyph, 0, Format_None, true);
1697 overall.width = g->width;
1698 overall.height = g->height;
1699 overall.xoff = g->advance;
1700 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1701 overall.xoff = overall.xoff.round();
1703 int left = FLOOR(face->glyph->metrics.horiBearingX);
1704 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1705 int top = CEIL(face->glyph->metrics.horiBearingY);
1706 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1708 overall.width = TRUNC(right-left);
1709 overall.height = TRUNC(top-bottom);
1710 overall.x = TRUNC(left);
1711 overall.y = -TRUNC(top);
1712 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1719 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1721 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1724 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1727 glyph_metrics_t overall;
1728 QGlyphSet *glyphSet = 0;
1729 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1730 // TODO move everything here to a method of its own to access glyphSets
1731 // to be shared with a new method that will replace loadTransformedGlyphSet()
1733 m.xx = FT_Fixed(matrix.m11() * 65536);
1734 m.xy = FT_Fixed(-matrix.m21() * 65536);
1735 m.yx = FT_Fixed(-matrix.m12() * 65536);
1736 m.yy = FT_Fixed(matrix.m22() * 65536);
1737 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1738 const QGlyphSet &g = transformedGlyphSets.at(i);
1739 if (g.transformationMatrix.xx == m.xx
1740 && g.transformationMatrix.xy == m.xy
1741 && g.transformationMatrix.yx == m.yx
1742 && g.transformationMatrix.yy == m.yy) {
1744 // found a match, move it to the front
1745 transformedGlyphSets.move(i, 0);
1746 glyphSet = &transformedGlyphSets[0];
1752 // don't cache more than 10 transformations
1753 if (transformedGlyphSets.count() >= 10) {
1754 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1755 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1757 transformedGlyphSets.prepend(QGlyphSet());
1759 glyphSet = &transformedGlyphSets[0];
1761 glyphSet->id = allocateServerGlyphSet();
1762 glyphSet->transformationMatrix = m;
1766 glyphSet = &defaultGlyphSet;
1768 Glyph * g = glyphSet->getGlyph(glyph);
1769 if (!g || g->format != format) {
1771 FT_Matrix m = this->matrix;
1772 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1773 freetype->matrix = m;
1774 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1780 overall.width = g->width;
1781 overall.height = g->height;
1782 overall.xoff = g->advance;
1784 int left = FLOOR(face->glyph->metrics.horiBearingX);
1785 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1786 int top = CEIL(face->glyph->metrics.horiBearingY);
1787 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1789 overall.width = TRUNC(right-left);
1790 overall.height = TRUNC(top-bottom);
1791 overall.x = TRUNC(left);
1792 overall.y = -TRUNC(top);
1793 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1800 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1804 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1806 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1809 return QFontEngine::alphaMapForGlyph(g);
1812 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1814 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1816 QVector<QRgb> colors(256);
1817 for (int i=0; i<256; ++i)
1818 colors[i] = qRgba(0, 0, 0, i);
1819 img.setColorTable(colors);
1821 QVector<QRgb> colors(2);
1822 colors[0] = qRgba(0, 0, 0, 0);
1823 colors[1] = qRgba(0, 0, 0, 255);
1824 img.setColorTable(colors);
1826 Q_ASSERT(img.bytesPerLine() == pitch);
1828 for (int y = 0; y < glyph->height; ++y)
1829 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1836 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1838 if (t.type() > QTransform::TxTranslate)
1839 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1843 GlyphFormat glyph_format = Format_A32;
1845 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1848 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1851 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1852 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1858 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1860 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1863 int QFontEngineFT::glyphCount() const
1866 FT_Face face = lockFace();
1868 count = face->num_glyphs;
1874 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1877 FT_Face face = freetype->face;
1878 if (scale == Unscaled) {
1879 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1880 freetype->xsize = face->units_per_EM << 6;
1881 freetype->ysize = face->units_per_EM << 6;
1882 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1883 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1884 freetype->xsize = xsize;
1885 freetype->ysize = ysize;
1887 if (freetype->matrix.xx != matrix.xx ||
1888 freetype->matrix.yy != matrix.yy ||
1889 freetype->matrix.xy != matrix.xy ||
1890 freetype->matrix.yx != matrix.yx) {
1891 freetype->matrix = matrix;
1892 FT_Set_Transform(face, &freetype->matrix, 0);
1898 void QFontEngineFT::unlockFace() const
1903 FT_Face QFontEngineFT::non_locked_face() const
1905 return freetype->face;
1909 QFontEngineFT::QGlyphSet::QGlyphSet()
1910 : id(0), outline_drawing(false)
1912 transformationMatrix.xx = 0x10000;
1913 transformationMatrix.yy = 0x10000;
1914 transformationMatrix.xy = 0;
1915 transformationMatrix.yx = 0;
1916 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1917 fast_glyph_count = 0;
1920 QFontEngineFT::QGlyphSet::~QGlyphSet()
1925 void QFontEngineFT::QGlyphSet::clear()
1927 if (fast_glyph_count > 0) {
1928 for (int i = 0; i < 256; ++i) {
1929 if (fast_glyph_data[i]) {
1930 delete fast_glyph_data[i];
1931 fast_glyph_data[i] = 0;
1934 fast_glyph_count = 0;
1936 qDeleteAll(glyph_data);
1940 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1942 if (useFastGlyphData(index, subPixelPosition)) {
1943 if (fast_glyph_data[index]) {
1944 delete fast_glyph_data[index];
1945 fast_glyph_data[index] = 0;
1946 if (fast_glyph_count > 0)
1950 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1954 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1956 if (useFastGlyphData(index, subPixelPosition)) {
1957 if (!fast_glyph_data[index])
1959 fast_glyph_data[index] = glyph;
1961 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1965 unsigned long QFontEngineFT::allocateServerGlyphSet()
1970 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1975 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1978 bool hsubpixel = true;
1980 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1981 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1986 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
1988 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1991 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1993 freetype->ref.ref();
1995 default_load_flags = fe->default_load_flags;
1996 default_hint_style = fe->default_hint_style;
1997 antialias = fe->antialias;
1998 transform = fe->transform;
1999 embolden = fe->embolden;
2000 obliquen = fe->obliquen;
2001 subpixelType = fe->subpixelType;
2002 lcdFilterType = fe->lcdFilterType;
2003 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2004 embeddedbitmap = fe->embeddedbitmap;
2009 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2012 fontDef.pixelSize = pixelSize;
2013 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2014 if (!fe->initFromFontEngine(this)) {
2024 #endif // QT_NO_FREETYPE