Get started with patching up the Qt GUI docs
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_ft.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
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 "qfontengine_ft_p.h"
57 #include <ft2build.h>
58 #include FT_FREETYPE_H
59 #include FT_OUTLINE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
63 #include FT_GLYPH_H
64
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
67 #endif
68
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
71 #endif
72
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
75 #endif
76
77 #ifdef QT_LINUXBASE
78 #include FT_ERRORS_H
79 #endif
80
81 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
82 #  define QT_MAX_CACHED_GLYPH_SIZE 64
83 #endif
84
85 QT_BEGIN_NAMESPACE
86
87 /*
88  * Freetype 2.1.7 and earlier used width/height
89  * for matching sizes in the BDF and PCF loaders.
90  * This has been fixed for 2.1.8.
91  */
92 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
93 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
94 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
95 #else
96 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
97 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
98 #endif
99
100 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
101 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
102 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)   FT_GlyphSlot_Embolden(slot)
103 #else
104 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
105 #endif
106
107 /* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
108 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
109 #define Q_HAS_FT_GLYPHSLOT_OBLIQUE
110 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)   FT_GlyphSlot_Oblique(slot)
111 #else
112 #define Q_FT_GLYPHSLOT_OBLIQUE(slot)
113 #endif
114
115 #define FLOOR(x)    ((x) & -64)
116 #define CEIL(x)     (((x)+63) & -64)
117 #define TRUNC(x)    ((x) >> 6)
118 #define ROUND(x)    (((x)+32) & -64)
119
120 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
121 {
122 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
123     FT_Face face = (FT_Face)font;
124     FT_ULong ftlen = *length;
125     FT_Error error = 0;
126
127     if ( !FT_IS_SFNT(face) )
128         return HB_Err_Invalid_Argument;
129
130     error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
131     *length = ftlen;
132     return (HB_Error)error;
133 #else
134     return HB_Err_Invalid_Argument;
135 #endif
136 }
137
138 // -------------------------- Freetype support ------------------------------
139
140 class QtFreetypeData
141 {
142 public:
143     QtFreetypeData()
144         : library(0)
145     { }
146
147     FT_Library library;
148     QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
149 };
150
151 #ifdef QT_NO_THREAD
152 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
153
154 QtFreetypeData *qt_getFreetypeData()
155 {
156     return theFreetypeData();
157 }
158 #else
159 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
160
161 QtFreetypeData *qt_getFreetypeData()
162 {
163     QtFreetypeData *&freetypeData = theFreetypeData()->localData();
164     if (!freetypeData)
165         freetypeData = new QtFreetypeData;
166     return freetypeData;
167 }
168 #endif
169
170 FT_Library qt_getFreetype()
171 {
172     QtFreetypeData *freetypeData = qt_getFreetypeData();
173     if (!freetypeData->library)
174         FT_Init_FreeType(&freetypeData->library);
175     return freetypeData->library;
176 }
177
178 int QFreetypeFace::fsType() const
179 {
180     int fsType = 0;
181     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
182     if (os2)
183         fsType = os2->fsType;
184     return fsType;
185 }
186
187 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
188 {
189     if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
190         return error;
191
192     if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
193         return HB_Err_Invalid_SubTable;
194
195     *nPoints = face->glyph->outline.n_points;
196     if (!(*nPoints))
197         return HB_Err_Ok;
198
199     if (point > *nPoints)
200         return HB_Err_Invalid_SubTable;
201
202     *xpos = face->glyph->outline.points[point].x;
203     *ypos = face->glyph->outline.points[point].y;
204
205     return HB_Err_Ok;
206 }
207
208 extern QByteArray qt_fontdata_from_index(int);
209
210 /*
211  * One font file can contain more than one font (bold/italic for example)
212  * find the right one and return it.
213  *
214  * Returns the freetype face or 0 in case of an empty file or any other problems
215  * (like not being able to open the file)
216  */
217 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
218                                       const QByteArray &fontData)
219 {
220     if (face_id.filename.isEmpty() && fontData.isEmpty())
221         return 0;
222
223     QtFreetypeData *freetypeData = qt_getFreetypeData();
224     if (!freetypeData->library)
225         FT_Init_FreeType(&freetypeData->library);
226
227     QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
228     if (freetype) {
229         freetype->ref.ref();
230     } else {
231         QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
232         FT_Face face;
233         if (!face_id.filename.isEmpty()) {
234             QString fileName = QString::fromUtf8(face_id.filename);
235             if (face_id.filename.startsWith(":qmemoryfonts/")) {
236                 // from qfontdatabase.cpp
237                 QByteArray idx = face_id.filename;
238                 idx.remove(0, 14); // remove ':qmemoryfonts/'
239                 bool ok = false;
240                 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
241                 if (!ok)
242                     newFreetype->fontData = QByteArray();
243             } else if (!QFileInfo(fileName).isNativePath()) {
244                 QFile file(fileName);
245                 if (!file.open(QIODevice::ReadOnly)) {
246                     return 0;
247                 }
248                 newFreetype->fontData = file.readAll();
249             }
250         } else {
251             newFreetype->fontData = fontData;
252         }
253         if (!newFreetype->fontData.isEmpty()) {
254             if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
255                 return 0;
256             }
257         } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
258             return 0;
259         }
260         newFreetype->face = face;
261
262         newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
263         Q_CHECK_PTR(newFreetype->hbFace);
264         newFreetype->ref.store(1);
265         newFreetype->xsize = 0;
266         newFreetype->ysize = 0;
267         newFreetype->matrix.xx = 0x10000;
268         newFreetype->matrix.yy = 0x10000;
269         newFreetype->matrix.xy = 0;
270         newFreetype->matrix.yx = 0;
271         newFreetype->unicode_map = 0;
272         newFreetype->symbol_map = 0;
273
274         memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
275
276         for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
277             FT_CharMap cm = newFreetype->face->charmaps[i];
278             switch(cm->encoding) {
279             case FT_ENCODING_UNICODE:
280                 newFreetype->unicode_map = cm;
281                 break;
282             case FT_ENCODING_APPLE_ROMAN:
283             case FT_ENCODING_ADOBE_LATIN_1:
284                 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
285                     newFreetype->unicode_map = cm;
286                 break;
287             case FT_ENCODING_ADOBE_CUSTOM:
288             case FT_ENCODING_MS_SYMBOL:
289                 if (!newFreetype->symbol_map)
290                     newFreetype->symbol_map = cm;
291                 break;
292             default:
293                 break;
294             }
295         }
296
297         if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
298             FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
299
300         FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
301         QT_TRY {
302             freetypeData->faces.insert(face_id, newFreetype.data());
303         } QT_CATCH(...) {
304             newFreetype.take()->release(face_id);
305             // we could return null in principle instead of throwing
306             QT_RETHROW;
307         }
308         freetype = newFreetype.take();
309     }
310     return freetype;
311 }
312
313 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
314 {
315     QtFreetypeData *freetypeData = qt_getFreetypeData();
316     if (!ref.deref()) {
317         qHBFreeFace(hbFace);
318         FT_Done_Face(face);
319         if(freetypeData->faces.contains(face_id))
320             freetypeData->faces.take(face_id);
321         delete this;
322     }
323     if (freetypeData->faces.isEmpty()) {
324         FT_Done_FreeType(freetypeData->library);
325         freetypeData->library = 0;
326     }
327 }
328
329
330 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
331 {
332     *ysize = qRound(fontDef.pixelSize * 64);
333     *xsize = *ysize * fontDef.stretch / 100;
334     *outline_drawing = false;
335
336     /*
337      * Bitmap only faces must match exactly, so find the closest
338      * one (height dominant search)
339      */
340     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
341         int best = 0;
342         for (int i = 1; i < face->num_fixed_sizes; i++) {
343             if (qAbs(*ysize -  Y_SIZE(face,i)) <
344                 qAbs (*ysize - Y_SIZE(face, best)) ||
345                 (qAbs (*ysize - Y_SIZE(face, i)) ==
346                  qAbs (*ysize - Y_SIZE(face, best)) &&
347                  qAbs (*xsize - X_SIZE(face, i)) <
348                  qAbs (*xsize - X_SIZE(face, best)))) {
349                 best = i;
350             }
351         }
352         if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
353             *xsize = X_SIZE(face, best);
354             *ysize = Y_SIZE(face, best);
355         } else {
356             int err = 1;
357             if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
358                 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
359                 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
360                 if (err && face->num_fixed_sizes == 1)
361                     err = 0; //even more of a workaround...
362             }
363
364             if (err)
365                 *xsize = *ysize = 0;
366         }
367     } else {
368         *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
369     }
370 }
371
372 QFontEngine::Properties QFreetypeFace::properties() const
373 {
374     QFontEngine::Properties p;
375     p.postscriptName = FT_Get_Postscript_Name(face);
376     PS_FontInfoRec font_info;
377     if (FT_Get_PS_Font_Info(face, &font_info) == 0)
378         p.copyright = font_info.notice;
379     if (FT_IS_SCALABLE(face)) {
380         p.ascent = face->ascender;
381         p.descent = -face->descender;
382         p.leading = face->height - face->ascender + face->descender;
383         p.emSquare = face->units_per_EM;
384         p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
385                                face->bbox.xMax - face->bbox.xMin,
386                                face->bbox.yMax - face->bbox.yMin);
387     } else {
388         p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
389         p.descent = QFixed::fromFixed(-face->size->metrics.descender);
390         p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
391         p.emSquare = face->size->metrics.y_ppem;
392 //        p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
393         p.boundingBox = QRectF(0, -p.ascent.toReal(),
394                                face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
395     }
396     p.italicAngle = 0;
397     p.capHeight = p.ascent;
398     p.lineWidth = face->underline_thickness;
399     return p;
400 }
401
402 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
403 {
404     bool result = false;
405 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
406     if (FT_IS_SFNT(face)) {
407         FT_ULong len = *length;
408         result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
409         *length = len;
410     }
411 #endif
412     return result;
413 }
414
415 /* Some fonts (such as MingLiu rely on hinting to scale different
416    components to their correct sizes. While this is really broken (it
417    should be done in the component glyph itself, not the hinter) we
418    will have to live with it.
419
420    This means we can not use FT_LOAD_NO_HINTING to get the glyph
421    outline. All we can do is to load the unscaled glyph and scale it
422    down manually when required.
423 */
424 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
425 {
426     x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
427     y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
428     FT_Vector *p = g->outline.points;
429     const FT_Vector *e = p + g->outline.n_points;
430     while (p < e) {
431         p->x = FT_MulFix(p->x, x_scale);
432         p->y = FT_MulFix(p->y, y_scale);
433         ++p;
434     }
435 }
436
437 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
438 {
439     const qreal factor = 1/64.;
440     scaleOutline(face, g, x_scale, y_scale);
441
442     QPointF cp = point.toPointF();
443
444     // convert the outline to a painter path
445     int i = 0;
446     for (int j = 0; j < g->outline.n_contours; ++j) {
447         int last_point = g->outline.contours[j];
448         QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
449         if(!(g->outline.tags[i] & 1)) {
450             start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
451             start /= 2;
452         }
453 //         qDebug("contour: %d -- %d", i, g->outline.contours[j]);
454 //         qDebug("first point at %f %f", start.x(), start.y());
455         path->moveTo(start);
456
457         QPointF c[4];
458         c[0] = start;
459         int n = 1;
460         while (i < last_point) {
461             ++i;
462             c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
463 //             qDebug() << "    i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
464             ++n;
465             switch (g->outline.tags[i] & 3) {
466             case 2:
467                 // cubic bezier element
468                 if (n < 4)
469                     continue;
470                 c[3] = (c[3] + c[2])/2;
471                 --i;
472                 break;
473             case 0:
474                 // quadratic bezier element
475                 if (n < 3)
476                     continue;
477                 c[3] = (c[1] + c[2])/2;
478                 c[2] = (2*c[1] + c[3])/3;
479                 c[1] = (2*c[1] + c[0])/3;
480                 --i;
481                 break;
482             case 1:
483             case 3:
484                 if (n == 2) {
485 //                     qDebug() << "lineTo" << c[1];
486                     path->lineTo(c[1]);
487                     c[0] = c[1];
488                     n = 1;
489                     continue;
490                 } else if (n == 3) {
491                     c[3] = c[2];
492                     c[2] = (2*c[1] + c[3])/3;
493                     c[1] = (2*c[1] + c[0])/3;
494                 }
495                 break;
496             }
497 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
498             path->cubicTo(c[1], c[2], c[3]);
499             c[0] = c[3];
500             n = 1;
501         }
502         if (n == 1) {
503 //             qDebug() << "closeSubpath";
504             path->closeSubpath();
505         } else {
506             c[3] = start;
507             if (n == 2) {
508                 c[2] = (2*c[1] + c[3])/3;
509                 c[1] = (2*c[1] + c[0])/3;
510             }
511 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
512             path->cubicTo(c[1], c[2], c[3]);
513         }
514         ++i;
515     }
516 }
517
518 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
519
520 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
521 {
522     if (slot->format != FT_GLYPH_FORMAT_BITMAP
523         || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
524         return;
525
526     QPointF cp = point.toPointF();
527     qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
528                        slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
529 }
530
531 QFontEngineFT::Glyph::~Glyph()
532 {
533     delete [] data;
534 }
535
536 static const uint subpixel_filter[3][3] = {
537     { 180, 60, 16 },
538     { 38, 180, 38 },
539     { 16, 60, 180 }
540 };
541
542 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
543 {
544     uint res;
545     if (legacyFilter) {
546         uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
547         uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
548         uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
549         res = (mid << 24) + (high << 16) + (mid << 8) + low;
550     } else {
551         uint alpha = green;
552         res = (alpha << 24) + (red << 16) + (green << 8) + blue;
553     }
554     return res;
555 }
556
557 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
558 {
559     int h = height;
560     const int offs = bgr ? -1 : 1;
561     const int w = width * 3;
562     while (h--) {
563         uint *dd = dst;
564         for (int x = 0; x < w; x += 3) {
565             uint red = src[x+1-offs];
566             uint green = src[x+1];
567             uint blue = src[x+1+offs];
568             *dd = filterPixel(red, green, blue, legacyFilter);
569             ++dd;
570         }
571         dst += width;
572         src += src_pitch;
573     }
574 }
575
576 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
577 {
578     int h = height;
579     const int offs = bgr ? -src_pitch : src_pitch;
580     while (h--) {
581         for (int x = 0; x < width; x++) {
582             uint red = src[x+src_pitch-offs];
583             uint green = src[x+src_pitch];
584             uint blue = src[x+src_pitch+offs];
585             dst[x] = filterPixel(red, green, blue, legacyFilter);
586         }
587         dst += width;
588         src += 3*src_pitch;
589     }
590 }
591
592 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
593 {
594     // convolute the bitmap with a triangle filter to get rid of color fringes
595     // If we take account for a gamma value of 2, we end up with
596     // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
597     // as this nicely sums up to 16 :)
598     int h = height;
599     while (h--) {
600         dst[0] = dst[1] = 0;
601         //
602         for (int x = 2; x < width - 2; ++x) {
603             uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
604             dst[x] = (uchar) (sum >> 4);
605         }
606         dst[width - 2] = dst[width - 1] = 0;
607         src += pitch;
608         dst += pitch;
609     }
610 }
611
612 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
613 {
614     fontDef = fd;
615     matrix.xx = 0x10000;
616     matrix.yy = 0x10000;
617     matrix.xy = 0;
618     matrix.yx = 0;
619     cache_cost = 100;
620     kerning_pairs_loaded = false;
621     transform = false;
622     embolden = false;
623     obliquen = false;
624     antialias = true;
625     freetype = 0;
626     default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
627 #ifndef Q_OS_WIN
628     default_hint_style = HintNone;
629 #else
630     default_hint_style = HintFull;
631 #endif
632     subpixelType = Subpixel_None;
633     lcdFilterType = 0;
634 #if defined(FT_LCD_FILTER_H)
635     lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
636 #endif
637     defaultFormat = Format_None;
638     embeddedbitmap = false;
639     cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").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 & HB_ShaperFlag_UseDesignMetrics) || (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, QTextEngine::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, QTextEngine::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                                  QTextEngine::ShaperFlags flags) const
1471 {
1472     if (*nglyphs < len) {
1473         *nglyphs = len;
1474         return false;
1475     }
1476
1477     bool mirrored = flags & QTextEngine::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 & QTextEngine::GlyphIndicesOnly)
1537         return true;
1538
1539     recalcAdvances(glyphs, flags);
1540
1541     return true;
1542 }
1543
1544 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1545 {
1546     FT_Face face = 0;
1547     bool design = (default_hint_style == HintNone ||
1548                    default_hint_style == HintLight ||
1549                    (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1550     for (int i = 0; i < glyphs->numGlyphs; i++) {
1551         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1552         // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1553         GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1554         if (g && g->format == acceptableFormat) {
1555             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1556         } else {
1557             if (!face)
1558                 face = lockFace();
1559             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1560             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1561                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1562         }
1563         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1564             glyphs->advances_x[i] = glyphs->advances_x[i].round();
1565         glyphs->advances_y[i] = 0;
1566     }
1567     if (face)
1568         unlockFace();
1569 }
1570
1571 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1572 {
1573     FT_Face face = 0;
1574
1575     glyph_metrics_t overall;
1576     // initialize with line height, we get the same behaviour on all platforms
1577     overall.y = -ascent();
1578     overall.height = ascent() + descent();
1579
1580     QFixed ymax = 0;
1581     QFixed xmax = 0;
1582     for (int i = 0; i < glyphs.numGlyphs; i++) {
1583         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1584         if (!g) {
1585             if (!face)
1586                 face = lockFace();
1587             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1588         }
1589         if (g) {
1590             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1591             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1592             overall.x = qMin(overall.x, x);
1593             overall.y = qMin(overall.y, y);
1594             xmax = qMax(xmax, x + g->width);
1595             ymax = qMax(ymax, y + g->height);
1596             overall.xoff += g->advance;
1597         } else {
1598             int left  = FLOOR(face->glyph->metrics.horiBearingX);
1599             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1600             int top    = CEIL(face->glyph->metrics.horiBearingY);
1601             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1602
1603             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1604             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1605             overall.x = qMin(overall.x, x);
1606             overall.y = qMin(overall.y, y);
1607             xmax = qMax(xmax, x + TRUNC(right - left));
1608             ymax = qMax(ymax, y + TRUNC(top - bottom));
1609             overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1610         }
1611     }
1612     overall.height = qMax(overall.height, ymax - overall.y);
1613     overall.width = xmax - overall.x;
1614
1615     if (face)
1616         unlockFace();
1617
1618     return overall;
1619 }
1620
1621 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1622 {
1623     FT_Face face = 0;
1624     glyph_metrics_t overall;
1625     Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1626     if (!g) {
1627         face = lockFace();
1628         g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1629     }
1630     if (g) {
1631         overall.x = g->x;
1632         overall.y = -g->y;
1633         overall.width = g->width;
1634         overall.height = g->height;
1635         overall.xoff = g->advance;
1636         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1637             overall.xoff = overall.xoff.round();
1638     } else {
1639         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1640         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1641         int top    = CEIL(face->glyph->metrics.horiBearingY);
1642         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1643
1644         overall.width = TRUNC(right-left);
1645         overall.height = TRUNC(top-bottom);
1646         overall.x = TRUNC(left);
1647         overall.y = -TRUNC(top);
1648         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1649     }
1650     if (face)
1651         unlockFace();
1652     return overall;
1653 }
1654
1655 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1656 {
1657     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1658 }
1659
1660 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1661 {
1662     FT_Matrix m;
1663
1664     m.xx = FT_Fixed(matrix.m11() * 65536);
1665     m.xy = FT_Fixed(-matrix.m21() * 65536);
1666     m.yx = FT_Fixed(-matrix.m12() * 65536);
1667     m.yy = FT_Fixed(matrix.m22() * 65536);
1668
1669     return m;
1670 }
1671
1672 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1673 {
1674     FT_Face face = 0;
1675     glyph_metrics_t overall;
1676     QGlyphSet *glyphSet = 0;
1677     FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1678     if (cacheEnabled) {
1679         if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1680             // TODO move everything here to a method of its own to access glyphSets
1681             // to be shared with a new method that will replace loadTransformedGlyphSet()
1682             for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1683                 const QGlyphSet &g = transformedGlyphSets.at(i);
1684                 if (g.transformationMatrix.xx == ftMatrix.xx
1685                     && g.transformationMatrix.xy == ftMatrix.xy
1686                     && g.transformationMatrix.yx == ftMatrix.yx
1687                     && g.transformationMatrix.yy == ftMatrix.yy) {
1688
1689                     // found a match, move it to the front
1690                     transformedGlyphSets.move(i, 0);
1691                     glyphSet = &transformedGlyphSets[0];
1692                     break;
1693                 }
1694             }
1695
1696             if (!glyphSet) {
1697                 // don't cache more than 10 transformations
1698                 if (transformedGlyphSets.count() >= 10) {
1699                     transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1700                 } else {
1701                     transformedGlyphSets.prepend(QGlyphSet());
1702                 }
1703                 glyphSet = &transformedGlyphSets[0];
1704                 glyphSet->clear();
1705                 glyphSet->transformationMatrix = ftMatrix;
1706             }
1707             Q_ASSERT(glyphSet);
1708         } else {
1709             glyphSet = &defaultGlyphSet;
1710         }
1711     }
1712     Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1713     if (!g || g->format != format) {
1714         face = lockFace();
1715         FT_Matrix m = this->matrix;
1716         FT_Matrix_Multiply(&ftMatrix, &m);
1717         freetype->matrix = m;
1718         g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1719     }
1720
1721     if (g) {
1722         overall.x = g->x;
1723         overall.y = -g->y;
1724         overall.width = g->width;
1725         overall.height = g->height;
1726         overall.xoff = g->advance;
1727     } else {
1728         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1729         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1730         int top    = CEIL(face->glyph->metrics.horiBearingY);
1731         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1732
1733         overall.width = TRUNC(right-left);
1734         overall.height = TRUNC(top-bottom);
1735         overall.x = TRUNC(left);
1736         overall.y = -TRUNC(top);
1737         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1738     }
1739     if (face)
1740         unlockFace();
1741     return overall;
1742 }
1743
1744 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1745                                               QFontEngine::GlyphFormat neededFormat,
1746                                               const QTransform &t, QPoint *offset)
1747 {
1748     Q_ASSERT(currentlyLockedAlphaMap.isNull());
1749     lockFace();
1750
1751     if (isBitmapFont())
1752         neededFormat = Format_Mono;
1753     else if (neededFormat == Format_None && defaultFormat != Format_None)
1754         neededFormat = defaultFormat;
1755     else if (neededFormat == Format_None)
1756         neededFormat = Format_A8;
1757
1758     QImage::Format format;
1759     switch (neededFormat) {
1760     case Format_Mono:
1761         format = QImage::Format_Mono;
1762         break;
1763     case Format_A8:
1764         format = QImage::Format_Indexed8;
1765         break;
1766     case Format_A32:
1767         format = QImage::Format_ARGB32;
1768         break;
1769     default:
1770         Q_ASSERT(false);
1771         format = QImage::Format_Invalid;
1772     };
1773
1774     QFontEngineFT::Glyph *glyph;
1775     if (cacheEnabled) {
1776         QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1777         QFontEngine::HintStyle hintStyle = default_hint_style;
1778         if (t.type() >= QTransform::TxScale) {
1779             // disable hinting if the glyphs are transformed
1780             default_hint_style = HintNone;
1781             if (t.isAffine())
1782                 gset = loadTransformedGlyphSet(t);
1783             else
1784                 gset = 0;
1785         }
1786
1787         if (gset) {
1788             FT_Matrix m = matrix;
1789             FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1790             FT_Set_Transform(freetype->face, &m, 0);
1791             freetype->matrix = m;
1792         }
1793
1794         if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1795                                                          neededFormat)) {
1796             default_hint_style = hintStyle;
1797             return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1798                                                        offset);
1799         }
1800         default_hint_style = hintStyle;
1801
1802         glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1803     } else {
1804         FT_Matrix m = matrix;
1805         FT_Matrix extra = QTransformToFTMatrix(t);
1806         FT_Matrix_Multiply(&extra, &m);
1807         FT_Set_Transform(freetype->face, &m, 0);
1808         freetype->matrix = m;
1809         glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1810     }
1811
1812     if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1813         unlockFace();
1814         return 0;
1815     }
1816
1817     int pitch;
1818     switch (neededFormat) {
1819     case Format_Mono:
1820         pitch = ((glyph->width + 31) & ~31) >> 3;
1821         break;
1822     case Format_A8:
1823         pitch = (glyph->width + 3) & ~3;
1824         break;
1825     case Format_A32:
1826         pitch = glyph->width * 4;
1827         break;
1828     default:
1829         Q_ASSERT(false);
1830         pitch = 0;
1831     };
1832
1833     if (offset != 0)
1834         *offset = QPoint(glyph->x, -glyph->y);
1835
1836     currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1837     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1838
1839     QImageData *data = currentlyLockedAlphaMap.data_ptr();
1840     data->is_locked = true;
1841
1842     return &currentlyLockedAlphaMap;
1843 }
1844
1845 void QFontEngineFT::unlockAlphaMapForGlyph()
1846 {
1847     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1848     unlockFace();
1849     currentlyLockedAlphaMap = QImage();
1850 }
1851
1852 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1853 {
1854     return defaultGlyphSet.outline_drawing ? 0 :
1855             loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1856 }
1857
1858 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1859 {
1860     lockFace();
1861
1862     Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1863     if (!glyph || !glyph->data) {
1864         unlockFace();
1865         return QFontEngine::alphaMapForGlyph(g);
1866     }
1867
1868     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1869
1870     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1871     if (antialias) {
1872         QVector<QRgb> colors(256);
1873         for (int i=0; i<256; ++i)
1874             colors[i] = qRgba(0, 0, 0, i);
1875         img.setColorTable(colors);
1876     } else {
1877         QVector<QRgb> colors(2);
1878         colors[0] = qRgba(0, 0, 0, 0);
1879         colors[1] = qRgba(0, 0, 0, 255);
1880         img.setColorTable(colors);
1881     }
1882     Q_ASSERT(img.bytesPerLine() == pitch);
1883     if (glyph->width) {
1884         for (int y = 0; y < glyph->height; ++y)
1885             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1886     }
1887     unlockFace();
1888
1889     return img;
1890 }
1891
1892 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1893 {
1894     if (t.type() > QTransform::TxTranslate)
1895         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1896
1897     lockFace();
1898
1899     Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1900     if (!glyph || !glyph->data) {
1901         unlockFace();
1902         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1903     }
1904
1905     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1906     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1907     unlockFace();
1908
1909     return img;
1910 }
1911
1912 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1913 {
1914     defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1915 }
1916
1917 int QFontEngineFT::glyphCount() const
1918 {
1919     int count = 0;
1920     FT_Face face = lockFace();
1921     if (face) {
1922         count = face->num_glyphs;
1923         unlockFace();
1924     }
1925     return count;
1926 }
1927
1928 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1929 {
1930     freetype->lock();
1931     FT_Face face = freetype->face;
1932     if (scale == Unscaled) {
1933         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1934         freetype->xsize = face->units_per_EM << 6;
1935         freetype->ysize = face->units_per_EM << 6;
1936     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1937         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1938         freetype->xsize = xsize;
1939         freetype->ysize = ysize;
1940     }
1941     if (freetype->matrix.xx != matrix.xx ||
1942         freetype->matrix.yy != matrix.yy ||
1943         freetype->matrix.xy != matrix.xy ||
1944         freetype->matrix.yx != matrix.yx) {
1945         freetype->matrix = matrix;
1946         FT_Set_Transform(face, &freetype->matrix, 0);
1947     }
1948
1949     return face;
1950 }
1951
1952 void QFontEngineFT::unlockFace() const
1953 {
1954     freetype->unlock();
1955 }
1956
1957 FT_Face QFontEngineFT::non_locked_face() const
1958 {
1959     return freetype->face;
1960 }
1961
1962
1963 QFontEngineFT::QGlyphSet::QGlyphSet()
1964     : outline_drawing(false)
1965 {
1966     transformationMatrix.xx = 0x10000;
1967     transformationMatrix.yy = 0x10000;
1968     transformationMatrix.xy = 0;
1969     transformationMatrix.yx = 0;
1970     memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1971     fast_glyph_count = 0;
1972 }
1973
1974 QFontEngineFT::QGlyphSet::~QGlyphSet()
1975 {
1976     clear();
1977 }
1978
1979 void QFontEngineFT::QGlyphSet::clear()
1980 {
1981     if (fast_glyph_count > 0) {
1982         for (int i = 0; i < 256; ++i) {
1983             if (fast_glyph_data[i]) {
1984                 delete fast_glyph_data[i];
1985                 fast_glyph_data[i] = 0;
1986             }
1987         }
1988         fast_glyph_count = 0;
1989     }
1990     qDeleteAll(glyph_data);
1991     glyph_data.clear();
1992 }
1993
1994 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1995 {
1996     if (useFastGlyphData(index, subPixelPosition)) {
1997         if (fast_glyph_data[index]) {
1998             delete fast_glyph_data[index];
1999             fast_glyph_data[index] = 0;
2000             if (fast_glyph_count > 0)
2001                 --fast_glyph_count;
2002         }
2003     } else {
2004         delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2005     }
2006 }
2007
2008 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2009 {
2010     if (useFastGlyphData(index, subPixelPosition)) {
2011         if (!fast_glyph_data[index])
2012             ++fast_glyph_count;
2013         fast_glyph_data[index] = glyph;
2014     } else {
2015         glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2016     }
2017 }
2018
2019 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2020 {
2021     lockFace();
2022     bool hsubpixel = true;
2023     int vfactor = 1;
2024     int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2025     HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2026     unlockFace();
2027     return result;
2028 }
2029
2030 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2031 {
2032     if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2033         return false;
2034
2035     // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2036     // will be using it
2037     freetype->ref.ref();
2038
2039     default_load_flags = fe->default_load_flags;
2040     default_hint_style = fe->default_hint_style;
2041     antialias = fe->antialias;
2042     transform = fe->transform;
2043     embolden = fe->embolden;
2044     obliquen = fe->obliquen;
2045     subpixelType = fe->subpixelType;
2046     lcdFilterType = fe->lcdFilterType;
2047     embeddedbitmap = fe->embeddedbitmap;
2048
2049     return true;
2050 }
2051
2052 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2053 {
2054     QFontDef fontDef(this->fontDef);
2055     fontDef.pixelSize = pixelSize;
2056     QFontEngineFT *fe = new QFontEngineFT(fontDef);
2057     if (!fe->initFromFontEngine(this)) {
2058         delete fe;
2059         return 0;
2060     } else {
2061         return fe;
2062     }
2063 }
2064
2065 QT_END_NAMESPACE
2066
2067 #endif // QT_NO_FREETYPE