Move ForceIntegerMetrics testing out of the loop
[qt:qtbase.git] / src / gui / text / qfontengine_ft.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdir.h"
43 #include "qmetatype.h"
44 #include "qtextstream.h"
45 #include "qvariant.h"
46 #include "qfontengine_ft_p.h"
47 #include "private/qimage_p.h"
48
49 #ifndef QT_NO_FREETYPE
50
51 #include "qfile.h"
52 #include "qfileinfo.h"
53 #include "qthreadstorage.h"
54 #include <qmath.h>
55
56 #include <ft2build.h>
57 #include FT_FREETYPE_H
58 #include FT_OUTLINE_H
59 #include FT_SYNTHESIS_H
60 #include FT_TRUETYPE_TABLES_H
61 #include FT_TYPE1_TABLES_H
62 #include FT_GLYPH_H
63
64 #if defined(FT_LCD_FILTER_H)
65 #include FT_LCD_FILTER_H
66 #endif
67
68 #if defined(FT_CONFIG_OPTIONS_H)
69 #include FT_CONFIG_OPTIONS_H
70 #endif
71
72 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
73 #define QT_USE_FREETYPE_LCDFILTER
74 #endif
75
76 #ifdef QT_LINUXBASE
77 #include FT_ERRORS_H
78 #endif
79
80 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
81 #  define QT_MAX_CACHED_GLYPH_SIZE 64
82 #endif
83
84 QT_BEGIN_NAMESPACE
85
86 /*
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.
90  */
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)
94 #else
95 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
96 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
97 #endif
98
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)
102 #else
103 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
104 #endif
105
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)
110 #else
111 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
112 #endif
113
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)
118
119 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
120 {
121 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
122     FT_Face face = (FT_Face)font;
123     FT_ULong ftlen = *length;
124     FT_Error error = 0;
125
126     if ( !FT_IS_SFNT(face) )
127         return HB_Err_Invalid_Argument;
128
129     error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
130     *length = ftlen;
131     return (HB_Error)error;
132 #else
133     return HB_Err_Invalid_Argument;
134 #endif
135 }
136
137 // -------------------------- Freetype support ------------------------------
138
139 class QtFreetypeData
140 {
141 public:
142     QtFreetypeData()
143         : library(0)
144     { }
145
146     FT_Library library;
147     QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
148 };
149
150 #ifdef QT_NO_THREAD
151 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
152
153 QtFreetypeData *qt_getFreetypeData()
154 {
155     return theFreetypeData();
156 }
157 #else
158 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
159
160 QtFreetypeData *qt_getFreetypeData()
161 {
162     QtFreetypeData *&freetypeData = theFreetypeData()->localData();
163     if (!freetypeData)
164         freetypeData = new QtFreetypeData;
165     return freetypeData;
166 }
167 #endif
168
169 FT_Library qt_getFreetype()
170 {
171     QtFreetypeData *freetypeData = qt_getFreetypeData();
172     if (!freetypeData->library)
173         FT_Init_FreeType(&freetypeData->library);
174     return freetypeData->library;
175 }
176
177 int QFreetypeFace::fsType() const
178 {
179     int fsType = 0;
180     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
181     if (os2)
182         fsType = os2->fsType;
183     return fsType;
184 }
185
186 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
187 {
188     if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
189         return error;
190
191     if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
192         return HB_Err_Invalid_SubTable;
193
194     *nPoints = face->glyph->outline.n_points;
195     if (!(*nPoints))
196         return HB_Err_Ok;
197
198     if (point > *nPoints)
199         return HB_Err_Invalid_SubTable;
200
201     *xpos = face->glyph->outline.points[point].x;
202     *ypos = face->glyph->outline.points[point].y;
203
204     return HB_Err_Ok;
205 }
206
207 extern QByteArray qt_fontdata_from_index(int);
208
209 /*
210  * One font file can contain more than one font (bold/italic for example)
211  * find the right one and return it.
212  *
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)
215  */
216 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
217                                       const QByteArray &fontData)
218 {
219     if (face_id.filename.isEmpty() && fontData.isEmpty())
220         return 0;
221
222     QtFreetypeData *freetypeData = qt_getFreetypeData();
223     if (!freetypeData->library)
224         FT_Init_FreeType(&freetypeData->library);
225
226     QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
227     if (freetype) {
228         freetype->ref.ref();
229     } else {
230         QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
231         FT_Face face;
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/'
238                 bool ok = false;
239                 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
240                 if (!ok)
241                     newFreetype->fontData = QByteArray();
242             } else if (!QFileInfo(fileName).isNativePath()) {
243                 QFile file(fileName);
244                 if (!file.open(QIODevice::ReadOnly)) {
245                     return 0;
246                 }
247                 newFreetype->fontData = file.readAll();
248             }
249         } else {
250             newFreetype->fontData = fontData;
251         }
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)) {
254                 return 0;
255             }
256         } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
257             return 0;
258         }
259         newFreetype->face = face;
260
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;
272
273         memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
274
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;
280                 break;
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;
285                 break;
286             case FT_ENCODING_ADOBE_CUSTOM:
287             case FT_ENCODING_MS_SYMBOL:
288                 if (!newFreetype->symbol_map)
289                     newFreetype->symbol_map = cm;
290                 break;
291             default:
292                 break;
293             }
294         }
295
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);
298
299         FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
300         QT_TRY {
301             freetypeData->faces.insert(face_id, newFreetype.data());
302         } QT_CATCH(...) {
303             newFreetype.take()->release(face_id);
304             // we could return null in principle instead of throwing
305             QT_RETHROW;
306         }
307         freetype = newFreetype.take();
308     }
309     return freetype;
310 }
311
312 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
313 {
314     QtFreetypeData *freetypeData = qt_getFreetypeData();
315     if (!ref.deref()) {
316         qHBFreeFace(hbFace);
317         FT_Done_Face(face);
318         if(freetypeData->faces.contains(face_id))
319             freetypeData->faces.take(face_id);
320         delete this;
321     }
322     if (freetypeData->faces.isEmpty()) {
323         FT_Done_FreeType(freetypeData->library);
324         freetypeData->library = 0;
325     }
326 }
327
328
329 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
330 {
331     *ysize = qRound(fontDef.pixelSize * 64);
332     *xsize = *ysize * fontDef.stretch / 100;
333     *outline_drawing = false;
334
335     /*
336      * Bitmap only faces must match exactly, so find the closest
337      * one (height dominant search)
338      */
339     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
340         int best = 0;
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)))) {
348                 best = i;
349             }
350         }
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);
354         } else {
355             int err = 1;
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...
361             }
362
363             if (err)
364                 *xsize = *ysize = 0;
365         }
366     } else {
367         *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
368     }
369 }
370
371 QFontEngine::Properties QFreetypeFace::properties() const
372 {
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);
386     } else {
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() );
394     }
395     p.italicAngle = 0;
396     p.capHeight = p.ascent;
397     p.lineWidth = face->underline_thickness;
398     return p;
399 }
400
401 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
402 {
403     bool result = false;
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;
408         *length = len;
409     }
410 #endif
411     return result;
412 }
413
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.
418
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.
422 */
423 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
424 {
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;
429     while (p < e) {
430         p->x = FT_MulFix(p->x, x_scale);
431         p->y = FT_MulFix(p->y, y_scale);
432         ++p;
433     }
434 }
435
436 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
437 {
438     const qreal factor = 1/64.;
439     scaleOutline(face, g, x_scale, y_scale);
440
441     QPointF cp = point.toPointF();
442
443     // convert the outline to a painter path
444     int i = 0;
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);
450             start /= 2;
451         }
452 //         qDebug("contour: %d -- %d", i, g->outline.contours[j]);
453 //         qDebug("first point at %f %f", start.x(), start.y());
454         path->moveTo(start);
455
456         QPointF c[4];
457         c[0] = start;
458         int n = 1;
459         while (i < last_point) {
460             ++i;
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];
463             ++n;
464             switch (g->outline.tags[i] & 3) {
465             case 2:
466                 // cubic bezier element
467                 if (n < 4)
468                     continue;
469                 c[3] = (c[3] + c[2])/2;
470                 --i;
471                 break;
472             case 0:
473                 // quadratic bezier element
474                 if (n < 3)
475                     continue;
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;
479                 --i;
480                 break;
481             case 1:
482             case 3:
483                 if (n == 2) {
484 //                     qDebug() << "lineTo" << c[1];
485                     path->lineTo(c[1]);
486                     c[0] = c[1];
487                     n = 1;
488                     continue;
489                 } else if (n == 3) {
490                     c[3] = c[2];
491                     c[2] = (2*c[1] + c[3])/3;
492                     c[1] = (2*c[1] + c[0])/3;
493                 }
494                 break;
495             }
496 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
497             path->cubicTo(c[1], c[2], c[3]);
498             c[0] = c[3];
499             n = 1;
500         }
501         if (n == 1) {
502 //             qDebug() << "closeSubpath";
503             path->closeSubpath();
504         } else {
505             c[3] = start;
506             if (n == 2) {
507                 c[2] = (2*c[1] + c[3])/3;
508                 c[1] = (2*c[1] + c[0])/3;
509             }
510 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
511             path->cubicTo(c[1], c[2], c[3]);
512         }
513         ++i;
514     }
515 }
516
517 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
518
519 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
520 {
521     if (slot->format != FT_GLYPH_FORMAT_BITMAP
522         || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
523         return;
524
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);
528 }
529
530 QFontEngineFT::Glyph::~Glyph()
531 {
532     delete [] data;
533 }
534
535 static const uint subpixel_filter[3][3] = {
536     { 180, 60, 16 },
537     { 38, 180, 38 },
538     { 16, 60, 180 }
539 };
540
541 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
542 {
543     uint res;
544     if (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;
549     } else {
550         uint alpha = green;
551         res = (alpha << 24) + (red << 16) + (green << 8) + blue;
552     }
553     return res;
554 }
555
556 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
557 {
558     int h = height;
559     const int offs = bgr ? -1 : 1;
560     const int w = width * 3;
561     while (h--) {
562         uint *dd = dst;
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);
568             ++dd;
569         }
570         dst += width;
571         src += src_pitch;
572     }
573 }
574
575 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
576 {
577     int h = height;
578     const int offs = bgr ? -src_pitch : src_pitch;
579     while (h--) {
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);
585         }
586         dst += width;
587         src += 3*src_pitch;
588     }
589 }
590
591 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
592 {
593     // convolute the bitmap with a triangle filter to get rid of color fringes
594     // If we take account for a gamma value of 2, we end up with
595     // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
596     // as this nicely sums up to 16 :)
597     int h = height;
598     while (h--) {
599         dst[0] = dst[1] = 0;
600         //
601         for (int x = 2; x < width - 2; ++x) {
602             uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
603             dst[x] = (uchar) (sum >> 4);
604         }
605         dst[width - 2] = dst[width - 1] = 0;
606         src += pitch;
607         dst += pitch;
608     }
609 }
610
611 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
612 {
613     fontDef = fd;
614     matrix.xx = 0x10000;
615     matrix.yy = 0x10000;
616     matrix.xy = 0;
617     matrix.yx = 0;
618     cache_cost = 100;
619     kerning_pairs_loaded = false;
620     transform = false;
621     embolden = false;
622     obliquen = false;
623     antialias = true;
624     freetype = 0;
625     default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
626 #ifndef Q_OS_WIN
627     default_hint_style = HintNone;
628 #else
629     default_hint_style = HintFull;
630 #endif
631     subpixelType = Subpixel_None;
632     lcdFilterType = 0;
633 #if defined(FT_LCD_FILTER_H)
634     lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
635 #endif
636     defaultFormat = Format_None;
637     embeddedbitmap = false;
638     const QByteArray env = qgetenv("QT_NO_FT_CACHE");
639     cacheEnabled = env.isEmpty() || env.toInt() == 0;
640     m_subPixelPositionCount = 4;
641 }
642
643 QFontEngineFT::~QFontEngineFT()
644 {
645     if (freetype)
646         freetype->release(face_id);
647     hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
648 }
649
650 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
651                          const QByteArray &fontData)
652 {
653     return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
654 }
655
656 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
657                          QFreetypeFace *freetypeFace)
658 {
659     freetype = freetypeFace;
660     if (!freetype) {
661         xsize = 0;
662         ysize = 0;
663         return false;
664     }
665     defaultFormat = format;
666     this->antialias = antialias;
667
668     if (!antialias)
669         glyphFormat = QFontEngineGlyphCache::Raster_Mono;
670     else if (format == Format_A8)
671         glyphFormat = QFontEngineGlyphCache::Raster_A8;
672     else if (format == Format_A32)
673         glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
674
675     face_id = faceId;
676
677     symbol = freetype->symbol_map != 0;
678     PS_FontInfoRec psrec;
679     // don't assume that type1 fonts are symbol fonts by default
680     if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
681         symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
682     }
683     // #####
684     freetype->hbFace->isSymbolFont = symbol;
685
686     lbearing = rbearing = SHRT_MIN;
687     freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
688
689     FT_Face face = lockFace();
690
691     if (FT_IS_SCALABLE(face)) {
692         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
693         if (fake_oblique) {
694 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
695             matrix.xy = 0x10000*3/10;
696             transform = true;
697 #else
698             obliquen = true;
699 #endif
700         }
701         FT_Set_Transform(face, &matrix, 0);
702         freetype->matrix = matrix;
703         // fake bold
704         if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
705             embolden = true;
706         // underline metrics
707         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
708         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
709     } else {
710         // copied from QFontEngineQPF
711         // ad hoc algorithm
712         int score = fontDef.weight * fontDef.pixelSize;
713         line_thickness = score / 700;
714         // looks better with thicker line for small pointsizes
715         if (line_thickness < 2 && score >= 1050)
716             line_thickness = 2;
717         underline_position =  ((line_thickness * 2) + 3) / 6;
718     }
719     if (line_thickness < 1)
720         line_thickness = 1;
721
722     hbFont.x_ppem  = face->size->metrics.x_ppem;
723     hbFont.y_ppem  = face->size->metrics.y_ppem;
724     hbFont.x_scale = face->size->metrics.x_scale;
725     hbFont.y_scale = face->size->metrics.y_scale;
726
727     hbFace = freetype->hbFace;
728
729     metrics = face->size->metrics;
730
731     /*
732        TrueType fonts with embedded bitmaps may have a bitmap font specific
733        ascent/descent in the EBLC table. There is no direct public API
734        to extract those values. The only way we've found is to trick freetype
735        into thinking that it's not a scalable font in FT_SelectSize so that
736        the metrics are retrieved from the bitmap strikes.
737     */
738     if (FT_IS_SCALABLE(face)) {
739         for (int i = 0; i < face->num_fixed_sizes; ++i) {
740             if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
741                 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
742
743                 FT_Select_Size(face, i);
744                 metrics.ascender = face->size->metrics.ascender;
745                 metrics.descender = face->size->metrics.descender;
746                 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
747
748                 face->face_flags |= FT_FACE_FLAG_SCALABLE;
749                 break;
750             }
751         }
752     }
753
754     fontDef.styleName = QString::fromUtf8(face->style_name);
755
756     unlockFace();
757
758     fsType = freetype->fsType();
759     return true;
760 }
761
762 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
763 {
764     default_hint_style = style;
765 }
766
767 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
768                              bool &hsubpixel, int &vfactor) const
769 {
770     int load_flags = FT_LOAD_DEFAULT | default_load_flags;
771     int load_target = default_hint_style == HintLight
772                       ? FT_LOAD_TARGET_LIGHT
773                       : FT_LOAD_TARGET_NORMAL;
774
775     if (format == Format_Mono) {
776         load_target = FT_LOAD_TARGET_MONO;
777     } else if (format == Format_A32) {
778         if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
779             if (default_hint_style == HintFull)
780                 load_target = FT_LOAD_TARGET_LCD;
781             hsubpixel = true;
782         } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
783             if (default_hint_style == HintFull)
784                 load_target = FT_LOAD_TARGET_LCD_V;
785             vfactor = 3;
786         }
787     }
788
789     if (set && set->outline_drawing)
790         load_flags = FT_LOAD_NO_BITMAP;
791
792     if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
793         load_flags |= FT_LOAD_NO_HINTING;
794     else
795         load_flags |= load_target;
796
797     return load_flags;
798 }
799
800 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
801                                                QFixed subPixelPosition,
802                                                GlyphFormat format,
803                                                bool fetchMetricsOnly) const
804 {
805 //     Q_ASSERT(freetype->lock == 1);
806
807     if (format == Format_None) {
808         if (defaultFormat != Format_None) {
809             format = defaultFormat;
810         } else {
811             format = Format_Mono;
812         }
813     }
814
815     Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
816     if (g && g->format == format && (fetchMetricsOnly || g->data))
817         return g;
818
819     QFontEngineFT::GlyphInfo info;
820
821     Q_ASSERT(format != Format_None);
822     bool hsubpixel = false;
823     int vfactor = 1;
824     int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
825
826     if (format != Format_Mono && !embeddedbitmap)
827         load_flags |= FT_LOAD_NO_BITMAP;
828
829     FT_Matrix matrix = freetype->matrix;
830     bool transform = matrix.xx != 0x10000
831                      || matrix.yy != 0x10000
832                      || matrix.xy != 0
833                      || matrix.yx != 0;
834
835     if (transform)
836         load_flags |= FT_LOAD_NO_BITMAP;
837
838     FT_Face face = freetype->face;
839
840     FT_Vector v;
841     v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
842     v.y = 0;
843     FT_Set_Transform(face, &freetype->matrix, &v);
844
845     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
846     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
847         load_flags &= ~FT_LOAD_NO_BITMAP;
848         err = FT_Load_Glyph(face, glyph, load_flags);
849     }
850     if (err == FT_Err_Too_Few_Arguments) {
851         // this is an error in the bytecode interpreter, just try to run without it
852         load_flags |= FT_LOAD_FORCE_AUTOHINT;
853         err = FT_Load_Glyph(face, glyph, load_flags);
854     }
855     if (err != FT_Err_Ok)
856         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
857
858     FT_GlyphSlot slot = face->glyph;
859
860     if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
861     if (obliquen) {
862         Q_FT_GLYPHSLOT_OBLIQUE(slot);
863
864         // While Embolden alters the metrics of the slot, oblique does not, so we need
865         // to fix this ourselves.
866         transform = true;
867         FT_Matrix m;
868         m.xx = 0x10000;
869         m.yx = 0x0;
870         m.xy = 0x6000;
871         m.yy = 0x10000;
872
873         FT_Matrix_Multiply(&m, &matrix);
874     }
875
876     FT_Library library = qt_getFreetype();
877
878     info.xOff = TRUNC(ROUND(slot->advance.x));
879     info.yOff = 0;
880
881     if ((set && set->outline_drawing) || fetchMetricsOnly) {
882         // If the advance doesn't fit in signed char, don't cache it
883         if (qAbs(info.xOff) >= 128)
884             return 0;
885         g = new Glyph;
886         g->data = 0;
887         g->linearAdvance = slot->linearHoriAdvance >> 10;
888         int left  = FLOOR(slot->metrics.horiBearingX);
889         int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
890         int top    = CEIL(slot->metrics.horiBearingY);
891         int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
892         g->width = TRUNC(right-left);
893         g->height = TRUNC(top-bottom);
894         g->x = TRUNC(left);
895         g->y = TRUNC(top);
896         g->advance = TRUNC(ROUND(slot->advance.x));
897         g->format = format;
898
899         if (set)
900             set->setGlyph(glyph, subPixelPosition, g);
901
902         return g;
903     }
904
905     uchar *glyph_buffer = 0;
906     int glyph_buffer_size = 0;
907 #if defined(QT_USE_FREETYPE_LCDFILTER)
908     bool useFreetypeRenderGlyph = false;
909     if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
910         err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
911         if (err == FT_Err_Ok)
912             useFreetypeRenderGlyph = true;
913     }
914
915     if (useFreetypeRenderGlyph) {
916         err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
917
918         if (err != FT_Err_Ok)
919             qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
920
921         FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
922
923         info.height = slot->bitmap.rows / vfactor;
924         info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
925         info.x = -slot->bitmap_left;
926         info.y = slot->bitmap_top;
927
928         glyph_buffer_size = info.width * info.height * 4;
929         glyph_buffer = new uchar[glyph_buffer_size];
930
931         if (hsubpixel)
932             convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
933         else if (vfactor != 1)
934             convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
935     } else
936 #endif
937     {
938     int left  = slot->metrics.horiBearingX;
939     int right = slot->metrics.horiBearingX + slot->metrics.width;
940     int top    = slot->metrics.horiBearingY;
941     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
942     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
943         int l, r, t, b;
944         FT_Vector vector;
945         vector.x = left;
946         vector.y = top;
947         FT_Vector_Transform(&vector, &matrix);
948         l = r = vector.x;
949         t = b = vector.y;
950         vector.x = right;
951         vector.y = top;
952         FT_Vector_Transform(&vector, &matrix);
953         if (l > vector.x) l = vector.x;
954         if (r < vector.x) r = vector.x;
955         if (t < vector.y) t = vector.y;
956         if (b > vector.y) b = vector.y;
957         vector.x = right;
958         vector.y = bottom;
959         FT_Vector_Transform(&vector, &matrix);
960         if (l > vector.x) l = vector.x;
961         if (r < vector.x) r = vector.x;
962         if (t < vector.y) t = vector.y;
963         if (b > vector.y) b = vector.y;
964         vector.x = left;
965         vector.y = bottom;
966         FT_Vector_Transform(&vector, &matrix);
967         if (l > vector.x) l = vector.x;
968         if (r < vector.x) r = vector.x;
969         if (t < vector.y) t = vector.y;
970         if (b > vector.y) b = vector.y;
971         left = l;
972         right = r;
973         top = t;
974         bottom = b;
975     }
976     left = FLOOR(left);
977     right = CEIL(right);
978     bottom = FLOOR(bottom);
979     top = CEIL(top);
980
981     int hpixels = TRUNC(right - left);
982     // subpixel position requires one more pixel
983     if (subPixelPosition > 0 && format != Format_Mono)
984         hpixels++;
985
986     if (hsubpixel)
987         hpixels = hpixels*3 + 8;
988     info.width = hpixels;
989     info.height = TRUNC(top - bottom);
990     info.x = -TRUNC(left);
991     info.y = TRUNC(top);
992     if (hsubpixel) {
993         info.width /= 3;
994         info.x += 1;
995     }
996
997     bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
998                         || ((uchar)(info.width) != info.width)
999                         || ((uchar)(info.height) != info.height)
1000                         || ((signed char)(info.x) != info.x)
1001                         || ((signed char)(info.y) != info.y)
1002                         || ((signed char)(info.xOff) != info.xOff));
1003
1004     if (large_glyph) {
1005         delete [] glyph_buffer;
1006         return 0;
1007     }
1008
1009     int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1010                  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1011     glyph_buffer_size = pitch * info.height;
1012     glyph_buffer = new uchar[glyph_buffer_size];
1013
1014     if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1015         FT_Bitmap bitmap;
1016         bitmap.rows = info.height*vfactor;
1017         bitmap.width = hpixels;
1018         bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1019         if (!hsubpixel && vfactor == 1)
1020             bitmap.buffer = glyph_buffer;
1021         else
1022             bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1023         memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1024         bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1025         FT_Matrix matrix;
1026         matrix.xx = (hsubpixel ? 3 : 1) << 16;
1027         matrix.yy = vfactor << 16;
1028         matrix.yx = matrix.xy = 0;
1029
1030         FT_Outline_Transform(&slot->outline, &matrix);
1031         FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1032         FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1033         if (hsubpixel) {
1034             Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1035             Q_ASSERT(antialias);
1036             uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1037             bool useLegacyLcdFilter = false;
1038 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1039             useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1040 #endif
1041             uchar *buffer = bitmap.buffer;
1042             if (!useLegacyLcdFilter) {
1043                 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1044                 buffer = convoluted;
1045             }
1046             convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1047             delete [] convoluted;
1048         } else if (vfactor != 1) {
1049             convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1050         }
1051
1052         if (bitmap.buffer != glyph_buffer)
1053             delete [] bitmap.buffer;
1054     } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1055         Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1056         uchar *src = slot->bitmap.buffer;
1057         uchar *dst = glyph_buffer;
1058         int h = slot->bitmap.rows;
1059         if (format == Format_Mono) {
1060             int bytes = ((info.width + 7) & ~7) >> 3;
1061             while (h--) {
1062                 memcpy (dst, src, bytes);
1063                 dst += pitch;
1064                 src += slot->bitmap.pitch;
1065             }
1066         } else {
1067             if (hsubpixel) {
1068                 while (h--) {
1069                     uint *dd = (uint *)dst;
1070                     *dd++ = 0;
1071                     for (int x = 0; x < slot->bitmap.width; x++) {
1072                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1073                         *dd++ = a;
1074                     }
1075                     *dd++ = 0;
1076                     dst += pitch;
1077                     src += slot->bitmap.pitch;
1078                 }
1079             } else if (vfactor != 1) {
1080                 while (h--) {
1081                     uint *dd = (uint *)dst;
1082                     for (int x = 0; x < slot->bitmap.width; x++) {
1083                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1084                         *dd++ = a;
1085                     }
1086                     dst += pitch;
1087                     src += slot->bitmap.pitch;
1088                 }
1089             } else {
1090                 while (h--) {
1091                     for (int x = 0; x < slot->bitmap.width; x++) {
1092                         unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1093                         dst[x] = a;
1094                     }
1095                     dst += pitch;
1096                     src += slot->bitmap.pitch;
1097                 }
1098             }
1099         }
1100     } else {
1101         qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1102         delete [] glyph_buffer;
1103         return 0;
1104     }
1105     }
1106
1107
1108     if (!g) {
1109         g = new Glyph;
1110         g->data = 0;
1111     }
1112
1113     g->linearAdvance = slot->linearHoriAdvance >> 10;
1114     g->width = info.width;
1115     g->height = info.height;
1116     g->x = -info.x;
1117     g->y = info.y;
1118     g->advance = info.xOff;
1119     g->format = format;
1120     delete [] g->data;
1121     g->data = glyph_buffer;
1122
1123     if (set)
1124         set->setGlyph(glyph, subPixelPosition, g);
1125
1126     return g;
1127 }
1128
1129 QFontEngine::FaceId QFontEngineFT::faceId() const
1130 {
1131     return face_id;
1132 }
1133
1134 QFontEngine::Properties QFontEngineFT::properties() const
1135 {
1136     Properties p = freetype->properties();
1137     if (p.postscriptName.isEmpty()) {
1138         p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1139     }
1140
1141     return freetype->properties();
1142 }
1143
1144 QFixed QFontEngineFT::emSquareSize() const
1145 {
1146     if (FT_IS_SCALABLE(freetype->face))
1147         return freetype->face->units_per_EM;
1148     else
1149         return freetype->face->size->metrics.y_ppem;
1150 }
1151
1152 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1153 {
1154     return freetype->getSfntTable(tag, buffer, length);
1155 }
1156
1157 int QFontEngineFT::synthesized() const
1158 {
1159     int s = 0;
1160     if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1161         s = SynthesizedItalic;
1162     if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1163         s |= SynthesizedBold;
1164     if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1165         s |= SynthesizedStretch;
1166     return s;
1167 }
1168
1169 QFixed QFontEngineFT::ascent() const
1170 {
1171     return QFixed::fromFixed(metrics.ascender);
1172 }
1173
1174 QFixed QFontEngineFT::descent() const
1175 {
1176     return QFixed::fromFixed(-metrics.descender);
1177 }
1178
1179 QFixed QFontEngineFT::leading() const
1180 {
1181     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1182 }
1183
1184 QFixed QFontEngineFT::xHeight() const
1185 {
1186     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1187     if (os2 && os2->sxHeight) {
1188         lockFace();
1189         QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1190         unlockFace();
1191         return answer;
1192     }
1193     return QFontEngine::xHeight();
1194 }
1195
1196 QFixed QFontEngineFT::averageCharWidth() const
1197 {
1198     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1199     if (os2 && os2->xAvgCharWidth) {
1200         lockFace();
1201         QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1202         unlockFace();
1203         return answer;
1204     }
1205     return QFontEngine::averageCharWidth();
1206 }
1207
1208 qreal QFontEngineFT::maxCharWidth() const
1209 {
1210     return metrics.max_advance >> 6;
1211 }
1212
1213 static const ushort char_table[] = {
1214         40,
1215         67,
1216         70,
1217         75,
1218         86,
1219         88,
1220         89,
1221         91,
1222         95,
1223         102,
1224         114,
1225         124,
1226         127,
1227         205,
1228         645,
1229         884,
1230         922,
1231         1070,
1232         12386
1233 };
1234
1235 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1236
1237
1238 qreal QFontEngineFT::minLeftBearing() const
1239 {
1240     if (lbearing == SHRT_MIN)
1241         (void) minRightBearing(); // calculates both
1242     return lbearing.toReal();
1243 }
1244
1245 qreal QFontEngineFT::minRightBearing() const
1246 {
1247     if (rbearing == SHRT_MIN) {
1248         lbearing = rbearing = 0;
1249         const QChar *ch = (const QChar *)(const void*)char_table;
1250         QGlyphLayoutArray<char_table_entries> glyphs;
1251         int ng = char_table_entries;
1252         stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly);
1253         while (--ng) {
1254             if (glyphs.glyphs[ng]) {
1255                 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1256                 lbearing = qMin(lbearing, gi.x);
1257                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1258             }
1259         }
1260     }
1261     return rbearing.toReal();
1262 }
1263
1264 QFixed QFontEngineFT::lineThickness() const
1265 {
1266     return line_thickness;
1267 }
1268
1269 QFixed QFontEngineFT::underlinePosition() const
1270 {
1271     return underline_position;
1272 }
1273
1274 void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
1275 {
1276     if (!kerning_pairs_loaded) {
1277         kerning_pairs_loaded = true;
1278         lockFace();
1279         if (freetype->face->size->metrics.x_ppem != 0) {
1280             QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1281             unlockFace();
1282             const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1283         } else {
1284             unlockFace();
1285         }
1286     }
1287     QFontEngine::doKerning(g, flags);
1288 }
1289
1290 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1291 {
1292     if (matrix.type() > QTransform::TxShear)
1293         return 0;
1294
1295     // FT_Set_Transform only supports scalable fonts
1296     if (!FT_IS_SCALABLE(freetype->face))
1297         return 0;
1298
1299     FT_Matrix m;
1300     m.xx = FT_Fixed(matrix.m11() * 65536);
1301     m.xy = FT_Fixed(-matrix.m21() * 65536);
1302     m.yx = FT_Fixed(-matrix.m12() * 65536);
1303     m.yy = FT_Fixed(matrix.m22() * 65536);
1304
1305     QGlyphSet *gs = 0;
1306
1307     for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1308         const QGlyphSet &g = transformedGlyphSets.at(i);
1309         if (g.transformationMatrix.xx == m.xx
1310             && g.transformationMatrix.xy == m.xy
1311             && g.transformationMatrix.yx == m.yx
1312             && g.transformationMatrix.yy == m.yy) {
1313
1314             // found a match, move it to the front
1315             transformedGlyphSets.move(i, 0);
1316             gs = &transformedGlyphSets[0];
1317             break;
1318         }
1319     }
1320
1321     if (!gs) {
1322         // don't try to load huge fonts
1323         bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1324         if (draw_as_outline)
1325             return 0;
1326
1327         // don't cache more than 10 transformations
1328         if (transformedGlyphSets.count() >= 10) {
1329             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1330         } else {
1331             transformedGlyphSets.prepend(QGlyphSet());
1332         }
1333         gs = &transformedGlyphSets[0];
1334         gs->clear();
1335         gs->transformationMatrix = m;
1336         gs->outline_drawing = draw_as_outline;
1337     }
1338
1339     return gs;
1340 }
1341
1342 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1343                                const QFixedPoint *positions,
1344                                GlyphFormat format)
1345 {
1346     FT_Face face = 0;
1347
1348     for (int i = 0; i < num_glyphs; ++i) {
1349         QFixed spp = subPixelPositionForX(positions[i].x);
1350         Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1351         if (glyph == 0 || glyph->format != format) {
1352             if (!face) {
1353                 face = lockFace();
1354                 FT_Matrix m = matrix;
1355                 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1356                 FT_Set_Transform(face, &m, 0);
1357                 freetype->matrix = m;
1358             }
1359             if (!loadGlyph(gs, glyphs[i], spp, format)) {
1360                 unlockFace();
1361                 return false;
1362             }
1363         }
1364     }
1365
1366     if (face)
1367         unlockFace();
1368
1369     return true;
1370 }
1371
1372 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1373 {
1374     FT_Face face = lockFace(Unscaled);
1375     FT_Set_Transform(face, 0, 0);
1376     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1377
1378     int left  = face->glyph->metrics.horiBearingX;
1379     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1380     int top    = face->glyph->metrics.horiBearingY;
1381     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1382
1383     QFixedPoint p;
1384     p.x = 0;
1385     p.y = 0;
1386
1387     metrics->width = QFixed::fromFixed(right-left);
1388     metrics->height = QFixed::fromFixed(top-bottom);
1389     metrics->x = QFixed::fromFixed(left);
1390     metrics->y = QFixed::fromFixed(-top);
1391     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1392
1393     if (!FT_IS_SCALABLE(freetype->face))
1394         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1395     else
1396         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1397
1398     FT_Set_Transform(face, &freetype->matrix, 0);
1399     unlockFace();
1400 }
1401
1402 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1403 {
1404     uint ucs4 = str[i].unicode();
1405     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1406         ++i;
1407         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1408     }
1409     return ucs4;
1410 }
1411
1412 bool QFontEngineFT::canRender(const QChar *string, int len)
1413 {
1414     FT_Face face = freetype->face;
1415     {
1416         for ( int i = 0; i < len; i++ ) {
1417             unsigned int uc = getChar(string, i, len);
1418             if (!FT_Get_Char_Index(face, uc))
1419                     return false;
1420         }
1421     }
1422     return true;
1423 }
1424
1425 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1426 {
1427     if (!glyphs.numGlyphs)
1428         return;
1429
1430     if (FT_IS_SCALABLE(freetype->face)) {
1431         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1432     } else {
1433         QVarLengthArray<QFixedPoint> positions;
1434         QVarLengthArray<glyph_t> positioned_glyphs;
1435         QTransform matrix;
1436         matrix.translate(x, y);
1437         getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1438
1439         FT_Face face = lockFace(Unscaled);
1440         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1441             FT_UInt glyph = positioned_glyphs[gl];
1442             FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1443             freetype->addBitmapToPath(face->glyph, positions[gl], path);
1444         }
1445         unlockFace();
1446     }
1447 }
1448
1449 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1450                                     QPainterPath *path, QTextItem::RenderFlags)
1451 {
1452     FT_Face face = lockFace(Unscaled);
1453
1454     for (int gl = 0; gl < numGlyphs; gl++) {
1455         FT_UInt glyph = glyphs[gl];
1456
1457         FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1458
1459         FT_GlyphSlot g = face->glyph;
1460         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1461             continue;
1462         if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1463         if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1464         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1465     }
1466     unlockFace();
1467 }
1468
1469 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1470                                  QFontEngine::ShaperFlags flags) const
1471 {
1472     if (*nglyphs < len) {
1473         *nglyphs = len;
1474         return false;
1475     }
1476
1477     bool mirrored = flags & QFontEngine::RightToLeft;
1478     int glyph_pos = 0;
1479     if (freetype->symbol_map) {
1480         FT_Face face = freetype->face;
1481         for ( int i = 0; i < len; ++i ) {
1482             unsigned int uc = getChar(str, i, len);
1483             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1484             if ( !glyphs->glyphs[glyph_pos] ) {
1485                 // Symbol fonts can have more than one CMAPs, FreeType should take the
1486                 // correct one for us by default, so we always try FT_Get_Char_Index
1487                 // first. If it didn't work (returns 0), we will explicitly set the
1488                 // CMAP to symbol font one and try again. symbol_map is not always the
1489                 // correct one because in certain fonts like Wingdings symbol_map only
1490                 // contains PUA codepoints instead of the common ones.
1491                 glyph_t glyph = FT_Get_Char_Index(face, uc);
1492                 // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1493                 // while we usually want to render them as space
1494                 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1495                     uc = 0x20;
1496                     glyph = FT_Get_Char_Index(face, uc);
1497                 }
1498                 if (!glyph) {
1499                     FT_Set_Charmap(face, freetype->symbol_map);
1500                     glyph = FT_Get_Char_Index(face, uc);
1501                     FT_Set_Charmap(face, freetype->unicode_map);
1502                 }
1503                 glyphs->glyphs[glyph_pos] = glyph;
1504                 if (uc < QFreetypeFace::cmapCacheSize)
1505                     freetype->cmapCache[uc] = glyph;
1506             }
1507             ++glyph_pos;
1508         }
1509     } else {
1510         FT_Face face = freetype->face;
1511         for (int i = 0; i < len; ++i) {
1512             unsigned int uc = getChar(str, i, len);
1513             if (mirrored)
1514                 uc = QChar::mirroredChar(uc);
1515             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1516             if (!glyphs->glyphs[glyph_pos]) {
1517                 {
1518                 redo:
1519                     glyph_t glyph = FT_Get_Char_Index(face, uc);
1520                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1521                         uc = 0x20;
1522                         goto redo;
1523                     }
1524                     glyphs->glyphs[glyph_pos] = glyph;
1525                     if (uc < QFreetypeFace::cmapCacheSize)
1526                         freetype->cmapCache[uc] = glyph;
1527                 }
1528             }
1529             ++glyph_pos;
1530         }
1531     }
1532
1533     *nglyphs = glyph_pos;
1534     glyphs->numGlyphs = glyph_pos;
1535
1536     if (!(flags & GlyphIndicesOnly))
1537         recalcAdvances(glyphs, flags);
1538
1539     return true;
1540 }
1541
1542 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1543 {
1544     FT_Face face = 0;
1545     bool design = (default_hint_style == HintNone ||
1546                    default_hint_style == HintLight ||
1547                    (flags & DesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1548     for (int i = 0; i < glyphs->numGlyphs; i++) {
1549         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1550         // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1551         GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1552         if (g && g->format == acceptableFormat) {
1553             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1554         } else {
1555             if (!face)
1556                 face = lockFace();
1557             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1558             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1559                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1560         }
1561         glyphs->advances_y[i] = 0;
1562     }
1563     if (face)
1564         unlockFace();
1565
1566     if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
1567         for (int i = 0; i < glyphs->numGlyphs; ++i)
1568             glyphs->advances_x[i] = glyphs->advances_x[i].round();
1569     }
1570 }
1571
1572 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1573 {
1574     FT_Face face = 0;
1575
1576     glyph_metrics_t overall;
1577     // initialize with line height, we get the same behaviour on all platforms
1578     overall.y = -ascent();
1579     overall.height = ascent() + descent();
1580
1581     QFixed ymax = 0;
1582     QFixed xmax = 0;
1583     for (int i = 0; i < glyphs.numGlyphs; i++) {
1584         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1585         if (!g) {
1586             if (!face)
1587                 face = lockFace();
1588             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1589         }
1590         if (g) {
1591             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1592             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1593             overall.x = qMin(overall.x, x);
1594             overall.y = qMin(overall.y, y);
1595             xmax = qMax(xmax, x + g->width);
1596             ymax = qMax(ymax, y + g->height);
1597             overall.xoff += g->advance;
1598         } else {
1599             int left  = FLOOR(face->glyph->metrics.horiBearingX);
1600             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1601             int top    = CEIL(face->glyph->metrics.horiBearingY);
1602             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1603
1604             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1605             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1606             overall.x = qMin(overall.x, x);
1607             overall.y = qMin(overall.y, y);
1608             xmax = qMax(xmax, x + TRUNC(right - left));
1609             ymax = qMax(ymax, y + TRUNC(top - bottom));
1610             overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1611         }
1612     }
1613     overall.height = qMax(overall.height, ymax - overall.y);
1614     overall.width = xmax - overall.x;
1615
1616     if (face)
1617         unlockFace();
1618
1619     return overall;
1620 }
1621
1622 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1623 {
1624     FT_Face face = 0;
1625     glyph_metrics_t overall;
1626     Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1627     if (!g) {
1628         face = lockFace();
1629         g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1630     }
1631     if (g) {
1632         overall.x = g->x;
1633         overall.y = -g->y;
1634         overall.width = g->width;
1635         overall.height = g->height;
1636         overall.xoff = g->advance;
1637         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1638             overall.xoff = overall.xoff.round();
1639     } else {
1640         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1641         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1642         int top    = CEIL(face->glyph->metrics.horiBearingY);
1643         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1644
1645         overall.width = TRUNC(right-left);
1646         overall.height = TRUNC(top-bottom);
1647         overall.x = TRUNC(left);
1648         overall.y = -TRUNC(top);
1649         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1650     }
1651     if (face)
1652         unlockFace();
1653     return overall;
1654 }
1655
1656 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1657 {
1658     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1659 }
1660
1661 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1662 {
1663     FT_Matrix m;
1664
1665     m.xx = FT_Fixed(matrix.m11() * 65536);
1666     m.xy = FT_Fixed(-matrix.m21() * 65536);
1667     m.yx = FT_Fixed(-matrix.m12() * 65536);
1668     m.yy = FT_Fixed(matrix.m22() * 65536);
1669
1670     return m;
1671 }
1672
1673 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1674 {
1675     FT_Face face = 0;
1676     glyph_metrics_t overall;
1677     QGlyphSet *glyphSet = 0;
1678     FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1679     if (cacheEnabled) {
1680         if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1681             // TODO move everything here to a method of its own to access glyphSets
1682             // to be shared with a new method that will replace loadTransformedGlyphSet()
1683             for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1684                 const QGlyphSet &g = transformedGlyphSets.at(i);
1685                 if (g.transformationMatrix.xx == ftMatrix.xx
1686                     && g.transformationMatrix.xy == ftMatrix.xy
1687                     && g.transformationMatrix.yx == ftMatrix.yx
1688                     && g.transformationMatrix.yy == ftMatrix.yy) {
1689
1690                     // found a match, move it to the front
1691                     transformedGlyphSets.move(i, 0);
1692                     glyphSet = &transformedGlyphSets[0];
1693                     break;
1694                 }
1695             }
1696
1697             if (!glyphSet) {
1698                 // don't cache more than 10 transformations
1699                 if (transformedGlyphSets.count() >= 10) {
1700                     transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1701                 } else {
1702                     transformedGlyphSets.prepend(QGlyphSet());
1703                 }
1704                 glyphSet = &transformedGlyphSets[0];
1705                 glyphSet->clear();
1706                 glyphSet->transformationMatrix = ftMatrix;
1707             }
1708             Q_ASSERT(glyphSet);
1709         } else {
1710             glyphSet = &defaultGlyphSet;
1711         }
1712     }
1713     Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1714     if (!g || g->format != format) {
1715         face = lockFace();
1716         FT_Matrix m = this->matrix;
1717         FT_Matrix_Multiply(&ftMatrix, &m);
1718         freetype->matrix = m;
1719         g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1720     }
1721
1722     if (g) {
1723         overall.x = g->x;
1724         overall.y = -g->y;
1725         overall.width = g->width;
1726         overall.height = g->height;
1727         overall.xoff = g->advance;
1728     } else {
1729         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1730         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1731         int top    = CEIL(face->glyph->metrics.horiBearingY);
1732         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1733
1734         overall.width = TRUNC(right-left);
1735         overall.height = TRUNC(top-bottom);
1736         overall.x = TRUNC(left);
1737         overall.y = -TRUNC(top);
1738         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1739     }
1740     if (face)
1741         unlockFace();
1742     return overall;
1743 }
1744
1745 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1746                                               QFontEngine::GlyphFormat neededFormat,
1747                                               const QTransform &t, QPoint *offset)
1748 {
1749     Q_ASSERT(currentlyLockedAlphaMap.isNull());
1750     lockFace();
1751
1752     if (isBitmapFont())
1753         neededFormat = Format_Mono;
1754     else if (neededFormat == Format_None && defaultFormat != Format_None)
1755         neededFormat = defaultFormat;
1756     else if (neededFormat == Format_None)
1757         neededFormat = Format_A8;
1758
1759     QImage::Format format;
1760     switch (neededFormat) {
1761     case Format_Mono:
1762         format = QImage::Format_Mono;
1763         break;
1764     case Format_A8:
1765         format = QImage::Format_Indexed8;
1766         break;
1767     case Format_A32:
1768         format = QImage::Format_ARGB32;
1769         break;
1770     default:
1771         Q_ASSERT(false);
1772         format = QImage::Format_Invalid;
1773     };
1774
1775     QFontEngineFT::Glyph *glyph;
1776     if (cacheEnabled) {
1777         QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1778         QFontEngine::HintStyle hintStyle = default_hint_style;
1779         if (t.type() >= QTransform::TxScale) {
1780             // disable hinting if the glyphs are transformed
1781             default_hint_style = HintNone;
1782             if (t.isAffine())
1783                 gset = loadTransformedGlyphSet(t);
1784             else
1785                 gset = 0;
1786         }
1787
1788         if (gset) {
1789             FT_Matrix m = matrix;
1790             FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1791             FT_Set_Transform(freetype->face, &m, 0);
1792             freetype->matrix = m;
1793         }
1794
1795         if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1796                                                          neededFormat)) {
1797             default_hint_style = hintStyle;
1798             return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1799                                                        offset);
1800         }
1801         default_hint_style = hintStyle;
1802
1803         glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1804     } else {
1805         FT_Matrix m = matrix;
1806         FT_Matrix extra = QTransformToFTMatrix(t);
1807         FT_Matrix_Multiply(&extra, &m);
1808         FT_Set_Transform(freetype->face, &m, 0);
1809         freetype->matrix = m;
1810         glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1811     }
1812
1813     if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1814         unlockFace();
1815         return 0;
1816     }
1817
1818     int pitch;
1819     switch (neededFormat) {
1820     case Format_Mono:
1821         pitch = ((glyph->width + 31) & ~31) >> 3;
1822         break;
1823     case Format_A8:
1824         pitch = (glyph->width + 3) & ~3;
1825         break;
1826     case Format_A32:
1827         pitch = glyph->width * 4;
1828         break;
1829     default:
1830         Q_ASSERT(false);
1831         pitch = 0;
1832     };
1833
1834     if (offset != 0)
1835         *offset = QPoint(glyph->x, -glyph->y);
1836
1837     currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1838     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1839
1840     QImageData *data = currentlyLockedAlphaMap.data_ptr();
1841     data->is_locked = true;
1842
1843     return &currentlyLockedAlphaMap;
1844 }
1845
1846 void QFontEngineFT::unlockAlphaMapForGlyph()
1847 {
1848     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1849     unlockFace();
1850     currentlyLockedAlphaMap = QImage();
1851 }
1852
1853 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1854 {
1855     return defaultGlyphSet.outline_drawing ? 0 :
1856             loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1857 }
1858
1859 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1860 {
1861     lockFace();
1862
1863     Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1864     if (!glyph || !glyph->data) {
1865         unlockFace();
1866         return QFontEngine::alphaMapForGlyph(g);
1867     }
1868
1869     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1870
1871     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1872     if (antialias) {
1873         QVector<QRgb> colors(256);
1874         for (int i=0; i<256; ++i)
1875             colors[i] = qRgba(0, 0, 0, i);
1876         img.setColorTable(colors);
1877     } else {
1878         QVector<QRgb> colors(2);
1879         colors[0] = qRgba(0, 0, 0, 0);
1880         colors[1] = qRgba(0, 0, 0, 255);
1881         img.setColorTable(colors);
1882     }
1883     Q_ASSERT(img.bytesPerLine() == pitch);
1884     if (glyph->width) {
1885         for (int y = 0; y < glyph->height; ++y)
1886             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1887     }
1888     unlockFace();
1889
1890     return img;
1891 }
1892
1893 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1894 {
1895     if (t.type() > QTransform::TxTranslate)
1896         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1897
1898     lockFace();
1899
1900     Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1901     if (!glyph || !glyph->data) {
1902         unlockFace();
1903         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1904     }
1905
1906     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1907     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1908     unlockFace();
1909
1910     return img;
1911 }
1912
1913 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1914 {
1915     defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1916 }
1917
1918 int QFontEngineFT::glyphCount() const
1919 {
1920     int count = 0;
1921     FT_Face face = lockFace();
1922     if (face) {
1923         count = face->num_glyphs;
1924         unlockFace();
1925     }
1926     return count;
1927 }
1928
1929 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1930 {
1931     freetype->lock();
1932     FT_Face face = freetype->face;
1933     if (scale == Unscaled) {
1934         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1935         freetype->xsize = face->units_per_EM << 6;
1936         freetype->ysize = face->units_per_EM << 6;
1937     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1938         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1939         freetype->xsize = xsize;
1940         freetype->ysize = ysize;
1941     }
1942     if (freetype->matrix.xx != matrix.xx ||
1943         freetype->matrix.yy != matrix.yy ||
1944         freetype->matrix.xy != matrix.xy ||
1945         freetype->matrix.yx != matrix.yx) {
1946         freetype->matrix = matrix;
1947         FT_Set_Transform(face, &freetype->matrix, 0);
1948     }
1949
1950     return face;
1951 }
1952
1953 void QFontEngineFT::unlockFace() const
1954 {
1955     freetype->unlock();
1956 }
1957
1958 FT_Face QFontEngineFT::non_locked_face() const
1959 {
1960     return freetype->face;
1961 }
1962
1963
1964 QFontEngineFT::QGlyphSet::QGlyphSet()
1965     : outline_drawing(false)
1966 {
1967     transformationMatrix.xx = 0x10000;
1968     transformationMatrix.yy = 0x10000;
1969     transformationMatrix.xy = 0;
1970     transformationMatrix.yx = 0;
1971     memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1972     fast_glyph_count = 0;
1973 }
1974
1975 QFontEngineFT::QGlyphSet::~QGlyphSet()
1976 {
1977     clear();
1978 }
1979
1980 void QFontEngineFT::QGlyphSet::clear()
1981 {
1982     if (fast_glyph_count > 0) {
1983         for (int i = 0; i < 256; ++i) {
1984             if (fast_glyph_data[i]) {
1985                 delete fast_glyph_data[i];
1986                 fast_glyph_data[i] = 0;
1987             }
1988         }
1989         fast_glyph_count = 0;
1990     }
1991     qDeleteAll(glyph_data);
1992     glyph_data.clear();
1993 }
1994
1995 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1996 {
1997     if (useFastGlyphData(index, subPixelPosition)) {
1998         if (fast_glyph_data[index]) {
1999             delete fast_glyph_data[index];
2000             fast_glyph_data[index] = 0;
2001             if (fast_glyph_count > 0)
2002                 --fast_glyph_count;
2003         }
2004     } else {
2005         delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2006     }
2007 }
2008
2009 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2010 {
2011     if (useFastGlyphData(index, subPixelPosition)) {
2012         if (!fast_glyph_data[index])
2013             ++fast_glyph_count;
2014         fast_glyph_data[index] = glyph;
2015     } else {
2016         glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2017     }
2018 }
2019
2020 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2021 {
2022     lockFace();
2023     bool hsubpixel = true;
2024     int vfactor = 1;
2025     int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2026     HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2027     unlockFace();
2028     return result;
2029 }
2030
2031 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2032 {
2033     if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2034         return false;
2035
2036     // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2037     // will be using it
2038     freetype->ref.ref();
2039
2040     default_load_flags = fe->default_load_flags;
2041     default_hint_style = fe->default_hint_style;
2042     antialias = fe->antialias;
2043     transform = fe->transform;
2044     embolden = fe->embolden;
2045     obliquen = fe->obliquen;
2046     subpixelType = fe->subpixelType;
2047     lcdFilterType = fe->lcdFilterType;
2048     embeddedbitmap = fe->embeddedbitmap;
2049
2050     return true;
2051 }
2052
2053 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2054 {
2055     QFontDef fontDef(this->fontDef);
2056     fontDef.pixelSize = pixelSize;
2057     QFontEngineFT *fe = new QFontEngineFT(fontDef);
2058     if (!fe->initFromFontEngine(this)) {
2059         delete fe;
2060         return 0;
2061     } else {
2062         return fe;
2063     }
2064 }
2065
2066 QT_END_NAMESPACE
2067
2068 #endif // QT_NO_FREETYPE