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