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