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