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