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