1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
43 #include "qmetatype.h"
44 #include "qtextstream.h"
46 #include "qfontengine_ft_p.h"
47 #include "private/qimage_p.h"
49 #ifndef QT_NO_FREETYPE
52 #include "qfileinfo.h"
53 #include "qthreadstorage.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
80 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
81 # define QT_MAX_CACHED_GLYPH_SIZE 64
87 * Freetype 2.1.7 and earlier used width/height
88 * for matching sizes in the BDF and PCF loaders.
89 * This has been fixed for 2.1.8.
91 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
92 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
93 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
95 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
96 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
99 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
100 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
101 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
103 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
106 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
107 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
108 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
109 #define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
111 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
114 #define FLOOR(x) ((x) & -64)
115 #define CEIL(x) (((x)+63) & -64)
116 #define TRUNC(x) ((x) >> 6)
117 #define ROUND(x) (((x)+32) & -64)
119 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
121 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
122 FT_Face face = (FT_Face)font;
123 FT_ULong ftlen = *length;
126 if ( !FT_IS_SFNT(face) )
127 return HB_Err_Invalid_Argument;
129 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
131 return (HB_Error)error;
133 return HB_Err_Invalid_Argument;
137 // -------------------------- Freetype support ------------------------------
147 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
151 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
153 QtFreetypeData *qt_getFreetypeData()
155 return theFreetypeData();
158 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
160 QtFreetypeData *qt_getFreetypeData()
162 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
164 freetypeData = new QtFreetypeData;
169 FT_Library qt_getFreetype()
171 QtFreetypeData *freetypeData = qt_getFreetypeData();
172 if (!freetypeData->library)
173 FT_Init_FreeType(&freetypeData->library);
174 return freetypeData->library;
177 int QFreetypeFace::fsType() const
180 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
182 fsType = os2->fsType;
186 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
188 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
191 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
192 return HB_Err_Invalid_SubTable;
194 *nPoints = face->glyph->outline.n_points;
198 if (point > *nPoints)
199 return HB_Err_Invalid_SubTable;
201 *xpos = face->glyph->outline.points[point].x;
202 *ypos = face->glyph->outline.points[point].y;
207 extern QByteArray qt_fontdata_from_index(int);
210 * One font file can contain more than one font (bold/italic for example)
211 * find the right one and return it.
213 * Returns the freetype face or 0 in case of an empty file or any other problems
214 * (like not being able to open the file)
216 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
217 const QByteArray &fontData)
219 if (face_id.filename.isEmpty() && fontData.isEmpty())
222 QtFreetypeData *freetypeData = qt_getFreetypeData();
223 if (!freetypeData->library)
224 FT_Init_FreeType(&freetypeData->library);
226 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
230 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
232 if (!face_id.filename.isEmpty()) {
233 QString fileName = QString::fromUtf8(face_id.filename);
234 if (face_id.filename.startsWith(":qmemoryfonts/")) {
235 // from qfontdatabase.cpp
236 QByteArray idx = face_id.filename;
237 idx.remove(0, 14); // remove ':qmemoryfonts/'
239 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
241 newFreetype->fontData = QByteArray();
242 } else if (!QFileInfo(fileName).isNativePath()) {
243 QFile file(fileName);
244 if (!file.open(QIODevice::ReadOnly)) {
247 newFreetype->fontData = file.readAll();
250 newFreetype->fontData = fontData;
252 if (!newFreetype->fontData.isEmpty()) {
253 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
256 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
259 newFreetype->face = face;
261 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
262 Q_CHECK_PTR(newFreetype->hbFace);
263 newFreetype->ref.store(1);
264 newFreetype->xsize = 0;
265 newFreetype->ysize = 0;
266 newFreetype->matrix.xx = 0x10000;
267 newFreetype->matrix.yy = 0x10000;
268 newFreetype->matrix.xy = 0;
269 newFreetype->matrix.yx = 0;
270 newFreetype->unicode_map = 0;
271 newFreetype->symbol_map = 0;
273 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
275 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
276 FT_CharMap cm = newFreetype->face->charmaps[i];
277 switch(cm->encoding) {
278 case FT_ENCODING_UNICODE:
279 newFreetype->unicode_map = cm;
281 case FT_ENCODING_APPLE_ROMAN:
282 case FT_ENCODING_ADOBE_LATIN_1:
283 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
284 newFreetype->unicode_map = cm;
286 case FT_ENCODING_ADOBE_CUSTOM:
287 case FT_ENCODING_MS_SYMBOL:
288 if (!newFreetype->symbol_map)
289 newFreetype->symbol_map = cm;
296 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
297 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
299 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
301 freetypeData->faces.insert(face_id, newFreetype.data());
303 newFreetype.take()->release(face_id);
304 // we could return null in principle instead of throwing
307 freetype = newFreetype.take();
312 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
314 QtFreetypeData *freetypeData = qt_getFreetypeData();
318 if(freetypeData->faces.contains(face_id))
319 freetypeData->faces.take(face_id);
322 if (freetypeData->faces.isEmpty()) {
323 FT_Done_FreeType(freetypeData->library);
324 freetypeData->library = 0;
329 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
331 *ysize = qRound(fontDef.pixelSize * 64);
332 *xsize = *ysize * fontDef.stretch / 100;
333 *outline_drawing = false;
336 * Bitmap only faces must match exactly, so find the closest
337 * one (height dominant search)
339 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
341 for (int i = 1; i < face->num_fixed_sizes; i++) {
342 if (qAbs(*ysize - Y_SIZE(face,i)) <
343 qAbs (*ysize - Y_SIZE(face, best)) ||
344 (qAbs (*ysize - Y_SIZE(face, i)) ==
345 qAbs (*ysize - Y_SIZE(face, best)) &&
346 qAbs (*xsize - X_SIZE(face, i)) <
347 qAbs (*xsize - X_SIZE(face, best)))) {
351 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
352 *xsize = X_SIZE(face, best);
353 *ysize = Y_SIZE(face, best);
356 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
357 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
358 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
359 if (err && face->num_fixed_sizes == 1)
360 err = 0; //even more of a workaround...
367 *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
371 QFontEngine::Properties QFreetypeFace::properties() const
373 QFontEngine::Properties p;
374 p.postscriptName = FT_Get_Postscript_Name(face);
375 PS_FontInfoRec font_info;
376 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
377 p.copyright = font_info.notice;
378 if (FT_IS_SCALABLE(face)) {
379 p.ascent = face->ascender;
380 p.descent = -face->descender;
381 p.leading = face->height - face->ascender + face->descender;
382 p.emSquare = face->units_per_EM;
383 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
384 face->bbox.xMax - face->bbox.xMin,
385 face->bbox.yMax - face->bbox.yMin);
387 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
388 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
389 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
390 p.emSquare = face->size->metrics.y_ppem;
391 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
392 p.boundingBox = QRectF(0, -p.ascent.toReal(),
393 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
396 p.capHeight = p.ascent;
397 p.lineWidth = face->underline_thickness;
401 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
404 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
405 if (FT_IS_SFNT(face)) {
406 FT_ULong len = *length;
407 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
414 /* Some fonts (such as MingLiu rely on hinting to scale different
415 components to their correct sizes. While this is really broken (it
416 should be done in the component glyph itself, not the hinter) we
417 will have to live with it.
419 This means we can not use FT_LOAD_NO_HINTING to get the glyph
420 outline. All we can do is to load the unscaled glyph and scale it
421 down manually when required.
423 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
425 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
426 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
427 FT_Vector *p = g->outline.points;
428 const FT_Vector *e = p + g->outline.n_points;
430 p->x = FT_MulFix(p->x, x_scale);
431 p->y = FT_MulFix(p->y, y_scale);
436 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
438 const qreal factor = 1/64.;
439 scaleOutline(face, g, x_scale, y_scale);
441 QPointF cp = point.toPointF();
443 // convert the outline to a painter path
445 for (int j = 0; j < g->outline.n_contours; ++j) {
446 int last_point = g->outline.contours[j];
447 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
448 if(!(g->outline.tags[i] & 1)) {
449 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
452 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
453 // qDebug("first point at %f %f", start.x(), start.y());
459 while (i < last_point) {
461 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
462 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
464 switch (g->outline.tags[i] & 3) {
466 // cubic bezier element
469 c[3] = (c[3] + c[2])/2;
473 // quadratic bezier element
476 c[3] = (c[1] + c[2])/2;
477 c[2] = (2*c[1] + c[3])/3;
478 c[1] = (2*c[1] + c[0])/3;
484 // qDebug() << "lineTo" << c[1];
491 c[2] = (2*c[1] + c[3])/3;
492 c[1] = (2*c[1] + c[0])/3;
496 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
497 path->cubicTo(c[1], c[2], c[3]);
502 // qDebug() << "closeSubpath";
503 path->closeSubpath();
507 c[2] = (2*c[1] + c[3])/3;
508 c[1] = (2*c[1] + c[0])/3;
510 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
511 path->cubicTo(c[1], c[2], c[3]);
517 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
519 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
521 if (slot->format != FT_GLYPH_FORMAT_BITMAP
522 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
525 QPointF cp = point.toPointF();
526 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
527 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
530 QFontEngineFT::Glyph::~Glyph()
535 static const uint subpixel_filter[3][3] = {
541 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
545 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
546 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
547 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
548 res = (mid << 24) + (high << 16) + (mid << 8) + low;
551 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
556 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
559 const int offs = bgr ? -1 : 1;
560 const int w = width * 3;
563 for (int x = 0; x < w; x += 3) {
564 uint red = src[x+1-offs];
565 uint green = src[x+1];
566 uint blue = src[x+1+offs];
567 *dd = filterPixel(red, green, blue, legacyFilter);
575 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
578 const int offs = bgr ? -src_pitch : src_pitch;
580 for (int x = 0; x < width; x++) {
581 uint red = src[x+src_pitch-offs];
582 uint green = src[x+src_pitch];
583 uint blue = src[x+src_pitch+offs];
584 dst[x] = filterPixel(red, green, blue, legacyFilter);
591 static void convertGRAYToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch) {
592 for (int y = 0; y < height; ++y) {
593 int readpos = (y * src_pitch);
594 int writepos = (y * width);
595 for (int x = 0; x < width; ++x) {
596 dst[writepos + x] = (0xFF << 24) + (src[readpos + x] << 16) + (src[readpos + x] << 8) + src[readpos + x];
601 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
603 // convolute the bitmap with a triangle filter to get rid of color fringes
604 // If we take account for a gamma value of 2, we end up with
605 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
606 // as this nicely sums up to 16 :)
611 for (int x = 2; x < width - 2; ++x) {
612 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
613 dst[x] = (uchar) (sum >> 4);
615 dst[width - 2] = dst[width - 1] = 0;
621 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
629 kerning_pairs_loaded = false;
635 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
637 default_hint_style = HintNone;
639 default_hint_style = HintFull;
641 subpixelType = Subpixel_None;
643 #if defined(FT_LCD_FILTER_H)
644 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
646 defaultFormat = Format_None;
647 embeddedbitmap = false;
648 const QByteArray env = qgetenv("QT_NO_FT_CACHE");
649 cacheEnabled = env.isEmpty() || env.toInt() == 0;
650 m_subPixelPositionCount = 4;
653 QFontEngineFT::~QFontEngineFT()
656 freetype->release(face_id);
657 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
660 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
661 const QByteArray &fontData)
663 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
666 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
667 QFreetypeFace *freetypeFace)
669 freetype = freetypeFace;
675 defaultFormat = format;
676 this->antialias = antialias;
679 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
680 else if (format == Format_A8)
681 glyphFormat = QFontEngineGlyphCache::Raster_A8;
682 else if (format == Format_A32)
683 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
687 symbol = freetype->symbol_map != 0;
688 PS_FontInfoRec psrec;
689 // don't assume that type1 fonts are symbol fonts by default
690 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
691 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
694 freetype->hbFace->isSymbolFont = symbol;
696 lbearing = rbearing = SHRT_MIN;
697 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
699 FT_Face face = lockFace();
701 if (FT_IS_SCALABLE(face)) {
702 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
704 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
705 matrix.xy = 0x10000*3/10;
711 FT_Set_Transform(face, &matrix, 0);
712 freetype->matrix = matrix;
714 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
717 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
718 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
720 // copied from QFontEngineQPF
722 int score = fontDef.weight * fontDef.pixelSize;
723 line_thickness = score / 700;
724 // looks better with thicker line for small pointsizes
725 if (line_thickness < 2 && score >= 1050)
727 underline_position = ((line_thickness * 2) + 3) / 6;
729 if (line_thickness < 1)
732 hbFont.x_ppem = face->size->metrics.x_ppem;
733 hbFont.y_ppem = face->size->metrics.y_ppem;
734 hbFont.x_scale = face->size->metrics.x_scale;
735 hbFont.y_scale = face->size->metrics.y_scale;
737 hbFace = freetype->hbFace;
739 metrics = face->size->metrics;
742 TrueType fonts with embedded bitmaps may have a bitmap font specific
743 ascent/descent in the EBLC table. There is no direct public API
744 to extract those values. The only way we've found is to trick freetype
745 into thinking that it's not a scalable font in FT_SelectSize so that
746 the metrics are retrieved from the bitmap strikes.
748 if (FT_IS_SCALABLE(face)) {
749 for (int i = 0; i < face->num_fixed_sizes; ++i) {
750 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
751 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
753 FT_Select_Size(face, i);
754 metrics.ascender = face->size->metrics.ascender;
755 metrics.descender = face->size->metrics.descender;
756 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
758 face->face_flags |= FT_FACE_FLAG_SCALABLE;
764 fontDef.styleName = QString::fromUtf8(face->style_name);
768 fsType = freetype->fsType();
772 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
774 default_hint_style = style;
777 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
778 bool &hsubpixel, int &vfactor) const
780 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
781 int load_target = default_hint_style == HintLight
782 ? FT_LOAD_TARGET_LIGHT
783 : FT_LOAD_TARGET_NORMAL;
785 if (format == Format_Mono) {
786 load_target = FT_LOAD_TARGET_MONO;
787 } else if (format == Format_A32) {
788 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
789 if (default_hint_style == HintFull)
790 load_target = FT_LOAD_TARGET_LCD;
792 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
793 if (default_hint_style == HintFull)
794 load_target = FT_LOAD_TARGET_LCD_V;
799 if (set && set->outline_drawing)
800 load_flags = FT_LOAD_NO_BITMAP;
802 if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
803 load_flags |= FT_LOAD_NO_HINTING;
805 load_flags |= load_target;
810 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
811 QFixed subPixelPosition,
813 bool fetchMetricsOnly) const
815 // Q_ASSERT(freetype->lock == 1);
817 if (format == Format_None) {
818 if (defaultFormat != Format_None) {
819 format = defaultFormat;
821 format = Format_Mono;
825 Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
826 if (g && g->format == format && (fetchMetricsOnly || g->data))
829 QFontEngineFT::GlyphInfo info;
831 Q_ASSERT(format != Format_None);
832 bool hsubpixel = false;
834 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
836 if (format != Format_Mono && !embeddedbitmap)
837 load_flags |= FT_LOAD_NO_BITMAP;
839 FT_Matrix matrix = freetype->matrix;
840 bool transform = matrix.xx != 0x10000
841 || matrix.yy != 0x10000
846 load_flags |= FT_LOAD_NO_BITMAP;
848 FT_Face face = freetype->face;
851 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
853 FT_Set_Transform(face, &freetype->matrix, &v);
855 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
856 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
857 load_flags &= ~FT_LOAD_NO_BITMAP;
858 err = FT_Load_Glyph(face, glyph, load_flags);
860 if (err == FT_Err_Too_Few_Arguments) {
861 // this is an error in the bytecode interpreter, just try to run without it
862 load_flags |= FT_LOAD_FORCE_AUTOHINT;
863 err = FT_Load_Glyph(face, glyph, load_flags);
865 if (err != FT_Err_Ok)
866 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
868 FT_GlyphSlot slot = face->glyph;
870 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
872 Q_FT_GLYPHSLOT_OBLIQUE(slot);
874 // While Embolden alters the metrics of the slot, oblique does not, so we need
875 // to fix this ourselves.
883 FT_Matrix_Multiply(&m, &matrix);
886 FT_Library library = qt_getFreetype();
888 info.xOff = TRUNC(ROUND(slot->advance.x));
891 if ((set && set->outline_drawing) || fetchMetricsOnly) {
892 // If the advance doesn't fit in signed char, don't cache it
893 if (qAbs(info.xOff) >= 128)
897 g->linearAdvance = slot->linearHoriAdvance >> 10;
898 int left = FLOOR(slot->metrics.horiBearingX);
899 int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
900 int top = CEIL(slot->metrics.horiBearingY);
901 int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
902 g->width = TRUNC(right-left);
903 g->height = TRUNC(top-bottom);
906 g->advance = TRUNC(ROUND(slot->advance.x));
910 set->setGlyph(glyph, subPixelPosition, g);
915 uchar *glyph_buffer = 0;
916 int glyph_buffer_size = 0;
917 #if defined(QT_USE_FREETYPE_LCDFILTER)
918 bool useFreetypeRenderGlyph = false;
919 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
920 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
921 if (err == FT_Err_Ok)
922 useFreetypeRenderGlyph = true;
925 if (useFreetypeRenderGlyph) {
926 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
928 if (err != FT_Err_Ok)
929 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
931 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
933 info.height = slot->bitmap.rows / vfactor;
934 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
935 info.x = -slot->bitmap_left;
936 info.y = slot->bitmap_top;
938 glyph_buffer_size = info.width * info.height * 4;
939 glyph_buffer = new uchar[glyph_buffer_size];
942 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
943 else if (vfactor != 1)
944 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
948 int left = slot->metrics.horiBearingX;
949 int right = slot->metrics.horiBearingX + slot->metrics.width;
950 int top = slot->metrics.horiBearingY;
951 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
952 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
957 FT_Vector_Transform(&vector, &matrix);
962 FT_Vector_Transform(&vector, &matrix);
963 if (l > vector.x) l = vector.x;
964 if (r < vector.x) r = vector.x;
965 if (t < vector.y) t = vector.y;
966 if (b > vector.y) b = vector.y;
969 FT_Vector_Transform(&vector, &matrix);
970 if (l > vector.x) l = vector.x;
971 if (r < vector.x) r = vector.x;
972 if (t < vector.y) t = vector.y;
973 if (b > vector.y) b = vector.y;
976 FT_Vector_Transform(&vector, &matrix);
977 if (l > vector.x) l = vector.x;
978 if (r < vector.x) r = vector.x;
979 if (t < vector.y) t = vector.y;
980 if (b > vector.y) b = vector.y;
988 bottom = FLOOR(bottom);
991 int hpixels = TRUNC(right - left);
992 // subpixel position requires one more pixel
993 if (subPixelPosition > 0 && format != Format_Mono)
997 hpixels = hpixels*3 + 8;
998 info.width = hpixels;
999 info.height = TRUNC(top - bottom);
1000 info.x = -TRUNC(left);
1001 info.y = TRUNC(top);
1007 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1008 || ((uchar)(info.width) != info.width)
1009 || ((uchar)(info.height) != info.height)
1010 || ((signed char)(info.x) != info.x)
1011 || ((signed char)(info.y) != info.y)
1012 || ((signed char)(info.xOff) != info.xOff));
1015 delete [] glyph_buffer;
1019 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1020 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1021 glyph_buffer_size = pitch * info.height;
1022 glyph_buffer = new uchar[glyph_buffer_size];
1024 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1026 bitmap.rows = info.height*vfactor;
1027 bitmap.width = hpixels;
1028 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1029 if (!hsubpixel && vfactor == 1 && format != Format_A32)
1030 bitmap.buffer = glyph_buffer;
1032 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1033 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1034 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1036 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1037 matrix.yy = vfactor << 16;
1038 matrix.yx = matrix.xy = 0;
1040 FT_Outline_Transform(&slot->outline, &matrix);
1041 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1042 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1044 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1045 Q_ASSERT(antialias);
1046 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1047 bool useLegacyLcdFilter = false;
1048 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1049 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1051 uchar *buffer = bitmap.buffer;
1052 if (!useLegacyLcdFilter) {
1053 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1054 buffer = convoluted;
1056 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1057 delete [] convoluted;
1058 } else if (vfactor != 1) {
1059 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1060 } else if (format == Format_A32 && bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
1061 convertGRAYToARGB(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch);
1064 if (bitmap.buffer != glyph_buffer)
1065 delete [] bitmap.buffer;
1066 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1067 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1068 uchar *src = slot->bitmap.buffer;
1069 uchar *dst = glyph_buffer;
1070 int h = slot->bitmap.rows;
1071 if (format == Format_Mono) {
1072 int bytes = ((info.width + 7) & ~7) >> 3;
1074 memcpy (dst, src, bytes);
1076 src += slot->bitmap.pitch;
1081 uint *dd = (uint *)dst;
1083 for (int x = 0; x < slot->bitmap.width; x++) {
1084 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1089 src += slot->bitmap.pitch;
1091 } else if (vfactor != 1) {
1093 uint *dd = (uint *)dst;
1094 for (int x = 0; x < slot->bitmap.width; x++) {
1095 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1099 src += slot->bitmap.pitch;
1103 for (int x = 0; x < slot->bitmap.width; x++) {
1104 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1108 src += slot->bitmap.pitch;
1113 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1114 delete [] glyph_buffer;
1125 g->linearAdvance = slot->linearHoriAdvance >> 10;
1126 g->width = info.width;
1127 g->height = info.height;
1130 g->advance = info.xOff;
1133 g->data = glyph_buffer;
1136 set->setGlyph(glyph, subPixelPosition, g);
1141 QFontEngine::FaceId QFontEngineFT::faceId() const
1146 QFontEngine::Properties QFontEngineFT::properties() const
1148 Properties p = freetype->properties();
1149 if (p.postscriptName.isEmpty()) {
1150 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1153 return freetype->properties();
1156 QFixed QFontEngineFT::emSquareSize() const
1158 if (FT_IS_SCALABLE(freetype->face))
1159 return freetype->face->units_per_EM;
1161 return freetype->face->size->metrics.y_ppem;
1164 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1166 return freetype->getSfntTable(tag, buffer, length);
1169 int QFontEngineFT::synthesized() const
1172 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1173 s = SynthesizedItalic;
1174 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1175 s |= SynthesizedBold;
1176 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1177 s |= SynthesizedStretch;
1181 QFixed QFontEngineFT::ascent() const
1183 return QFixed::fromFixed(metrics.ascender);
1186 QFixed QFontEngineFT::descent() const
1188 return QFixed::fromFixed(-metrics.descender);
1191 QFixed QFontEngineFT::leading() const
1193 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1196 QFixed QFontEngineFT::xHeight() const
1198 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1199 if (os2 && os2->sxHeight) {
1201 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1205 return QFontEngine::xHeight();
1208 QFixed QFontEngineFT::averageCharWidth() const
1210 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1211 if (os2 && os2->xAvgCharWidth) {
1213 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1217 return QFontEngine::averageCharWidth();
1220 qreal QFontEngineFT::maxCharWidth() const
1222 return metrics.max_advance >> 6;
1225 static const ushort char_table[] = {
1247 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1250 qreal QFontEngineFT::minLeftBearing() const
1252 if (lbearing == SHRT_MIN)
1253 (void) minRightBearing(); // calculates both
1254 return lbearing.toReal();
1257 qreal QFontEngineFT::minRightBearing() const
1259 if (rbearing == SHRT_MIN) {
1260 lbearing = rbearing = 0;
1261 const QChar *ch = (const QChar *)(const void*)char_table;
1262 QGlyphLayoutArray<char_table_entries> glyphs;
1263 int ng = char_table_entries;
1264 stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly);
1266 if (glyphs.glyphs[ng]) {
1267 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1268 lbearing = qMin(lbearing, gi.x);
1269 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1273 return rbearing.toReal();
1276 QFixed QFontEngineFT::lineThickness() const
1278 return line_thickness;
1281 QFixed QFontEngineFT::underlinePosition() const
1283 return underline_position;
1286 void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
1288 if (!kerning_pairs_loaded) {
1289 kerning_pairs_loaded = true;
1291 if (freetype->face->size->metrics.x_ppem != 0) {
1292 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1294 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1299 QFontEngine::doKerning(g, flags);
1302 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1304 if (matrix.type() > QTransform::TxShear)
1307 // FT_Set_Transform only supports scalable fonts
1308 if (!FT_IS_SCALABLE(freetype->face))
1312 m.xx = FT_Fixed(matrix.m11() * 65536);
1313 m.xy = FT_Fixed(-matrix.m21() * 65536);
1314 m.yx = FT_Fixed(-matrix.m12() * 65536);
1315 m.yy = FT_Fixed(matrix.m22() * 65536);
1319 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1320 const QGlyphSet &g = transformedGlyphSets.at(i);
1321 if (g.transformationMatrix.xx == m.xx
1322 && g.transformationMatrix.xy == m.xy
1323 && g.transformationMatrix.yx == m.yx
1324 && g.transformationMatrix.yy == m.yy) {
1326 // found a match, move it to the front
1327 transformedGlyphSets.move(i, 0);
1328 gs = &transformedGlyphSets[0];
1334 // don't try to load huge fonts
1335 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1336 if (draw_as_outline)
1339 // don't cache more than 10 transformations
1340 if (transformedGlyphSets.count() >= 10) {
1341 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1343 transformedGlyphSets.prepend(QGlyphSet());
1345 gs = &transformedGlyphSets[0];
1347 gs->transformationMatrix = m;
1348 gs->outline_drawing = draw_as_outline;
1354 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1355 const QFixedPoint *positions,
1360 for (int i = 0; i < num_glyphs; ++i) {
1361 QFixed spp = subPixelPositionForX(positions[i].x);
1362 Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1363 if (glyph == 0 || glyph->format != format) {
1366 FT_Matrix m = matrix;
1367 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1368 FT_Set_Transform(face, &m, 0);
1369 freetype->matrix = m;
1371 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1384 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1386 FT_Face face = lockFace(Unscaled);
1387 FT_Set_Transform(face, 0, 0);
1388 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1390 int left = face->glyph->metrics.horiBearingX;
1391 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1392 int top = face->glyph->metrics.horiBearingY;
1393 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1399 metrics->width = QFixed::fromFixed(right-left);
1400 metrics->height = QFixed::fromFixed(top-bottom);
1401 metrics->x = QFixed::fromFixed(left);
1402 metrics->y = QFixed::fromFixed(-top);
1403 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1405 if (!FT_IS_SCALABLE(freetype->face))
1406 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1408 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1410 FT_Set_Transform(face, &freetype->matrix, 0);
1414 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1416 uint ucs4 = str[i].unicode();
1417 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1419 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1424 bool QFontEngineFT::canRender(const QChar *string, int len)
1426 FT_Face face = freetype->face;
1428 for ( int i = 0; i < len; i++ ) {
1429 unsigned int uc = getChar(string, i, len);
1430 if (!FT_Get_Char_Index(face, uc))
1437 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1439 if (!glyphs.numGlyphs)
1442 if (FT_IS_SCALABLE(freetype->face)) {
1443 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1445 QVarLengthArray<QFixedPoint> positions;
1446 QVarLengthArray<glyph_t> positioned_glyphs;
1448 matrix.translate(x, y);
1449 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1451 FT_Face face = lockFace(Unscaled);
1452 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1453 FT_UInt glyph = positioned_glyphs[gl];
1454 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1455 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1461 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1462 QPainterPath *path, QTextItem::RenderFlags)
1464 FT_Face face = lockFace(Unscaled);
1466 for (int gl = 0; gl < numGlyphs; gl++) {
1467 FT_UInt glyph = glyphs[gl];
1469 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1471 FT_GlyphSlot g = face->glyph;
1472 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1474 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1475 if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1476 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1481 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1482 QFontEngine::ShaperFlags flags) const
1484 if (*nglyphs < len) {
1489 bool mirrored = flags & QFontEngine::RightToLeft;
1491 if (freetype->symbol_map) {
1492 FT_Face face = freetype->face;
1493 for ( int i = 0; i < len; ++i ) {
1494 unsigned int uc = getChar(str, i, len);
1495 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1496 if ( !glyphs->glyphs[glyph_pos] ) {
1497 // Symbol fonts can have more than one CMAPs, FreeType should take the
1498 // correct one for us by default, so we always try FT_Get_Char_Index
1499 // first. If it didn't work (returns 0), we will explicitly set the
1500 // CMAP to symbol font one and try again. symbol_map is not always the
1501 // correct one because in certain fonts like Wingdings symbol_map only
1502 // contains PUA codepoints instead of the common ones.
1503 glyph_t glyph = FT_Get_Char_Index(face, uc);
1504 // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1505 // while we usually want to render them as space
1506 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1508 glyph = FT_Get_Char_Index(face, uc);
1511 FT_Set_Charmap(face, freetype->symbol_map);
1512 glyph = FT_Get_Char_Index(face, uc);
1513 FT_Set_Charmap(face, freetype->unicode_map);
1515 glyphs->glyphs[glyph_pos] = glyph;
1516 if (uc < QFreetypeFace::cmapCacheSize)
1517 freetype->cmapCache[uc] = glyph;
1522 FT_Face face = freetype->face;
1523 for (int i = 0; i < len; ++i) {
1524 unsigned int uc = getChar(str, i, len);
1526 uc = QChar::mirroredChar(uc);
1527 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1528 if (!glyphs->glyphs[glyph_pos]) {
1531 glyph_t glyph = FT_Get_Char_Index(face, uc);
1532 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1536 glyphs->glyphs[glyph_pos] = glyph;
1537 if (uc < QFreetypeFace::cmapCacheSize)
1538 freetype->cmapCache[uc] = glyph;
1545 *nglyphs = glyph_pos;
1546 glyphs->numGlyphs = glyph_pos;
1548 if (!(flags & GlyphIndicesOnly))
1549 recalcAdvances(glyphs, flags);
1554 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1557 bool design = (default_hint_style == HintNone ||
1558 default_hint_style == HintLight ||
1559 (flags & DesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1560 for (int i = 0; i < glyphs->numGlyphs; i++) {
1561 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1562 // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1563 GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1564 if (g && g->format == acceptableFormat) {
1565 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1569 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1570 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1571 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1573 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1574 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1575 glyphs->advances_y[i] = 0;
1581 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1585 glyph_metrics_t overall;
1586 // initialize with line height, we get the same behaviour on all platforms
1587 overall.y = -ascent();
1588 overall.height = ascent() + descent();
1592 for (int i = 0; i < glyphs.numGlyphs; i++) {
1593 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1597 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1600 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1601 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1602 overall.x = qMin(overall.x, x);
1603 overall.y = qMin(overall.y, y);
1604 xmax = qMax(xmax, x + g->width);
1605 ymax = qMax(ymax, y + g->height);
1606 overall.xoff += g->advance;
1608 int left = FLOOR(face->glyph->metrics.horiBearingX);
1609 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1610 int top = CEIL(face->glyph->metrics.horiBearingY);
1611 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1613 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1614 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1615 overall.x = qMin(overall.x, x);
1616 overall.y = qMin(overall.y, y);
1617 xmax = qMax(xmax, x + TRUNC(right - left));
1618 ymax = qMax(ymax, y + TRUNC(top - bottom));
1619 overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1622 overall.height = qMax(overall.height, ymax - overall.y);
1623 overall.width = xmax - overall.x;
1631 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1634 glyph_metrics_t overall;
1635 Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1638 g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1643 overall.width = g->width;
1644 overall.height = g->height;
1645 overall.xoff = g->advance;
1646 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1647 overall.xoff = overall.xoff.round();
1649 int left = FLOOR(face->glyph->metrics.horiBearingX);
1650 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1651 int top = CEIL(face->glyph->metrics.horiBearingY);
1652 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1654 overall.width = TRUNC(right-left);
1655 overall.height = TRUNC(top-bottom);
1656 overall.x = TRUNC(left);
1657 overall.y = -TRUNC(top);
1658 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1665 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1667 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1670 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1674 m.xx = FT_Fixed(matrix.m11() * 65536);
1675 m.xy = FT_Fixed(-matrix.m21() * 65536);
1676 m.yx = FT_Fixed(-matrix.m12() * 65536);
1677 m.yy = FT_Fixed(matrix.m22() * 65536);
1682 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1685 glyph_metrics_t overall;
1686 QGlyphSet *glyphSet = 0;
1687 FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1689 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1690 // TODO move everything here to a method of its own to access glyphSets
1691 // to be shared with a new method that will replace loadTransformedGlyphSet()
1692 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1693 const QGlyphSet &g = transformedGlyphSets.at(i);
1694 if (g.transformationMatrix.xx == ftMatrix.xx
1695 && g.transformationMatrix.xy == ftMatrix.xy
1696 && g.transformationMatrix.yx == ftMatrix.yx
1697 && g.transformationMatrix.yy == ftMatrix.yy) {
1699 // found a match, move it to the front
1700 transformedGlyphSets.move(i, 0);
1701 glyphSet = &transformedGlyphSets[0];
1707 // don't cache more than 10 transformations
1708 if (transformedGlyphSets.count() >= 10) {
1709 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1711 transformedGlyphSets.prepend(QGlyphSet());
1713 glyphSet = &transformedGlyphSets[0];
1715 glyphSet->transformationMatrix = ftMatrix;
1719 glyphSet = &defaultGlyphSet;
1722 Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1723 if (!g || g->format != format) {
1725 FT_Matrix m = this->matrix;
1726 FT_Matrix_Multiply(&ftMatrix, &m);
1727 freetype->matrix = m;
1728 g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1734 overall.width = g->width;
1735 overall.height = g->height;
1736 overall.xoff = g->advance;
1738 int left = FLOOR(face->glyph->metrics.horiBearingX);
1739 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1740 int top = CEIL(face->glyph->metrics.horiBearingY);
1741 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1743 overall.width = TRUNC(right-left);
1744 overall.height = TRUNC(top-bottom);
1745 overall.x = TRUNC(left);
1746 overall.y = -TRUNC(top);
1747 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1754 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1755 QFontEngine::GlyphFormat neededFormat,
1756 const QTransform &t, QPoint *offset)
1758 Q_ASSERT(currentlyLockedAlphaMap.isNull());
1762 neededFormat = Format_Mono;
1763 else if (neededFormat == Format_None && defaultFormat != Format_None)
1764 neededFormat = defaultFormat;
1765 else if (neededFormat == Format_None)
1766 neededFormat = Format_A8;
1768 QImage::Format format;
1769 switch (neededFormat) {
1771 format = QImage::Format_Mono;
1774 format = QImage::Format_Indexed8;
1777 format = QImage::Format_ARGB32;
1781 format = QImage::Format_Invalid;
1784 QFontEngineFT::Glyph *glyph;
1786 QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1787 QFontEngine::HintStyle hintStyle = default_hint_style;
1788 if (t.type() >= QTransform::TxScale) {
1789 // disable hinting if the glyphs are transformed
1790 default_hint_style = HintNone;
1792 gset = loadTransformedGlyphSet(t);
1798 FT_Matrix m = matrix;
1799 FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1800 FT_Set_Transform(freetype->face, &m, 0);
1801 freetype->matrix = m;
1804 if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1806 default_hint_style = hintStyle;
1807 return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1810 default_hint_style = hintStyle;
1812 glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1814 FT_Matrix m = matrix;
1815 FT_Matrix extra = QTransformToFTMatrix(t);
1816 FT_Matrix_Multiply(&extra, &m);
1817 FT_Set_Transform(freetype->face, &m, 0);
1818 freetype->matrix = m;
1819 glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1822 if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1828 switch (neededFormat) {
1830 pitch = ((glyph->width + 31) & ~31) >> 3;
1833 pitch = (glyph->width + 3) & ~3;
1836 pitch = glyph->width * 4;
1844 *offset = QPoint(glyph->x, -glyph->y);
1846 currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1847 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1849 QImageData *data = currentlyLockedAlphaMap.data_ptr();
1850 data->is_locked = true;
1852 return ¤tlyLockedAlphaMap;
1855 void QFontEngineFT::unlockAlphaMapForGlyph()
1857 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1859 currentlyLockedAlphaMap = QImage();
1862 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1864 return defaultGlyphSet.outline_drawing ? 0 :
1865 loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1868 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1872 Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1873 if (!glyph || !glyph->data) {
1875 return QFontEngine::alphaMapForGlyph(g);
1878 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1880 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1882 QVector<QRgb> colors(256);
1883 for (int i=0; i<256; ++i)
1884 colors[i] = qRgba(0, 0, 0, i);
1885 img.setColorTable(colors);
1887 QVector<QRgb> colors(2);
1888 colors[0] = qRgba(0, 0, 0, 0);
1889 colors[1] = qRgba(0, 0, 0, 255);
1890 img.setColorTable(colors);
1892 Q_ASSERT(img.bytesPerLine() == pitch);
1894 for (int y = 0; y < glyph->height; ++y)
1895 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1902 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1904 if (t.type() > QTransform::TxTranslate)
1905 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1909 Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1910 if (!glyph || !glyph->data) {
1912 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1915 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1916 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1922 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1924 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1927 int QFontEngineFT::glyphCount() const
1930 FT_Face face = lockFace();
1932 count = face->num_glyphs;
1938 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1941 FT_Face face = freetype->face;
1942 if (scale == Unscaled) {
1943 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1944 freetype->xsize = face->units_per_EM << 6;
1945 freetype->ysize = face->units_per_EM << 6;
1946 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1947 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1948 freetype->xsize = xsize;
1949 freetype->ysize = ysize;
1951 if (freetype->matrix.xx != matrix.xx ||
1952 freetype->matrix.yy != matrix.yy ||
1953 freetype->matrix.xy != matrix.xy ||
1954 freetype->matrix.yx != matrix.yx) {
1955 freetype->matrix = matrix;
1956 FT_Set_Transform(face, &freetype->matrix, 0);
1962 void QFontEngineFT::unlockFace() const
1967 FT_Face QFontEngineFT::non_locked_face() const
1969 return freetype->face;
1973 QFontEngineFT::QGlyphSet::QGlyphSet()
1974 : outline_drawing(false)
1976 transformationMatrix.xx = 0x10000;
1977 transformationMatrix.yy = 0x10000;
1978 transformationMatrix.xy = 0;
1979 transformationMatrix.yx = 0;
1980 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1981 fast_glyph_count = 0;
1984 QFontEngineFT::QGlyphSet::~QGlyphSet()
1989 void QFontEngineFT::QGlyphSet::clear()
1991 if (fast_glyph_count > 0) {
1992 for (int i = 0; i < 256; ++i) {
1993 if (fast_glyph_data[i]) {
1994 delete fast_glyph_data[i];
1995 fast_glyph_data[i] = 0;
1998 fast_glyph_count = 0;
2000 qDeleteAll(glyph_data);
2004 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2006 if (useFastGlyphData(index, subPixelPosition)) {
2007 if (fast_glyph_data[index]) {
2008 delete fast_glyph_data[index];
2009 fast_glyph_data[index] = 0;
2010 if (fast_glyph_count > 0)
2014 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2018 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2020 if (useFastGlyphData(index, subPixelPosition)) {
2021 if (!fast_glyph_data[index])
2023 fast_glyph_data[index] = glyph;
2025 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2029 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2032 bool hsubpixel = true;
2034 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2035 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2040 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2042 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2045 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2047 freetype->ref.ref();
2049 default_load_flags = fe->default_load_flags;
2050 default_hint_style = fe->default_hint_style;
2051 antialias = fe->antialias;
2052 transform = fe->transform;
2053 embolden = fe->embolden;
2054 obliquen = fe->obliquen;
2055 subpixelType = fe->subpixelType;
2056 lcdFilterType = fe->lcdFilterType;
2057 embeddedbitmap = fe->embeddedbitmap;
2062 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2064 QFontDef fontDef(this->fontDef);
2065 fontDef.pixelSize = pixelSize;
2066 QFontEngineFT *fe = new QFontEngineFT(fontDef);
2067 if (!fe->initFromFontEngine(this)) {
2077 #endif // QT_NO_FREETYPE