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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include "qmetatype.h"
44 #include "qtextstream.h"
46 #include "qfontengine_ft_p.h"
48 #ifndef QT_NO_FREETYPE
51 #include "qabstractfileengine.h"
52 #include "qthreadstorage.h"
54 #include <private/qharfbuzz_p.h>
56 #include "qfontengine_ft_p.h"
58 #include FT_FREETYPE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
84 * Freetype 2.1.7 and earlier used width/height
85 * for matching sizes in the BDF and PCF loaders.
86 * This has been fixed for 2.1.8.
88 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
89 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
90 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
92 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
93 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
96 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
97 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
98 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
100 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
103 #define FLOOR(x) ((x) & -64)
104 #define CEIL(x) (((x)+63) & -64)
105 #define TRUNC(x) ((x) >> 6)
106 #define ROUND(x) (((x)+32) & -64)
108 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
110 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
111 FT_Face face = (FT_Face)font;
112 FT_ULong ftlen = *length;
115 if ( !FT_IS_SFNT(face) )
116 return HB_Err_Invalid_Argument;
118 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
120 return (HB_Error)error;
122 return HB_Err_Invalid_Argument;
126 // -------------------------- Freetype support ------------------------------
136 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
140 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
142 QtFreetypeData *qt_getFreetypeData()
144 return theFreetypeData();
147 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
149 QtFreetypeData *qt_getFreetypeData()
151 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
153 freetypeData = new QtFreetypeData;
158 FT_Library qt_getFreetype()
160 QtFreetypeData *freetypeData = qt_getFreetypeData();
161 if (!freetypeData->library)
162 FT_Init_FreeType(&freetypeData->library);
163 return freetypeData->library;
166 int QFreetypeFace::fsType() const
169 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
171 fsType = os2->fsType;
175 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
177 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
180 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
181 return HB_Err_Invalid_SubTable;
183 *nPoints = face->glyph->outline.n_points;
187 if (point > *nPoints)
188 return HB_Err_Invalid_SubTable;
190 *xpos = face->glyph->outline.points[point].x;
191 *ypos = face->glyph->outline.points[point].y;
197 * One font file can contain more than one font (bold/italic for example)
198 * find the right one and return it.
200 * Returns the freetype face or 0 in case of an empty file or any other problems
201 * (like not being able to open the file)
203 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
204 const QByteArray &fontData)
206 if (face_id.filename.isEmpty() && fontData.isEmpty())
209 QtFreetypeData *freetypeData = qt_getFreetypeData();
210 if (!freetypeData->library)
211 FT_Init_FreeType(&freetypeData->library);
213 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
217 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
219 if (!face_id.filename.isEmpty()) {
220 QFile file(QString::fromUtf8(face_id.filename));
221 if (face_id.filename.startsWith(":qmemoryfonts/")) {
222 // from qfontdatabase.cpp
223 extern QByteArray qt_fontdata_from_index(int);
224 QByteArray idx = face_id.filename;
225 idx.remove(0, 14); // remove ':qmemoryfonts/'
227 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
229 newFreetype->fontData = QByteArray();
230 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
231 if (!file.open(QIODevice::ReadOnly)) {
234 newFreetype->fontData = file.readAll();
237 newFreetype->fontData = fontData;
239 if (!newFreetype->fontData.isEmpty()) {
240 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
243 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
246 newFreetype->face = face;
248 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
249 Q_CHECK_PTR(newFreetype->hbFace);
250 newFreetype->ref = 1;
251 newFreetype->xsize = 0;
252 newFreetype->ysize = 0;
253 newFreetype->matrix.xx = 0x10000;
254 newFreetype->matrix.yy = 0x10000;
255 newFreetype->matrix.xy = 0;
256 newFreetype->matrix.yx = 0;
257 newFreetype->unicode_map = 0;
258 newFreetype->symbol_map = 0;
259 #ifndef QT_NO_FONTCONFIG
260 newFreetype->charset = 0;
263 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
265 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
266 FT_CharMap cm = newFreetype->face->charmaps[i];
267 switch(cm->encoding) {
268 case FT_ENCODING_UNICODE:
269 newFreetype->unicode_map = cm;
271 case FT_ENCODING_APPLE_ROMAN:
272 case FT_ENCODING_ADOBE_LATIN_1:
273 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
274 newFreetype->unicode_map = cm;
276 case FT_ENCODING_ADOBE_CUSTOM:
277 case FT_ENCODING_MS_SYMBOL:
278 if (!newFreetype->symbol_map)
279 newFreetype->symbol_map = cm;
286 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
287 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
290 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
291 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
292 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
293 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
294 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
296 for (int i = 0; i < 256; i += 8)
297 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
298 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
299 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
300 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
301 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
304 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
306 freetypeData->faces.insert(face_id, newFreetype.data());
308 newFreetype.take()->release(face_id);
309 // we could return null in principle instead of throwing
312 freetype = newFreetype.take();
317 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
319 QtFreetypeData *freetypeData = qt_getFreetypeData();
323 #ifndef QT_NO_FONTCONFIG
325 FcCharSetDestroy(charset);
327 if(freetypeData->faces.contains(face_id))
328 freetypeData->faces.take(face_id);
331 if (freetypeData->faces.isEmpty()) {
332 FT_Done_FreeType(freetypeData->library);
333 freetypeData->library = 0;
338 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
340 *ysize = qRound(fontDef.pixelSize * 64);
341 *xsize = *ysize * fontDef.stretch / 100;
342 *outline_drawing = false;
345 * Bitmap only faces must match exactly, so find the closest
346 * one (height dominant search)
348 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
350 for (int i = 1; i < face->num_fixed_sizes; i++) {
351 if (qAbs(*ysize - Y_SIZE(face,i)) <
352 qAbs (*ysize - Y_SIZE(face, best)) ||
353 (qAbs (*ysize - Y_SIZE(face, i)) ==
354 qAbs (*ysize - Y_SIZE(face, best)) &&
355 qAbs (*xsize - X_SIZE(face, i)) <
356 qAbs (*xsize - X_SIZE(face, best)))) {
360 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
361 *xsize = X_SIZE(face, best);
362 *ysize = Y_SIZE(face, best);
365 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
366 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
367 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
368 if (err && face->num_fixed_sizes == 1)
369 err = 0; //even more of a workaround...
376 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
380 QFontEngine::Properties QFreetypeFace::properties() const
382 QFontEngine::Properties p;
383 p.postscriptName = FT_Get_Postscript_Name(face);
384 PS_FontInfoRec font_info;
385 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
386 p.copyright = font_info.notice;
387 if (FT_IS_SCALABLE(face)) {
388 p.ascent = face->ascender;
389 p.descent = -face->descender;
390 p.leading = face->height - face->ascender + face->descender;
391 p.emSquare = face->units_per_EM;
392 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
393 face->bbox.xMax - face->bbox.xMin,
394 face->bbox.yMax - face->bbox.yMin);
396 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
397 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
398 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
399 p.emSquare = face->size->metrics.y_ppem;
400 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
401 p.boundingBox = QRectF(0, -p.ascent.toReal(),
402 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
405 p.capHeight = p.ascent;
406 p.lineWidth = face->underline_thickness;
410 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
413 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
414 if (FT_IS_SFNT(face)) {
415 FT_ULong len = *length;
416 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
423 /* Some fonts (such as MingLiu rely on hinting to scale different
424 components to their correct sizes. While this is really broken (it
425 should be done in the component glyph itself, not the hinter) we
426 will have to live with it.
428 This means we can not use FT_LOAD_NO_HINTING to get the glyph
429 outline. All we can do is to load the unscaled glyph and scale it
430 down manually when required.
432 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
434 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
435 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
436 FT_Vector *p = g->outline.points;
437 const FT_Vector *e = p + g->outline.n_points;
439 p->x = FT_MulFix(p->x, x_scale);
440 p->y = FT_MulFix(p->y, y_scale);
445 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
447 const qreal factor = 1/64.;
448 scaleOutline(face, g, x_scale, y_scale);
450 QPointF cp = point.toPointF();
452 // convert the outline to a painter path
454 for (int j = 0; j < g->outline.n_contours; ++j) {
455 int last_point = g->outline.contours[j];
456 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
457 if(!(g->outline.tags[i] & 1)) {
458 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
461 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
462 // qDebug("first point at %f %f", start.x(), start.y());
468 while (i < last_point) {
470 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
471 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
473 switch (g->outline.tags[i] & 3) {
475 // cubic bezier element
478 c[3] = (c[3] + c[2])/2;
482 // quadratic bezier element
485 c[3] = (c[1] + c[2])/2;
486 c[2] = (2*c[1] + c[3])/3;
487 c[1] = (2*c[1] + c[0])/3;
493 // qDebug() << "lineTo" << c[1];
500 c[2] = (2*c[1] + c[3])/3;
501 c[1] = (2*c[1] + c[0])/3;
505 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
506 path->cubicTo(c[1], c[2], c[3]);
511 // qDebug() << "closeSubpath";
512 path->closeSubpath();
516 c[2] = (2*c[1] + c[3])/3;
517 c[1] = (2*c[1] + c[0])/3;
519 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
520 path->cubicTo(c[1], c[2], c[3]);
526 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
528 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
530 if (slot->format != FT_GLYPH_FORMAT_BITMAP
531 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
534 QPointF cp = point.toPointF();
535 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
536 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
539 QFontEngineFT::Glyph::~Glyph()
544 static const uint subpixel_filter[3][3] = {
550 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
554 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
555 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
556 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
557 res = (mid << 24) + (high << 16) + (mid << 8) + low;
560 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
565 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
568 const int offs = bgr ? -1 : 1;
569 const int w = width * 3;
572 for (int x = 0; x < w; x += 3) {
573 uint red = src[x+1-offs];
574 uint green = src[x+1];
575 uint blue = src[x+1+offs];
576 *dd = filterPixel(red, green, blue, legacyFilter);
584 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
587 const int offs = bgr ? -src_pitch : src_pitch;
589 for (int x = 0; x < width; x++) {
590 uint red = src[x+src_pitch-offs];
591 uint green = src[x+src_pitch];
592 uint blue = src[x+src_pitch+offs];
593 dst[x] = filterPixel(red, green, blue, legacyFilter);
600 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
602 // convolute the bitmap with a triangle filter to get rid of color fringes
603 // If we take account for a gamma value of 2, we end up with
604 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
605 // as this nicely sums up to 16 :)
610 for (int x = 2; x < width - 2; ++x) {
611 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
612 dst[x] = (uchar) (sum >> 4);
614 dst[width - 2] = dst[width - 1] = 0;
620 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
628 kerning_pairs_loaded = false;
633 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
634 default_hint_style = HintNone;
635 subpixelType = Subpixel_None;
637 #if defined(FT_LCD_FILTER_H)
638 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
640 defaultFormat = Format_None;
641 canUploadGlyphsToServer = false;
642 embeddedbitmap = false;
645 QFontEngineFT::~QFontEngineFT()
648 freetype->release(face_id);
649 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
652 void QFontEngineFT::freeGlyphSets()
654 freeServerGlyphSet(defaultGlyphSet.id);
655 for (int i = 0; i < transformedGlyphSets.count(); ++i)
656 freeServerGlyphSet(transformedGlyphSets.at(i).id);
659 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
660 const QByteArray &fontData)
662 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
665 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
666 QFreetypeFace *freetypeFace)
668 freetype = freetypeFace;
674 defaultFormat = format;
675 this->antialias = antialias;
678 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
679 else if (format == Format_A8)
680 glyphFormat = QFontEngineGlyphCache::Raster_A8;
681 else if (format == Format_A32)
682 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
686 symbol = freetype->symbol_map != 0;
687 PS_FontInfoRec psrec;
688 // don't assume that type1 fonts are symbol fonts by default
689 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
690 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
693 freetype->hbFace->isSymbolFont = symbol;
695 lbearing = rbearing = SHRT_MIN;
696 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
698 FT_Face face = lockFace();
700 if (FT_IS_SCALABLE(face)) {
701 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
703 matrix.xy = 0x10000*3/10;
704 FT_Set_Transform(face, &matrix, 0);
705 freetype->matrix = matrix;
709 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
712 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
713 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
715 // copied from QFontEngineQPF
717 int score = fontDef.weight * fontDef.pixelSize;
718 line_thickness = score / 700;
719 // looks better with thicker line for small pointsizes
720 if (line_thickness < 2 && score >= 1050)
722 underline_position = ((line_thickness * 2) + 3) / 6;
724 if (line_thickness < 1)
727 hbFont.x_ppem = face->size->metrics.x_ppem;
728 hbFont.y_ppem = face->size->metrics.y_ppem;
729 hbFont.x_scale = face->size->metrics.x_scale;
730 hbFont.y_scale = face->size->metrics.y_scale;
732 hbFace = freetype->hbFace;
734 metrics = face->size->metrics;
736 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
738 TrueType fonts with embedded bitmaps may have a bitmap font specific
739 ascent/descent in the EBLC table. There is no direct public API
740 to extract those values. The only way we've found is to trick freetype
741 into thinking that it's not a scalable font in FT_SelectSize so that
742 the metrics are retrieved from the bitmap strikes.
744 if (FT_IS_SCALABLE(face)) {
745 for (int i = 0; i < face->num_fixed_sizes; ++i) {
746 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
747 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
749 FT_Select_Size(face, i);
750 metrics.ascender = face->size->metrics.ascender;
751 metrics.descender = face->size->metrics.descender;
752 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
754 face->face_flags |= FT_FACE_FLAG_SCALABLE;
763 fsType = freetype->fsType();
764 defaultGlyphSet.id = allocateServerGlyphSet();
768 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
770 default_hint_style = style;
773 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
774 bool &hsubpixel, int &vfactor) const
776 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
777 int load_target = default_hint_style == HintLight
778 ? FT_LOAD_TARGET_LIGHT
779 : FT_LOAD_TARGET_NORMAL;
781 if (format == Format_Mono) {
782 load_target = FT_LOAD_TARGET_MONO;
783 } else if (format == Format_A32) {
784 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
785 if (default_hint_style == HintFull)
786 load_target = FT_LOAD_TARGET_LCD;
788 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
789 if (default_hint_style == HintFull)
790 load_target = FT_LOAD_TARGET_LCD_V;
795 if (set && set->outline_drawing)
796 load_flags = FT_LOAD_NO_BITMAP;
798 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics))
799 load_flags |= FT_LOAD_NO_HINTING;
801 load_flags |= load_target;
806 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const
808 Glyph *g = set->getGlyph(glyph);
809 if (g && g->format == format)
812 bool hsubpixel = false;
814 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
816 // apply our matrix to this, but note that the metrics will not be affected by this.
817 FT_Face face = lockFace();
818 FT_Matrix matrix = this->matrix;
819 FT_Matrix_Multiply(&set->transformationMatrix, &matrix);
820 FT_Set_Transform(face, &matrix, 0);
821 freetype->matrix = matrix;
823 bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0;
825 load_flags |= FT_LOAD_NO_BITMAP;
827 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
828 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
829 load_flags &= ~FT_LOAD_NO_BITMAP;
830 err = FT_Load_Glyph(face, glyph, load_flags);
832 if (err == FT_Err_Too_Few_Arguments) {
833 // this is an error in the bytecode interpreter, just try to run without it
834 load_flags |= FT_LOAD_FORCE_AUTOHINT;
835 err = FT_Load_Glyph(face, glyph, load_flags);
837 if (err != FT_Err_Ok)
838 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
841 if (set->outline_drawing)
846 g->uploadedToServer = false;
850 FT_GlyphSlot slot = face->glyph;
851 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
852 int left = slot->metrics.horiBearingX;
853 int right = slot->metrics.horiBearingX + slot->metrics.width;
854 int top = slot->metrics.horiBearingY;
855 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
856 if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics
861 FT_Vector_Transform(&vector, &matrix);
866 FT_Vector_Transform(&vector, &matrix);
867 if (l > vector.x) l = vector.x;
868 if (r < vector.x) r = vector.x;
869 if (t < vector.y) t = vector.y;
870 if (b > vector.y) b = vector.y;
873 FT_Vector_Transform(&vector, &matrix);
874 if (l > vector.x) l = vector.x;
875 if (r < vector.x) r = vector.x;
876 if (t < vector.y) t = vector.y;
877 if (b > vector.y) b = vector.y;
880 FT_Vector_Transform(&vector, &matrix);
881 if (l > vector.x) l = vector.x;
882 if (r < vector.x) r = vector.x;
883 if (t < vector.y) t = vector.y;
884 if (b > vector.y) b = vector.y;
892 bottom = FLOOR(bottom);
895 g->linearAdvance = face->glyph->linearHoriAdvance >> 10;
896 g->width = TRUNC(right-left);
897 g->height = TRUNC(top-bottom);
900 g->advance = TRUNC(ROUND(face->glyph->advance.x));
901 g->format = Format_None;
906 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
907 QFixed subPixelPosition,
909 bool fetchMetricsOnly) const
911 // Q_ASSERT(freetype->lock == 1);
913 bool uploadToServer = false;
914 if (format == Format_None) {
915 if (defaultFormat != Format_None) {
916 format = defaultFormat;
917 if (canUploadGlyphsToServer)
918 uploadToServer = true;
920 format = Format_Mono;
924 Glyph *g = set->getGlyph(glyph, subPixelPosition);
925 if (g && g->format == format) {
926 if (uploadToServer && !g->uploadedToServer) {
927 set->setGlyph(glyph, subPixelPosition, 0);
935 QFontEngineFT::GlyphInfo info;
937 Q_ASSERT(format != Format_None);
938 bool hsubpixel = false;
940 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
943 if (format != Format_Mono && !embeddedbitmap)
944 load_flags |= FT_LOAD_NO_BITMAP;
947 FT_Matrix matrix = freetype->matrix;
948 bool transform = matrix.xx != 0x10000
949 || matrix.yy != 0x10000
954 load_flags |= FT_LOAD_NO_BITMAP;
956 FT_Face face = freetype->face;
959 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
961 FT_Set_Transform(face, &freetype->matrix, &v);
963 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
964 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
965 load_flags &= ~FT_LOAD_NO_BITMAP;
966 err = FT_Load_Glyph(face, glyph, load_flags);
968 if (err == FT_Err_Too_Few_Arguments) {
969 // this is an error in the bytecode interpreter, just try to run without it
970 load_flags |= FT_LOAD_FORCE_AUTOHINT;
971 err = FT_Load_Glyph(face, glyph, load_flags);
973 if (err != FT_Err_Ok)
974 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
976 if (set->outline_drawing && fetchMetricsOnly)
979 FT_GlyphSlot slot = face->glyph;
980 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
981 FT_Library library = qt_getFreetype();
983 info.xOff = TRUNC(ROUND(slot->advance.x));
986 uchar *glyph_buffer = 0;
987 int glyph_buffer_size = 0;
988 #if defined(QT_USE_FREETYPE_LCDFILTER)
989 bool useFreetypeRenderGlyph = false;
990 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
991 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
992 if (err == FT_Err_Ok)
993 useFreetypeRenderGlyph = true;
996 if (useFreetypeRenderGlyph) {
997 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
999 if (err != FT_Err_Ok)
1000 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1002 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
1004 info.height = slot->bitmap.rows / vfactor;
1005 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
1006 info.x = -slot->bitmap_left;
1007 info.y = slot->bitmap_top;
1009 glyph_buffer_size = info.width * info.height * 4;
1010 glyph_buffer = new uchar[glyph_buffer_size];
1013 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
1014 else if (vfactor != 1)
1015 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
1019 int left = slot->metrics.horiBearingX;
1020 int right = slot->metrics.horiBearingX + slot->metrics.width;
1021 int top = slot->metrics.horiBearingY;
1022 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
1023 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
1028 FT_Vector_Transform(&vector, &matrix);
1033 FT_Vector_Transform(&vector, &matrix);
1034 if (l > vector.x) l = vector.x;
1035 if (r < vector.x) r = vector.x;
1036 if (t < vector.y) t = vector.y;
1037 if (b > vector.y) b = vector.y;
1040 FT_Vector_Transform(&vector, &matrix);
1041 if (l > vector.x) l = vector.x;
1042 if (r < vector.x) r = vector.x;
1043 if (t < vector.y) t = vector.y;
1044 if (b > vector.y) b = vector.y;
1047 FT_Vector_Transform(&vector, &matrix);
1048 if (l > vector.x) l = vector.x;
1049 if (r < vector.x) r = vector.x;
1050 if (t < vector.y) t = vector.y;
1051 if (b > vector.y) b = vector.y;
1058 right = CEIL(right);
1059 bottom = FLOOR(bottom);
1062 int hpixels = TRUNC(right - left);
1063 // subpixel position requires one more pixel
1064 if (subPixelPosition > 0 && format != Format_Mono)
1068 hpixels = hpixels*3 + 8;
1069 info.width = hpixels;
1070 info.height = TRUNC(top - bottom);
1071 info.x = -TRUNC(left);
1072 info.y = TRUNC(top);
1078 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1079 || ((uchar)(info.width) != info.width)
1080 || ((uchar)(info.height) != info.height)
1081 || ((signed char)(info.x) != info.x)
1082 || ((signed char)(info.y) != info.y)
1083 || ((signed char)(info.xOff) != info.xOff));
1086 delete [] glyph_buffer;
1090 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1091 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1092 glyph_buffer_size = pitch * info.height;
1093 glyph_buffer = new uchar[glyph_buffer_size];
1095 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1097 bitmap.rows = info.height*vfactor;
1098 bitmap.width = hpixels;
1099 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1100 if (!hsubpixel && vfactor == 1)
1101 bitmap.buffer = glyph_buffer;
1103 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1104 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1105 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1107 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1108 matrix.yy = vfactor << 16;
1109 matrix.yx = matrix.xy = 0;
1111 FT_Outline_Transform(&slot->outline, &matrix);
1112 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1113 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1115 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1116 Q_ASSERT(antialias);
1117 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1118 bool useLegacyLcdFilter = false;
1119 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1120 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1122 uchar *buffer = bitmap.buffer;
1123 if (!useLegacyLcdFilter) {
1124 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1125 buffer = convoluted;
1127 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1128 delete [] convoluted;
1129 } else if (vfactor != 1) {
1130 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1133 if (bitmap.buffer != glyph_buffer)
1134 delete [] bitmap.buffer;
1135 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1136 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1137 uchar *src = slot->bitmap.buffer;
1138 uchar *dst = glyph_buffer;
1139 int h = slot->bitmap.rows;
1140 if (format == Format_Mono) {
1141 int bytes = ((info.width + 7) & ~7) >> 3;
1143 memcpy (dst, src, bytes);
1145 src += slot->bitmap.pitch;
1150 uint *dd = (uint *)dst;
1152 for (int x = 0; x < slot->bitmap.width; x++) {
1153 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1158 src += slot->bitmap.pitch;
1160 } else if (vfactor != 1) {
1162 uint *dd = (uint *)dst;
1163 for (int x = 0; x < slot->bitmap.width; x++) {
1164 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1168 src += slot->bitmap.pitch;
1172 for (int x = 0; x < slot->bitmap.width; x++) {
1173 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1177 src += slot->bitmap.pitch;
1182 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1183 delete [] glyph_buffer;
1191 g->uploadedToServer = false;
1195 g->linearAdvance = slot->linearHoriAdvance >> 10;
1196 g->width = info.width;
1197 g->height = info.height;
1200 g->advance = info.xOff;
1203 g->data = glyph_buffer;
1205 if (uploadToServer) {
1206 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1209 set->setGlyph(glyph, subPixelPosition, g);
1214 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1220 Q_UNUSED(glyphDataSize);
1224 QFontEngine::FaceId QFontEngineFT::faceId() const
1229 QFontEngine::Properties QFontEngineFT::properties() const
1231 Properties p = freetype->properties();
1232 if (p.postscriptName.isEmpty()) {
1233 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1236 return freetype->properties();
1239 QFixed QFontEngineFT::emSquareSize() const
1241 if (FT_IS_SCALABLE(freetype->face))
1242 return freetype->face->units_per_EM;
1244 return freetype->face->size->metrics.y_ppem;
1247 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1249 return freetype->getSfntTable(tag, buffer, length);
1252 int QFontEngineFT::synthesized() const
1255 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1256 s = SynthesizedItalic;
1257 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1258 s |= SynthesizedBold;
1259 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1260 s |= SynthesizedStretch;
1264 QFixed QFontEngineFT::ascent() const
1266 return QFixed::fromFixed(metrics.ascender);
1269 QFixed QFontEngineFT::descent() const
1271 // subtract a pixel to work around QFontMetrics's built-in + 1
1272 return QFixed::fromFixed(-metrics.descender - 64);
1275 QFixed QFontEngineFT::leading() const
1277 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1280 QFixed QFontEngineFT::xHeight() const
1282 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1283 if (os2 && os2->sxHeight) {
1285 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1289 return QFontEngine::xHeight();
1292 QFixed QFontEngineFT::averageCharWidth() const
1294 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1295 if (os2 && os2->xAvgCharWidth) {
1297 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1301 return QFontEngine::averageCharWidth();
1304 qreal QFontEngineFT::maxCharWidth() const
1306 return metrics.max_advance >> 6;
1309 static const ushort char_table[] = {
1330 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1333 qreal QFontEngineFT::minLeftBearing() const
1335 if (lbearing == SHRT_MIN)
1336 (void) minRightBearing(); // calculates both
1337 return lbearing.toReal();
1340 qreal QFontEngineFT::minRightBearing() const
1342 if (rbearing == SHRT_MIN) {
1343 lbearing = rbearing = 0;
1344 const QChar *ch = (const QChar *)(const void*)char_table;
1345 QGlyphLayoutArray<char_table_entries> glyphs;
1346 int ng = char_table_entries;
1347 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1349 if (glyphs.glyphs[ng]) {
1350 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1351 lbearing = qMin(lbearing, gi.x);
1352 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1356 return rbearing.toReal();
1359 QFixed QFontEngineFT::lineThickness() const
1361 return line_thickness;
1364 QFixed QFontEngineFT::underlinePosition() const
1366 return underline_position;
1369 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1371 if (!kerning_pairs_loaded) {
1372 kerning_pairs_loaded = true;
1374 if (freetype->face->size->metrics.x_ppem != 0) {
1375 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1377 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1382 QFontEngine::doKerning(g, flags);
1385 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1387 if (matrix.type() > QTransform::TxShear)
1390 // FT_Set_Transform only supports scalable fonts
1391 if (!FT_IS_SCALABLE(freetype->face))
1395 m.xx = FT_Fixed(matrix.m11() * 65536);
1396 m.xy = FT_Fixed(-matrix.m21() * 65536);
1397 m.yx = FT_Fixed(-matrix.m12() * 65536);
1398 m.yy = FT_Fixed(matrix.m22() * 65536);
1402 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1403 const QGlyphSet &g = transformedGlyphSets.at(i);
1404 if (g.transformationMatrix.xx == m.xx
1405 && g.transformationMatrix.xy == m.xy
1406 && g.transformationMatrix.yx == m.yx
1407 && g.transformationMatrix.yy == m.yy) {
1409 // found a match, move it to the front
1410 transformedGlyphSets.move(i, 0);
1411 gs = &transformedGlyphSets[0];
1417 // don't try to load huge fonts
1418 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1419 if (draw_as_outline)
1422 // don't cache more than 10 transformations
1423 if (transformedGlyphSets.count() >= 10) {
1424 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1425 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1427 transformedGlyphSets.prepend(QGlyphSet());
1429 gs = &transformedGlyphSets[0];
1433 gs->id = allocateServerGlyphSet();
1435 gs->transformationMatrix = m;
1436 gs->outline_drawing = draw_as_outline;
1442 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1444 int m_subPixelPositionCount = 4;
1445 if (!supportsSubPixelPositions())
1448 QFixed subPixelPosition;
1450 subPixelPosition = x - x.floor();
1451 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1452 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1454 return subPixelPosition;
1457 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1458 const QFixedPoint *positions,
1463 for (int i = 0; i < num_glyphs; ++i) {
1464 QFixed spp = subPixelPositionForX(positions[i].x);
1465 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1466 if (glyph == 0 || glyph->format != format) {
1469 FT_Matrix m = matrix;
1470 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1471 FT_Set_Transform(face, &m, 0);
1472 freetype->matrix = m;
1474 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1487 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1489 FT_Face face = lockFace(Unscaled);
1490 FT_Set_Transform(face, 0, 0);
1491 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1493 int left = face->glyph->metrics.horiBearingX;
1494 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1495 int top = face->glyph->metrics.horiBearingY;
1496 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1502 metrics->width = QFixed::fromFixed(right-left);
1503 metrics->height = QFixed::fromFixed(top-bottom);
1504 metrics->x = QFixed::fromFixed(left);
1505 metrics->y = QFixed::fromFixed(-top);
1506 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1508 if (!FT_IS_SCALABLE(freetype->face))
1509 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1511 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1513 FT_Set_Transform(face, &freetype->matrix, 0);
1517 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1519 unsigned int uc = str[i].unicode();
1520 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
1521 uint low = str[i+1].unicode();
1522 if (low >= 0xdc00 && low < 0xe000) {
1523 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
1530 bool QFontEngineFT::canRender(const QChar *string, int len)
1532 FT_Face face = freetype->face;
1536 for ( int i = 0; i < len; i++ ) {
1537 unsigned int uc = getChar(string, i, len);
1538 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1547 for ( int i = 0; i < len; i++ ) {
1548 unsigned int uc = getChar(string, i, len);
1549 if (!FT_Get_Char_Index(face, uc))
1556 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1558 if (!glyphs.numGlyphs)
1561 if (FT_IS_SCALABLE(freetype->face)) {
1562 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1564 QVarLengthArray<QFixedPoint> positions;
1565 QVarLengthArray<glyph_t> positioned_glyphs;
1567 matrix.translate(x, y);
1568 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1570 FT_Face face = lockFace(Unscaled);
1571 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1572 FT_UInt glyph = positioned_glyphs[gl];
1573 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1574 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1580 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1581 QPainterPath *path, QTextItem::RenderFlags)
1583 FT_Face face = lockFace(Unscaled);
1585 for (int gl = 0; gl < numGlyphs; gl++) {
1586 FT_UInt glyph = glyphs[gl];
1588 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1590 FT_GlyphSlot g = face->glyph;
1591 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1593 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1598 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1599 QTextEngine::ShaperFlags flags) const
1601 if (*nglyphs < len) {
1606 #if !defined(QT_NO_FONTCONFIG)
1607 extern QMutex *qt_fontdatabase_mutex();
1611 bool mirrored = flags & QTextEngine::RightToLeft;
1613 if (freetype->symbol_map) {
1614 FT_Face face = freetype->face;
1615 for ( int i = 0; i < len; ++i ) {
1616 unsigned int uc = getChar(str, i, len);
1617 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1618 if ( !glyphs->glyphs[glyph_pos] ) {
1620 #if !defined(QT_NO_FONTCONFIG)
1622 mtx = qt_fontdatabase_mutex();
1626 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1631 glyph = FT_Get_Char_Index(face, uc);
1632 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1637 FT_Set_Charmap(face, freetype->symbol_map);
1638 glyph = FT_Get_Char_Index(face, uc);
1639 FT_Set_Charmap(face, freetype->unicode_map);
1641 glyphs->glyphs[glyph_pos] = glyph;
1642 if (uc < QFreetypeFace::cmapCacheSize)
1643 freetype->cmapCache[uc] = glyph;
1648 FT_Face face = freetype->face;
1649 for (int i = 0; i < len; ++i) {
1650 unsigned int uc = getChar(str, i, len);
1652 uc = QChar::mirroredChar(uc);
1653 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1654 if (!glyphs->glyphs[glyph_pos]) {
1655 #if !defined(QT_NO_FONTCONFIG)
1657 mtx = qt_fontdatabase_mutex();
1661 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1665 glyph_t glyph = FT_Get_Char_Index(face, uc);
1666 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1670 glyphs->glyphs[glyph_pos] = glyph;
1671 if (uc < QFreetypeFace::cmapCacheSize)
1672 freetype->cmapCache[uc] = glyph;
1679 *nglyphs = glyph_pos;
1680 glyphs->numGlyphs = glyph_pos;
1682 #if !defined(QT_NO_FONTCONFIG)
1687 if (flags & QTextEngine::GlyphIndicesOnly)
1690 recalcAdvances(glyphs, flags);
1695 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1698 bool design = (default_hint_style == HintNone ||
1699 default_hint_style == HintLight ||
1700 (flags & HB_ShaperFlag_UseDesignMetrics));
1701 for (int i = 0; i < glyphs->numGlyphs; i++) {
1702 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1704 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1708 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1709 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1710 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1712 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1713 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1714 glyphs->advances_y[i] = 0;
1720 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1725 glyph_metrics_t overall;
1726 // initialize with line height, we get the same behaviour on all platforms
1727 overall.y = -ascent();
1728 overall.height = ascent() + descent() + 1;
1732 for (int i = 0; i < glyphs.numGlyphs; i++) {
1733 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1737 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1740 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1741 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1742 overall.x = qMin(overall.x, x);
1743 overall.y = qMin(overall.y, y);
1744 xmax = qMax(xmax, x + g->width);
1745 ymax = qMax(ymax, y + g->height);
1746 overall.xoff += qRound(g->advance);
1748 int left = FLOOR(face->glyph->metrics.horiBearingX);
1749 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1750 int top = CEIL(face->glyph->metrics.horiBearingY);
1751 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1753 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1754 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1755 overall.x = qMin(overall.x, x);
1756 overall.y = qMin(overall.y, y);
1757 xmax = qMax(xmax, x + TRUNC(right - left));
1758 ymax = qMax(ymax, y + TRUNC(top - bottom));
1759 overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1762 overall.height = qMax(overall.height, ymax - overall.y);
1763 overall.width = xmax - overall.x;
1771 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1774 glyph_metrics_t overall;
1775 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1778 g = loadGlyph(glyph, 0, Format_None, true);
1783 overall.width = g->width;
1784 overall.height = g->height;
1785 overall.xoff = g->advance;
1786 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1787 overall.xoff = overall.xoff.round();
1789 int left = FLOOR(face->glyph->metrics.horiBearingX);
1790 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1791 int top = CEIL(face->glyph->metrics.horiBearingY);
1792 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1794 overall.width = TRUNC(right-left);
1795 overall.height = TRUNC(top-bottom);
1796 overall.x = TRUNC(left);
1797 overall.y = -TRUNC(top);
1798 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1805 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1807 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1810 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1813 glyph_metrics_t overall;
1814 QGlyphSet *glyphSet = 0;
1815 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1816 // TODO move everything here to a method of its own to access glyphSets
1817 // to be shared with a new method that will replace loadTransformedGlyphSet()
1819 m.xx = FT_Fixed(matrix.m11() * 65536);
1820 m.xy = FT_Fixed(-matrix.m21() * 65536);
1821 m.yx = FT_Fixed(-matrix.m12() * 65536);
1822 m.yy = FT_Fixed(matrix.m22() * 65536);
1823 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1824 const QGlyphSet &g = transformedGlyphSets.at(i);
1825 if (g.transformationMatrix.xx == m.xx
1826 && g.transformationMatrix.xy == m.xy
1827 && g.transformationMatrix.yx == m.yx
1828 && g.transformationMatrix.yy == m.yy) {
1830 // found a match, move it to the front
1831 transformedGlyphSets.move(i, 0);
1832 glyphSet = &transformedGlyphSets[0];
1838 // don't cache more than 10 transformations
1839 if (transformedGlyphSets.count() >= 10) {
1840 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1841 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1843 transformedGlyphSets.prepend(QGlyphSet());
1845 glyphSet = &transformedGlyphSets[0];
1847 glyphSet->id = allocateServerGlyphSet();
1848 glyphSet->transformationMatrix = m;
1852 glyphSet = &defaultGlyphSet;
1854 Glyph * g = glyphSet->getGlyph(glyph);
1855 if (!g || g->format != format) {
1857 FT_Matrix m = this->matrix;
1858 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1859 freetype->matrix = m;
1860 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1866 overall.width = g->width;
1867 overall.height = g->height;
1868 overall.xoff = g->advance;
1870 int left = FLOOR(face->glyph->metrics.horiBearingX);
1871 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1872 int top = CEIL(face->glyph->metrics.horiBearingY);
1873 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1875 overall.width = TRUNC(right-left);
1876 overall.height = TRUNC(top-bottom);
1877 overall.x = TRUNC(left);
1878 overall.y = -TRUNC(top);
1879 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1886 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1890 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1892 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1895 return QFontEngine::alphaMapForGlyph(g);
1898 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1900 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1902 QVector<QRgb> colors(256);
1903 for (int i=0; i<256; ++i)
1904 colors[i] = qRgba(0, 0, 0, i);
1905 img.setColorTable(colors);
1907 QVector<QRgb> colors(2);
1908 colors[0] = qRgba(0, 0, 0, 0);
1909 colors[1] = qRgba(0, 0, 0, 255);
1910 img.setColorTable(colors);
1912 Q_ASSERT(img.bytesPerLine() == pitch);
1914 for (int y = 0; y < glyph->height; ++y)
1915 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1922 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1924 if (t.type() > QTransform::TxTranslate)
1925 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1929 GlyphFormat glyph_format = Format_A32;
1931 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1934 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1937 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1938 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1944 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1946 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1949 int QFontEngineFT::glyphCount() const
1952 FT_Face face = lockFace();
1954 count = face->num_glyphs;
1960 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1963 FT_Face face = freetype->face;
1964 if (scale == Unscaled) {
1965 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1966 freetype->xsize = face->units_per_EM << 6;
1967 freetype->ysize = face->units_per_EM << 6;
1968 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1969 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1970 freetype->xsize = xsize;
1971 freetype->ysize = ysize;
1973 if (freetype->matrix.xx != matrix.xx ||
1974 freetype->matrix.yy != matrix.yy ||
1975 freetype->matrix.xy != matrix.xy ||
1976 freetype->matrix.yx != matrix.yx) {
1977 freetype->matrix = matrix;
1978 FT_Set_Transform(face, &freetype->matrix, 0);
1984 void QFontEngineFT::unlockFace() const
1989 FT_Face QFontEngineFT::non_locked_face() const
1991 return freetype->face;
1995 QFontEngineFT::QGlyphSet::QGlyphSet()
1996 : id(0), outline_drawing(false)
1998 transformationMatrix.xx = 0x10000;
1999 transformationMatrix.yy = 0x10000;
2000 transformationMatrix.xy = 0;
2001 transformationMatrix.yx = 0;
2002 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
2003 fast_glyph_count = 0;
2006 QFontEngineFT::QGlyphSet::~QGlyphSet()
2011 void QFontEngineFT::QGlyphSet::clear()
2013 if (fast_glyph_count > 0) {
2014 for (int i = 0; i < 256; ++i) {
2015 if (fast_glyph_data[i]) {
2016 delete fast_glyph_data[i];
2017 fast_glyph_data[i] = 0;
2020 fast_glyph_count = 0;
2022 qDeleteAll(glyph_data);
2026 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2028 if (useFastGlyphData(index, subPixelPosition)) {
2029 if (fast_glyph_data[index]) {
2030 delete fast_glyph_data[index];
2031 fast_glyph_data[index] = 0;
2032 if (fast_glyph_count > 0)
2036 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2040 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2042 if (useFastGlyphData(index, subPixelPosition)) {
2043 if (!fast_glyph_data[index])
2045 fast_glyph_data[index] = glyph;
2047 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2051 unsigned long QFontEngineFT::allocateServerGlyphSet()
2056 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
2061 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2064 bool hsubpixel = true;
2066 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2067 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2072 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2074 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2077 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2079 freetype->ref.ref();
2081 default_load_flags = fe->default_load_flags;
2082 default_hint_style = fe->default_hint_style;
2083 antialias = fe->antialias;
2084 transform = fe->transform;
2085 embolden = fe->embolden;
2086 subpixelType = fe->subpixelType;
2087 lcdFilterType = fe->lcdFilterType;
2088 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
2089 embeddedbitmap = fe->embeddedbitmap;
2094 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2097 fontDef.pixelSize = pixelSize;
2098 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2099 if (!fe->initFromFontEngine(this)) {
2109 #endif // QT_NO_FREETYPE