Update spec to build Qt 5.0
[profile/ivi/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 convertGRAYToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch) {
592     for (int y = 0; y < height; ++y) {
593         int readpos =  (y * src_pitch);
594         int writepos = (y * width);
595         for (int x = 0; x < width; ++x) {
596             dst[writepos + x] = (0xFF << 24) + (src[readpos + x] << 16) + (src[readpos + x] << 8) + src[readpos + x];
597         }
598     }
599 }
600
601 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
602 {
603     // convolute the bitmap with a triangle filter to get rid of color fringes
604     // If we take account for a gamma value of 2, we end up with
605     // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
606     // as this nicely sums up to 16 :)
607     int h = height;
608     while (h--) {
609         dst[0] = dst[1] = 0;
610         //
611         for (int x = 2; x < width - 2; ++x) {
612             uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
613             dst[x] = (uchar) (sum >> 4);
614         }
615         dst[width - 2] = dst[width - 1] = 0;
616         src += pitch;
617         dst += pitch;
618     }
619 }
620
621 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
622 {
623     fontDef = fd;
624     matrix.xx = 0x10000;
625     matrix.yy = 0x10000;
626     matrix.xy = 0;
627     matrix.yx = 0;
628     cache_cost = 100;
629     kerning_pairs_loaded = false;
630     transform = false;
631     embolden = false;
632     obliquen = false;
633     antialias = true;
634     freetype = 0;
635     default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
636 #ifndef Q_OS_WIN
637     default_hint_style = HintNone;
638 #else
639     default_hint_style = HintFull;
640 #endif
641     subpixelType = Subpixel_None;
642     lcdFilterType = 0;
643 #if defined(FT_LCD_FILTER_H)
644     lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
645 #endif
646     defaultFormat = Format_None;
647     embeddedbitmap = false;
648     const QByteArray env = qgetenv("QT_NO_FT_CACHE");
649     cacheEnabled = env.isEmpty() || env.toInt() == 0;
650     m_subPixelPositionCount = 4;
651 }
652
653 QFontEngineFT::~QFontEngineFT()
654 {
655     if (freetype)
656         freetype->release(face_id);
657     hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
658 }
659
660 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
661                          const QByteArray &fontData)
662 {
663     return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
664 }
665
666 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
667                          QFreetypeFace *freetypeFace)
668 {
669     freetype = freetypeFace;
670     if (!freetype) {
671         xsize = 0;
672         ysize = 0;
673         return false;
674     }
675     defaultFormat = format;
676     this->antialias = antialias;
677
678     if (!antialias)
679         glyphFormat = QFontEngineGlyphCache::Raster_Mono;
680     else if (format == Format_A8)
681         glyphFormat = QFontEngineGlyphCache::Raster_A8;
682     else if (format == Format_A32)
683         glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
684
685     face_id = faceId;
686
687     symbol = freetype->symbol_map != 0;
688     PS_FontInfoRec psrec;
689     // don't assume that type1 fonts are symbol fonts by default
690     if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
691         symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
692     }
693     // #####
694     freetype->hbFace->isSymbolFont = symbol;
695
696     lbearing = rbearing = SHRT_MIN;
697     freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
698
699     FT_Face face = lockFace();
700
701     if (FT_IS_SCALABLE(face)) {
702         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
703         if (fake_oblique) {
704 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
705             matrix.xy = 0x10000*3/10;
706             transform = true;
707 #else
708             obliquen = true;
709 #endif
710         }
711         FT_Set_Transform(face, &matrix, 0);
712         freetype->matrix = matrix;
713         // fake bold
714         if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
715             embolden = true;
716         // underline metrics
717         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
718         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
719     } else {
720         // copied from QFontEngineQPF
721         // ad hoc algorithm
722         int score = fontDef.weight * fontDef.pixelSize;
723         line_thickness = score / 700;
724         // looks better with thicker line for small pointsizes
725         if (line_thickness < 2 && score >= 1050)
726             line_thickness = 2;
727         underline_position =  ((line_thickness * 2) + 3) / 6;
728     }
729     if (line_thickness < 1)
730         line_thickness = 1;
731
732     hbFont.x_ppem  = face->size->metrics.x_ppem;
733     hbFont.y_ppem  = face->size->metrics.y_ppem;
734     hbFont.x_scale = face->size->metrics.x_scale;
735     hbFont.y_scale = face->size->metrics.y_scale;
736
737     hbFace = freetype->hbFace;
738
739     metrics = face->size->metrics;
740
741     /*
742        TrueType fonts with embedded bitmaps may have a bitmap font specific
743        ascent/descent in the EBLC table. There is no direct public API
744        to extract those values. The only way we've found is to trick freetype
745        into thinking that it's not a scalable font in FT_SelectSize so that
746        the metrics are retrieved from the bitmap strikes.
747     */
748     if (FT_IS_SCALABLE(face)) {
749         for (int i = 0; i < face->num_fixed_sizes; ++i) {
750             if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
751                 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
752
753                 FT_Select_Size(face, i);
754                 metrics.ascender = face->size->metrics.ascender;
755                 metrics.descender = face->size->metrics.descender;
756                 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
757
758                 face->face_flags |= FT_FACE_FLAG_SCALABLE;
759                 break;
760             }
761         }
762     }
763
764     fontDef.styleName = QString::fromUtf8(face->style_name);
765
766     unlockFace();
767
768     fsType = freetype->fsType();
769     return true;
770 }
771
772 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
773 {
774     default_hint_style = style;
775 }
776
777 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
778                              bool &hsubpixel, int &vfactor) const
779 {
780     int load_flags = FT_LOAD_DEFAULT | default_load_flags;
781     int load_target = default_hint_style == HintLight
782                       ? FT_LOAD_TARGET_LIGHT
783                       : FT_LOAD_TARGET_NORMAL;
784
785     if (format == Format_Mono) {
786         load_target = FT_LOAD_TARGET_MONO;
787     } else if (format == Format_A32) {
788         if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
789             if (default_hint_style == HintFull)
790                 load_target = FT_LOAD_TARGET_LCD;
791             hsubpixel = true;
792         } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
793             if (default_hint_style == HintFull)
794                 load_target = FT_LOAD_TARGET_LCD_V;
795             vfactor = 3;
796         }
797     }
798
799     if (set && set->outline_drawing)
800         load_flags = FT_LOAD_NO_BITMAP;
801
802     if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
803         load_flags |= FT_LOAD_NO_HINTING;
804     else
805         load_flags |= load_target;
806
807     return load_flags;
808 }
809
810 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
811                                                QFixed subPixelPosition,
812                                                GlyphFormat format,
813                                                bool fetchMetricsOnly) const
814 {
815 //     Q_ASSERT(freetype->lock == 1);
816
817     if (format == Format_None) {
818         if (defaultFormat != Format_None) {
819             format = defaultFormat;
820         } else {
821             format = Format_Mono;
822         }
823     }
824
825     Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
826     if (g && g->format == format && (fetchMetricsOnly || g->data))
827         return g;
828
829     QFontEngineFT::GlyphInfo info;
830
831     Q_ASSERT(format != Format_None);
832     bool hsubpixel = false;
833     int vfactor = 1;
834     int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
835
836     if (format != Format_Mono && !embeddedbitmap)
837         load_flags |= FT_LOAD_NO_BITMAP;
838
839     FT_Matrix matrix = freetype->matrix;
840     bool transform = matrix.xx != 0x10000
841                      || matrix.yy != 0x10000
842                      || matrix.xy != 0
843                      || matrix.yx != 0;
844
845     if (transform)
846         load_flags |= FT_LOAD_NO_BITMAP;
847
848     FT_Face face = freetype->face;
849
850     FT_Vector v;
851     v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
852     v.y = 0;
853     FT_Set_Transform(face, &freetype->matrix, &v);
854
855     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
856     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
857         load_flags &= ~FT_LOAD_NO_BITMAP;
858         err = FT_Load_Glyph(face, glyph, load_flags);
859     }
860     if (err == FT_Err_Too_Few_Arguments) {
861         // this is an error in the bytecode interpreter, just try to run without it
862         load_flags |= FT_LOAD_FORCE_AUTOHINT;
863         err = FT_Load_Glyph(face, glyph, load_flags);
864     }
865     if (err != FT_Err_Ok)
866         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
867
868     FT_GlyphSlot slot = face->glyph;
869
870     if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
871     if (obliquen) {
872         Q_FT_GLYPHSLOT_OBLIQUE(slot);
873
874         // While Embolden alters the metrics of the slot, oblique does not, so we need
875         // to fix this ourselves.
876         transform = true;
877         FT_Matrix m;
878         m.xx = 0x10000;
879         m.yx = 0x0;
880         m.xy = 0x6000;
881         m.yy = 0x10000;
882
883         FT_Matrix_Multiply(&m, &matrix);
884     }
885
886     FT_Library library = qt_getFreetype();
887
888     info.xOff = TRUNC(ROUND(slot->advance.x));
889     info.yOff = 0;
890
891     if ((set && set->outline_drawing) || fetchMetricsOnly) {
892         // If the advance doesn't fit in signed char, don't cache it
893         if (qAbs(info.xOff) >= 128)
894             return 0;
895         g = new Glyph;
896         g->data = 0;
897         g->linearAdvance = slot->linearHoriAdvance >> 10;
898         int left  = FLOOR(slot->metrics.horiBearingX);
899         int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
900         int top    = CEIL(slot->metrics.horiBearingY);
901         int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
902         g->width = TRUNC(right-left);
903         g->height = TRUNC(top-bottom);
904         g->x = TRUNC(left);
905         g->y = TRUNC(top);
906         g->advance = TRUNC(ROUND(slot->advance.x));
907         g->format = format;
908
909         if (set)
910             set->setGlyph(glyph, subPixelPosition, g);
911
912         return g;
913     }
914
915     uchar *glyph_buffer = 0;
916     int glyph_buffer_size = 0;
917 #if defined(QT_USE_FREETYPE_LCDFILTER)
918     bool useFreetypeRenderGlyph = false;
919     if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
920         err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
921         if (err == FT_Err_Ok)
922             useFreetypeRenderGlyph = true;
923     }
924
925     if (useFreetypeRenderGlyph) {
926         err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
927
928         if (err != FT_Err_Ok)
929             qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
930
931         FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
932
933         info.height = slot->bitmap.rows / vfactor;
934         info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
935         info.x = -slot->bitmap_left;
936         info.y = slot->bitmap_top;
937
938         glyph_buffer_size = info.width * info.height * 4;
939         glyph_buffer = new uchar[glyph_buffer_size];
940
941         if (hsubpixel)
942             convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
943         else if (vfactor != 1)
944             convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
945     } else
946 #endif
947     {
948     int left  = slot->metrics.horiBearingX;
949     int right = slot->metrics.horiBearingX + slot->metrics.width;
950     int top    = slot->metrics.horiBearingY;
951     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
952     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
953         int l, r, t, b;
954         FT_Vector vector;
955         vector.x = left;
956         vector.y = top;
957         FT_Vector_Transform(&vector, &matrix);
958         l = r = vector.x;
959         t = b = vector.y;
960         vector.x = right;
961         vector.y = top;
962         FT_Vector_Transform(&vector, &matrix);
963         if (l > vector.x) l = vector.x;
964         if (r < vector.x) r = vector.x;
965         if (t < vector.y) t = vector.y;
966         if (b > vector.y) b = vector.y;
967         vector.x = right;
968         vector.y = bottom;
969         FT_Vector_Transform(&vector, &matrix);
970         if (l > vector.x) l = vector.x;
971         if (r < vector.x) r = vector.x;
972         if (t < vector.y) t = vector.y;
973         if (b > vector.y) b = vector.y;
974         vector.x = left;
975         vector.y = bottom;
976         FT_Vector_Transform(&vector, &matrix);
977         if (l > vector.x) l = vector.x;
978         if (r < vector.x) r = vector.x;
979         if (t < vector.y) t = vector.y;
980         if (b > vector.y) b = vector.y;
981         left = l;
982         right = r;
983         top = t;
984         bottom = b;
985     }
986     left = FLOOR(left);
987     right = CEIL(right);
988     bottom = FLOOR(bottom);
989     top = CEIL(top);
990
991     int hpixels = TRUNC(right - left);
992     // subpixel position requires one more pixel
993     if (subPixelPosition > 0 && format != Format_Mono)
994         hpixels++;
995
996     if (hsubpixel)
997         hpixels = hpixels*3 + 8;
998     info.width = hpixels;
999     info.height = TRUNC(top - bottom);
1000     info.x = -TRUNC(left);
1001     info.y = TRUNC(top);
1002     if (hsubpixel) {
1003         info.width /= 3;
1004         info.x += 1;
1005     }
1006
1007     bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
1008                         || ((uchar)(info.width) != info.width)
1009                         || ((uchar)(info.height) != info.height)
1010                         || ((signed char)(info.x) != info.x)
1011                         || ((signed char)(info.y) != info.y)
1012                         || ((signed char)(info.xOff) != info.xOff));
1013
1014     if (large_glyph) {
1015         delete [] glyph_buffer;
1016         return 0;
1017     }
1018
1019     int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1020                  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1021     glyph_buffer_size = pitch * info.height;
1022     glyph_buffer = new uchar[glyph_buffer_size];
1023
1024     if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1025         FT_Bitmap bitmap;
1026         bitmap.rows = info.height*vfactor;
1027         bitmap.width = hpixels;
1028         bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1029         if (!hsubpixel && vfactor == 1 && format != Format_A32)
1030             bitmap.buffer = glyph_buffer;
1031         else
1032             bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1033         memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1034         bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1035         FT_Matrix matrix;
1036         matrix.xx = (hsubpixel ? 3 : 1) << 16;
1037         matrix.yy = vfactor << 16;
1038         matrix.yx = matrix.xy = 0;
1039
1040         FT_Outline_Transform(&slot->outline, &matrix);
1041         FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1042         FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1043         if (hsubpixel) {
1044             Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1045             Q_ASSERT(antialias);
1046             uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1047             bool useLegacyLcdFilter = false;
1048 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1049             useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1050 #endif
1051             uchar *buffer = bitmap.buffer;
1052             if (!useLegacyLcdFilter) {
1053                 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1054                 buffer = convoluted;
1055             }
1056             convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1057             delete [] convoluted;
1058         } else if (vfactor != 1) {
1059             convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1060         } else if (format == Format_A32 && bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
1061             convertGRAYToARGB(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch);
1062         }
1063
1064         if (bitmap.buffer != glyph_buffer)
1065             delete [] bitmap.buffer;
1066     } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1067         Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1068         uchar *src = slot->bitmap.buffer;
1069         uchar *dst = glyph_buffer;
1070         int h = slot->bitmap.rows;
1071         if (format == Format_Mono) {
1072             int bytes = ((info.width + 7) & ~7) >> 3;
1073             while (h--) {
1074                 memcpy (dst, src, bytes);
1075                 dst += pitch;
1076                 src += slot->bitmap.pitch;
1077             }
1078         } else {
1079             if (hsubpixel) {
1080                 while (h--) {
1081                     uint *dd = (uint *)dst;
1082                     *dd++ = 0;
1083                     for (int x = 0; x < slot->bitmap.width; x++) {
1084                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1085                         *dd++ = a;
1086                     }
1087                     *dd++ = 0;
1088                     dst += pitch;
1089                     src += slot->bitmap.pitch;
1090                 }
1091             } else if (vfactor != 1) {
1092                 while (h--) {
1093                     uint *dd = (uint *)dst;
1094                     for (int x = 0; x < slot->bitmap.width; x++) {
1095                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1096                         *dd++ = a;
1097                     }
1098                     dst += pitch;
1099                     src += slot->bitmap.pitch;
1100                 }
1101             } else {
1102                 while (h--) {
1103                     for (int x = 0; x < slot->bitmap.width; x++) {
1104                         unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1105                         dst[x] = a;
1106                     }
1107                     dst += pitch;
1108                     src += slot->bitmap.pitch;
1109                 }
1110             }
1111         }
1112     } else {
1113         qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1114         delete [] glyph_buffer;
1115         return 0;
1116     }
1117     }
1118
1119
1120     if (!g) {
1121         g = new Glyph;
1122         g->data = 0;
1123     }
1124
1125     g->linearAdvance = slot->linearHoriAdvance >> 10;
1126     g->width = info.width;
1127     g->height = info.height;
1128     g->x = -info.x;
1129     g->y = info.y;
1130     g->advance = info.xOff;
1131     g->format = format;
1132     delete [] g->data;
1133     g->data = glyph_buffer;
1134
1135     if (set)
1136         set->setGlyph(glyph, subPixelPosition, g);
1137
1138     return g;
1139 }
1140
1141 QFontEngine::FaceId QFontEngineFT::faceId() const
1142 {
1143     return face_id;
1144 }
1145
1146 QFontEngine::Properties QFontEngineFT::properties() const
1147 {
1148     Properties p = freetype->properties();
1149     if (p.postscriptName.isEmpty()) {
1150         p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1151     }
1152
1153     return freetype->properties();
1154 }
1155
1156 QFixed QFontEngineFT::emSquareSize() const
1157 {
1158     if (FT_IS_SCALABLE(freetype->face))
1159         return freetype->face->units_per_EM;
1160     else
1161         return freetype->face->size->metrics.y_ppem;
1162 }
1163
1164 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1165 {
1166     return freetype->getSfntTable(tag, buffer, length);
1167 }
1168
1169 int QFontEngineFT::synthesized() const
1170 {
1171     int s = 0;
1172     if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1173         s = SynthesizedItalic;
1174     if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1175         s |= SynthesizedBold;
1176     if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1177         s |= SynthesizedStretch;
1178     return s;
1179 }
1180
1181 QFixed QFontEngineFT::ascent() const
1182 {
1183     return QFixed::fromFixed(metrics.ascender);
1184 }
1185
1186 QFixed QFontEngineFT::descent() const
1187 {
1188     return QFixed::fromFixed(-metrics.descender);
1189 }
1190
1191 QFixed QFontEngineFT::leading() const
1192 {
1193     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1194 }
1195
1196 QFixed QFontEngineFT::xHeight() const
1197 {
1198     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1199     if (os2 && os2->sxHeight) {
1200         lockFace();
1201         QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1202         unlockFace();
1203         return answer;
1204     }
1205     return QFontEngine::xHeight();
1206 }
1207
1208 QFixed QFontEngineFT::averageCharWidth() const
1209 {
1210     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1211     if (os2 && os2->xAvgCharWidth) {
1212         lockFace();
1213         QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1214         unlockFace();
1215         return answer;
1216     }
1217     return QFontEngine::averageCharWidth();
1218 }
1219
1220 qreal QFontEngineFT::maxCharWidth() const
1221 {
1222     return metrics.max_advance >> 6;
1223 }
1224
1225 static const ushort char_table[] = {
1226         40,
1227         67,
1228         70,
1229         75,
1230         86,
1231         88,
1232         89,
1233         91,
1234         95,
1235         102,
1236         114,
1237         124,
1238         127,
1239         205,
1240         645,
1241         884,
1242         922,
1243         1070,
1244         12386
1245 };
1246
1247 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1248
1249
1250 qreal QFontEngineFT::minLeftBearing() const
1251 {
1252     if (lbearing == SHRT_MIN)
1253         (void) minRightBearing(); // calculates both
1254     return lbearing.toReal();
1255 }
1256
1257 qreal QFontEngineFT::minRightBearing() const
1258 {
1259     if (rbearing == SHRT_MIN) {
1260         lbearing = rbearing = 0;
1261         const QChar *ch = (const QChar *)(const void*)char_table;
1262         QGlyphLayoutArray<char_table_entries> glyphs;
1263         int ng = char_table_entries;
1264         stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly);
1265         while (--ng) {
1266             if (glyphs.glyphs[ng]) {
1267                 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1268                 lbearing = qMin(lbearing, gi.x);
1269                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1270             }
1271         }
1272     }
1273     return rbearing.toReal();
1274 }
1275
1276 QFixed QFontEngineFT::lineThickness() const
1277 {
1278     return line_thickness;
1279 }
1280
1281 QFixed QFontEngineFT::underlinePosition() const
1282 {
1283     return underline_position;
1284 }
1285
1286 void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
1287 {
1288     if (!kerning_pairs_loaded) {
1289         kerning_pairs_loaded = true;
1290         lockFace();
1291         if (freetype->face->size->metrics.x_ppem != 0) {
1292             QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1293             unlockFace();
1294             const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1295         } else {
1296             unlockFace();
1297         }
1298     }
1299     QFontEngine::doKerning(g, flags);
1300 }
1301
1302 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1303 {
1304     if (matrix.type() > QTransform::TxShear)
1305         return 0;
1306
1307     // FT_Set_Transform only supports scalable fonts
1308     if (!FT_IS_SCALABLE(freetype->face))
1309         return 0;
1310
1311     FT_Matrix m;
1312     m.xx = FT_Fixed(matrix.m11() * 65536);
1313     m.xy = FT_Fixed(-matrix.m21() * 65536);
1314     m.yx = FT_Fixed(-matrix.m12() * 65536);
1315     m.yy = FT_Fixed(matrix.m22() * 65536);
1316
1317     QGlyphSet *gs = 0;
1318
1319     for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1320         const QGlyphSet &g = transformedGlyphSets.at(i);
1321         if (g.transformationMatrix.xx == m.xx
1322             && g.transformationMatrix.xy == m.xy
1323             && g.transformationMatrix.yx == m.yx
1324             && g.transformationMatrix.yy == m.yy) {
1325
1326             // found a match, move it to the front
1327             transformedGlyphSets.move(i, 0);
1328             gs = &transformedGlyphSets[0];
1329             break;
1330         }
1331     }
1332
1333     if (!gs) {
1334         // don't try to load huge fonts
1335         bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1336         if (draw_as_outline)
1337             return 0;
1338
1339         // don't cache more than 10 transformations
1340         if (transformedGlyphSets.count() >= 10) {
1341             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1342         } else {
1343             transformedGlyphSets.prepend(QGlyphSet());
1344         }
1345         gs = &transformedGlyphSets[0];
1346         gs->clear();
1347         gs->transformationMatrix = m;
1348         gs->outline_drawing = draw_as_outline;
1349     }
1350
1351     return gs;
1352 }
1353
1354 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1355                                const QFixedPoint *positions,
1356                                GlyphFormat format)
1357 {
1358     FT_Face face = 0;
1359
1360     for (int i = 0; i < num_glyphs; ++i) {
1361         QFixed spp = subPixelPositionForX(positions[i].x);
1362         Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1363         if (glyph == 0 || glyph->format != format) {
1364             if (!face) {
1365                 face = lockFace();
1366                 FT_Matrix m = matrix;
1367                 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1368                 FT_Set_Transform(face, &m, 0);
1369                 freetype->matrix = m;
1370             }
1371             if (!loadGlyph(gs, glyphs[i], spp, format)) {
1372                 unlockFace();
1373                 return false;
1374             }
1375         }
1376     }
1377
1378     if (face)
1379         unlockFace();
1380
1381     return true;
1382 }
1383
1384 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1385 {
1386     FT_Face face = lockFace(Unscaled);
1387     FT_Set_Transform(face, 0, 0);
1388     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1389
1390     int left  = face->glyph->metrics.horiBearingX;
1391     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1392     int top    = face->glyph->metrics.horiBearingY;
1393     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1394
1395     QFixedPoint p;
1396     p.x = 0;
1397     p.y = 0;
1398
1399     metrics->width = QFixed::fromFixed(right-left);
1400     metrics->height = QFixed::fromFixed(top-bottom);
1401     metrics->x = QFixed::fromFixed(left);
1402     metrics->y = QFixed::fromFixed(-top);
1403     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1404
1405     if (!FT_IS_SCALABLE(freetype->face))
1406         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1407     else
1408         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1409
1410     FT_Set_Transform(face, &freetype->matrix, 0);
1411     unlockFace();
1412 }
1413
1414 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1415 {
1416     uint ucs4 = str[i].unicode();
1417     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1418         ++i;
1419         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1420     }
1421     return ucs4;
1422 }
1423
1424 bool QFontEngineFT::canRender(const QChar *string, int len)
1425 {
1426     FT_Face face = freetype->face;
1427     {
1428         for ( int i = 0; i < len; i++ ) {
1429             unsigned int uc = getChar(string, i, len);
1430             if (!FT_Get_Char_Index(face, uc))
1431                     return false;
1432         }
1433     }
1434     return true;
1435 }
1436
1437 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1438 {
1439     if (!glyphs.numGlyphs)
1440         return;
1441
1442     if (FT_IS_SCALABLE(freetype->face)) {
1443         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1444     } else {
1445         QVarLengthArray<QFixedPoint> positions;
1446         QVarLengthArray<glyph_t> positioned_glyphs;
1447         QTransform matrix;
1448         matrix.translate(x, y);
1449         getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1450
1451         FT_Face face = lockFace(Unscaled);
1452         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1453             FT_UInt glyph = positioned_glyphs[gl];
1454             FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1455             freetype->addBitmapToPath(face->glyph, positions[gl], path);
1456         }
1457         unlockFace();
1458     }
1459 }
1460
1461 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1462                                     QPainterPath *path, QTextItem::RenderFlags)
1463 {
1464     FT_Face face = lockFace(Unscaled);
1465
1466     for (int gl = 0; gl < numGlyphs; gl++) {
1467         FT_UInt glyph = glyphs[gl];
1468
1469         FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1470
1471         FT_GlyphSlot g = face->glyph;
1472         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1473             continue;
1474         if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1475         if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1476         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1477     }
1478     unlockFace();
1479 }
1480
1481 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1482                                  QFontEngine::ShaperFlags flags) const
1483 {
1484     if (*nglyphs < len) {
1485         *nglyphs = len;
1486         return false;
1487     }
1488
1489     bool mirrored = flags & QFontEngine::RightToLeft;
1490     int glyph_pos = 0;
1491     if (freetype->symbol_map) {
1492         FT_Face face = freetype->face;
1493         for ( int i = 0; i < len; ++i ) {
1494             unsigned int uc = getChar(str, i, len);
1495             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1496             if ( !glyphs->glyphs[glyph_pos] ) {
1497                 // Symbol fonts can have more than one CMAPs, FreeType should take the
1498                 // correct one for us by default, so we always try FT_Get_Char_Index
1499                 // first. If it didn't work (returns 0), we will explicitly set the
1500                 // CMAP to symbol font one and try again. symbol_map is not always the
1501                 // correct one because in certain fonts like Wingdings symbol_map only
1502                 // contains PUA codepoints instead of the common ones.
1503                 glyph_t glyph = FT_Get_Char_Index(face, uc);
1504                 // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
1505                 // while we usually want to render them as space
1506                 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1507                     uc = 0x20;
1508                     glyph = FT_Get_Char_Index(face, uc);
1509                 }
1510                 if (!glyph) {
1511                     FT_Set_Charmap(face, freetype->symbol_map);
1512                     glyph = FT_Get_Char_Index(face, uc);
1513                     FT_Set_Charmap(face, freetype->unicode_map);
1514                 }
1515                 glyphs->glyphs[glyph_pos] = glyph;
1516                 if (uc < QFreetypeFace::cmapCacheSize)
1517                     freetype->cmapCache[uc] = glyph;
1518             }
1519             ++glyph_pos;
1520         }
1521     } else {
1522         FT_Face face = freetype->face;
1523         for (int i = 0; i < len; ++i) {
1524             unsigned int uc = getChar(str, i, len);
1525             if (mirrored)
1526                 uc = QChar::mirroredChar(uc);
1527             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1528             if (!glyphs->glyphs[glyph_pos]) {
1529                 {
1530                 redo:
1531                     glyph_t glyph = FT_Get_Char_Index(face, uc);
1532                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1533                         uc = 0x20;
1534                         goto redo;
1535                     }
1536                     glyphs->glyphs[glyph_pos] = glyph;
1537                     if (uc < QFreetypeFace::cmapCacheSize)
1538                         freetype->cmapCache[uc] = glyph;
1539                 }
1540             }
1541             ++glyph_pos;
1542         }
1543     }
1544
1545     *nglyphs = glyph_pos;
1546     glyphs->numGlyphs = glyph_pos;
1547
1548     if (!(flags & GlyphIndicesOnly))
1549         recalcAdvances(glyphs, flags);
1550
1551     return true;
1552 }
1553
1554 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1555 {
1556     FT_Face face = 0;
1557     bool design = (default_hint_style == HintNone ||
1558                    default_hint_style == HintLight ||
1559                    (flags & DesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1560     for (int i = 0; i < glyphs->numGlyphs; i++) {
1561         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1562         // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
1563         GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
1564         if (g && g->format == acceptableFormat) {
1565             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1566         } else {
1567             if (!face)
1568                 face = lockFace();
1569             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1570             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1571                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1572         }
1573         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1574             glyphs->advances_x[i] = glyphs->advances_x[i].round();
1575         glyphs->advances_y[i] = 0;
1576     }
1577     if (face)
1578         unlockFace();
1579 }
1580
1581 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1582 {
1583     FT_Face face = 0;
1584
1585     glyph_metrics_t overall;
1586     // initialize with line height, we get the same behaviour on all platforms
1587     overall.y = -ascent();
1588     overall.height = ascent() + descent();
1589
1590     QFixed ymax = 0;
1591     QFixed xmax = 0;
1592     for (int i = 0; i < glyphs.numGlyphs; i++) {
1593         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1594         if (!g) {
1595             if (!face)
1596                 face = lockFace();
1597             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1598         }
1599         if (g) {
1600             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1601             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1602             overall.x = qMin(overall.x, x);
1603             overall.y = qMin(overall.y, y);
1604             xmax = qMax(xmax, x + g->width);
1605             ymax = qMax(ymax, y + g->height);
1606             overall.xoff += g->advance;
1607         } else {
1608             int left  = FLOOR(face->glyph->metrics.horiBearingX);
1609             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1610             int top    = CEIL(face->glyph->metrics.horiBearingY);
1611             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1612
1613             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1614             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1615             overall.x = qMin(overall.x, x);
1616             overall.y = qMin(overall.y, y);
1617             xmax = qMax(xmax, x + TRUNC(right - left));
1618             ymax = qMax(ymax, y + TRUNC(top - bottom));
1619             overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1620         }
1621     }
1622     overall.height = qMax(overall.height, ymax - overall.y);
1623     overall.width = xmax - overall.x;
1624
1625     if (face)
1626         unlockFace();
1627
1628     return overall;
1629 }
1630
1631 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1632 {
1633     FT_Face face = 0;
1634     glyph_metrics_t overall;
1635     Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1636     if (!g) {
1637         face = lockFace();
1638         g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1639     }
1640     if (g) {
1641         overall.x = g->x;
1642         overall.y = -g->y;
1643         overall.width = g->width;
1644         overall.height = g->height;
1645         overall.xoff = g->advance;
1646         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1647             overall.xoff = overall.xoff.round();
1648     } else {
1649         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1650         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1651         int top    = CEIL(face->glyph->metrics.horiBearingY);
1652         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1653
1654         overall.width = TRUNC(right-left);
1655         overall.height = TRUNC(top-bottom);
1656         overall.x = TRUNC(left);
1657         overall.y = -TRUNC(top);
1658         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1659     }
1660     if (face)
1661         unlockFace();
1662     return overall;
1663 }
1664
1665 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1666 {
1667     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1668 }
1669
1670 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1671 {
1672     FT_Matrix m;
1673
1674     m.xx = FT_Fixed(matrix.m11() * 65536);
1675     m.xy = FT_Fixed(-matrix.m21() * 65536);
1676     m.yx = FT_Fixed(-matrix.m12() * 65536);
1677     m.yy = FT_Fixed(matrix.m22() * 65536);
1678
1679     return m;
1680 }
1681
1682 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1683 {
1684     FT_Face face = 0;
1685     glyph_metrics_t overall;
1686     QGlyphSet *glyphSet = 0;
1687     FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1688     if (cacheEnabled) {
1689         if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1690             // TODO move everything here to a method of its own to access glyphSets
1691             // to be shared with a new method that will replace loadTransformedGlyphSet()
1692             for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1693                 const QGlyphSet &g = transformedGlyphSets.at(i);
1694                 if (g.transformationMatrix.xx == ftMatrix.xx
1695                     && g.transformationMatrix.xy == ftMatrix.xy
1696                     && g.transformationMatrix.yx == ftMatrix.yx
1697                     && g.transformationMatrix.yy == ftMatrix.yy) {
1698
1699                     // found a match, move it to the front
1700                     transformedGlyphSets.move(i, 0);
1701                     glyphSet = &transformedGlyphSets[0];
1702                     break;
1703                 }
1704             }
1705
1706             if (!glyphSet) {
1707                 // don't cache more than 10 transformations
1708                 if (transformedGlyphSets.count() >= 10) {
1709                     transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1710                 } else {
1711                     transformedGlyphSets.prepend(QGlyphSet());
1712                 }
1713                 glyphSet = &transformedGlyphSets[0];
1714                 glyphSet->clear();
1715                 glyphSet->transformationMatrix = ftMatrix;
1716             }
1717             Q_ASSERT(glyphSet);
1718         } else {
1719             glyphSet = &defaultGlyphSet;
1720         }
1721     }
1722     Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1723     if (!g || g->format != format) {
1724         face = lockFace();
1725         FT_Matrix m = this->matrix;
1726         FT_Matrix_Multiply(&ftMatrix, &m);
1727         freetype->matrix = m;
1728         g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1729     }
1730
1731     if (g) {
1732         overall.x = g->x;
1733         overall.y = -g->y;
1734         overall.width = g->width;
1735         overall.height = g->height;
1736         overall.xoff = g->advance;
1737     } else {
1738         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1739         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1740         int top    = CEIL(face->glyph->metrics.horiBearingY);
1741         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1742
1743         overall.width = TRUNC(right-left);
1744         overall.height = TRUNC(top-bottom);
1745         overall.x = TRUNC(left);
1746         overall.y = -TRUNC(top);
1747         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1748     }
1749     if (face)
1750         unlockFace();
1751     return overall;
1752 }
1753
1754 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1755                                               QFontEngine::GlyphFormat neededFormat,
1756                                               const QTransform &t, QPoint *offset)
1757 {
1758     Q_ASSERT(currentlyLockedAlphaMap.isNull());
1759     lockFace();
1760
1761     if (isBitmapFont())
1762         neededFormat = Format_Mono;
1763     else if (neededFormat == Format_None && defaultFormat != Format_None)
1764         neededFormat = defaultFormat;
1765     else if (neededFormat == Format_None)
1766         neededFormat = Format_A8;
1767
1768     QImage::Format format;
1769     switch (neededFormat) {
1770     case Format_Mono:
1771         format = QImage::Format_Mono;
1772         break;
1773     case Format_A8:
1774         format = QImage::Format_Indexed8;
1775         break;
1776     case Format_A32:
1777         format = QImage::Format_ARGB32;
1778         break;
1779     default:
1780         Q_ASSERT(false);
1781         format = QImage::Format_Invalid;
1782     };
1783
1784     QFontEngineFT::Glyph *glyph;
1785     if (cacheEnabled) {
1786         QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1787         QFontEngine::HintStyle hintStyle = default_hint_style;
1788         if (t.type() >= QTransform::TxScale) {
1789             // disable hinting if the glyphs are transformed
1790             default_hint_style = HintNone;
1791             if (t.isAffine())
1792                 gset = loadTransformedGlyphSet(t);
1793             else
1794                 gset = 0;
1795         }
1796
1797         if (gset) {
1798             FT_Matrix m = matrix;
1799             FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1800             FT_Set_Transform(freetype->face, &m, 0);
1801             freetype->matrix = m;
1802         }
1803
1804         if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1805                                                          neededFormat)) {
1806             default_hint_style = hintStyle;
1807             return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1808                                                        offset);
1809         }
1810         default_hint_style = hintStyle;
1811
1812         glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1813     } else {
1814         FT_Matrix m = matrix;
1815         FT_Matrix extra = QTransformToFTMatrix(t);
1816         FT_Matrix_Multiply(&extra, &m);
1817         FT_Set_Transform(freetype->face, &m, 0);
1818         freetype->matrix = m;
1819         glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1820     }
1821
1822     if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1823         unlockFace();
1824         return 0;
1825     }
1826
1827     int pitch;
1828     switch (neededFormat) {
1829     case Format_Mono:
1830         pitch = ((glyph->width + 31) & ~31) >> 3;
1831         break;
1832     case Format_A8:
1833         pitch = (glyph->width + 3) & ~3;
1834         break;
1835     case Format_A32:
1836         pitch = glyph->width * 4;
1837         break;
1838     default:
1839         Q_ASSERT(false);
1840         pitch = 0;
1841     };
1842
1843     if (offset != 0)
1844         *offset = QPoint(glyph->x, -glyph->y);
1845
1846     currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1847     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1848
1849     QImageData *data = currentlyLockedAlphaMap.data_ptr();
1850     data->is_locked = true;
1851
1852     return &currentlyLockedAlphaMap;
1853 }
1854
1855 void QFontEngineFT::unlockAlphaMapForGlyph()
1856 {
1857     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1858     unlockFace();
1859     currentlyLockedAlphaMap = QImage();
1860 }
1861
1862 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1863 {
1864     return defaultGlyphSet.outline_drawing ? 0 :
1865             loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1866 }
1867
1868 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1869 {
1870     lockFace();
1871
1872     Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1873     if (!glyph || !glyph->data) {
1874         unlockFace();
1875         return QFontEngine::alphaMapForGlyph(g);
1876     }
1877
1878     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1879
1880     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1881     if (antialias) {
1882         QVector<QRgb> colors(256);
1883         for (int i=0; i<256; ++i)
1884             colors[i] = qRgba(0, 0, 0, i);
1885         img.setColorTable(colors);
1886     } else {
1887         QVector<QRgb> colors(2);
1888         colors[0] = qRgba(0, 0, 0, 0);
1889         colors[1] = qRgba(0, 0, 0, 255);
1890         img.setColorTable(colors);
1891     }
1892     Q_ASSERT(img.bytesPerLine() == pitch);
1893     if (glyph->width) {
1894         for (int y = 0; y < glyph->height; ++y)
1895             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1896     }
1897     unlockFace();
1898
1899     return img;
1900 }
1901
1902 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1903 {
1904     if (t.type() > QTransform::TxTranslate)
1905         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1906
1907     lockFace();
1908
1909     Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1910     if (!glyph || !glyph->data) {
1911         unlockFace();
1912         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1913     }
1914
1915     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1916     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1917     unlockFace();
1918
1919     return img;
1920 }
1921
1922 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1923 {
1924     defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1925 }
1926
1927 int QFontEngineFT::glyphCount() const
1928 {
1929     int count = 0;
1930     FT_Face face = lockFace();
1931     if (face) {
1932         count = face->num_glyphs;
1933         unlockFace();
1934     }
1935     return count;
1936 }
1937
1938 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1939 {
1940     freetype->lock();
1941     FT_Face face = freetype->face;
1942     if (scale == Unscaled) {
1943         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1944         freetype->xsize = face->units_per_EM << 6;
1945         freetype->ysize = face->units_per_EM << 6;
1946     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1947         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1948         freetype->xsize = xsize;
1949         freetype->ysize = ysize;
1950     }
1951     if (freetype->matrix.xx != matrix.xx ||
1952         freetype->matrix.yy != matrix.yy ||
1953         freetype->matrix.xy != matrix.xy ||
1954         freetype->matrix.yx != matrix.yx) {
1955         freetype->matrix = matrix;
1956         FT_Set_Transform(face, &freetype->matrix, 0);
1957     }
1958
1959     return face;
1960 }
1961
1962 void QFontEngineFT::unlockFace() const
1963 {
1964     freetype->unlock();
1965 }
1966
1967 FT_Face QFontEngineFT::non_locked_face() const
1968 {
1969     return freetype->face;
1970 }
1971
1972
1973 QFontEngineFT::QGlyphSet::QGlyphSet()
1974     : outline_drawing(false)
1975 {
1976     transformationMatrix.xx = 0x10000;
1977     transformationMatrix.yy = 0x10000;
1978     transformationMatrix.xy = 0;
1979     transformationMatrix.yx = 0;
1980     memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1981     fast_glyph_count = 0;
1982 }
1983
1984 QFontEngineFT::QGlyphSet::~QGlyphSet()
1985 {
1986     clear();
1987 }
1988
1989 void QFontEngineFT::QGlyphSet::clear()
1990 {
1991     if (fast_glyph_count > 0) {
1992         for (int i = 0; i < 256; ++i) {
1993             if (fast_glyph_data[i]) {
1994                 delete fast_glyph_data[i];
1995                 fast_glyph_data[i] = 0;
1996             }
1997         }
1998         fast_glyph_count = 0;
1999     }
2000     qDeleteAll(glyph_data);
2001     glyph_data.clear();
2002 }
2003
2004 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2005 {
2006     if (useFastGlyphData(index, subPixelPosition)) {
2007         if (fast_glyph_data[index]) {
2008             delete fast_glyph_data[index];
2009             fast_glyph_data[index] = 0;
2010             if (fast_glyph_count > 0)
2011                 --fast_glyph_count;
2012         }
2013     } else {
2014         delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2015     }
2016 }
2017
2018 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2019 {
2020     if (useFastGlyphData(index, subPixelPosition)) {
2021         if (!fast_glyph_data[index])
2022             ++fast_glyph_count;
2023         fast_glyph_data[index] = glyph;
2024     } else {
2025         glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2026     }
2027 }
2028
2029 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2030 {
2031     lockFace();
2032     bool hsubpixel = true;
2033     int vfactor = 1;
2034     int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2035     HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2036     unlockFace();
2037     return result;
2038 }
2039
2040 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2041 {
2042     if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2043         return false;
2044
2045     // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2046     // will be using it
2047     freetype->ref.ref();
2048
2049     default_load_flags = fe->default_load_flags;
2050     default_hint_style = fe->default_hint_style;
2051     antialias = fe->antialias;
2052     transform = fe->transform;
2053     embolden = fe->embolden;
2054     obliquen = fe->obliquen;
2055     subpixelType = fe->subpixelType;
2056     lcdFilterType = fe->lcdFilterType;
2057     embeddedbitmap = fe->embeddedbitmap;
2058
2059     return true;
2060 }
2061
2062 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2063 {
2064     QFontDef fontDef(this->fontDef);
2065     fontDef.pixelSize = pixelSize;
2066     QFontEngineFT *fe = new QFontEngineFT(fontDef);
2067     if (!fe->initFromFontEngine(this)) {
2068         delete fe;
2069         return 0;
2070     } else {
2071         return fe;
2072     }
2073 }
2074
2075 QT_END_NAMESPACE
2076
2077 #endif // QT_NO_FREETYPE