Don't render glyph with FT with fetchMetricsOnly
[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     return QFixed::fromFixed(-metrics.descender);
1177 }
1178
1179 QFixed QFontEngineFT::leading() const
1180 {
1181     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1182 }
1183
1184 QFixed QFontEngineFT::xHeight() const
1185 {
1186     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1187     if (os2 && os2->sxHeight) {
1188         lockFace();
1189         QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1190         unlockFace();
1191         return answer;
1192     }
1193     return QFontEngine::xHeight();
1194 }
1195
1196 QFixed QFontEngineFT::averageCharWidth() const
1197 {
1198     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1199     if (os2 && os2->xAvgCharWidth) {
1200         lockFace();
1201         QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1202         unlockFace();
1203         return answer;
1204     }
1205     return QFontEngine::averageCharWidth();
1206 }
1207
1208 qreal QFontEngineFT::maxCharWidth() const
1209 {
1210     return metrics.max_advance >> 6;
1211 }
1212
1213 static const ushort char_table[] = {
1214         40,
1215         67,
1216         70,
1217         75,
1218         86,
1219         88,
1220         89,
1221         91,
1222         95,
1223         102,
1224         114,
1225         124,
1226         127,
1227         205,
1228         645,
1229         884,
1230         922,
1231         1070,
1232         12386
1233 };
1234
1235 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1236
1237
1238 qreal QFontEngineFT::minLeftBearing() const
1239 {
1240     if (lbearing == SHRT_MIN)
1241         (void) minRightBearing(); // calculates both
1242     return lbearing.toReal();
1243 }
1244
1245 qreal QFontEngineFT::minRightBearing() const
1246 {
1247     if (rbearing == SHRT_MIN) {
1248         lbearing = rbearing = 0;
1249         const QChar *ch = (const QChar *)(const void*)char_table;
1250         QGlyphLayoutArray<char_table_entries> glyphs;
1251         int ng = char_table_entries;
1252         stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1253         while (--ng) {
1254             if (glyphs.glyphs[ng]) {
1255                 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1256                 lbearing = qMin(lbearing, gi.x);
1257                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1258             }
1259         }
1260     }
1261     return rbearing.toReal();
1262 }
1263
1264 QFixed QFontEngineFT::lineThickness() const
1265 {
1266     return line_thickness;
1267 }
1268
1269 QFixed QFontEngineFT::underlinePosition() const
1270 {
1271     return underline_position;
1272 }
1273
1274 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1275 {
1276     if (!kerning_pairs_loaded) {
1277         kerning_pairs_loaded = true;
1278         lockFace();
1279         if (freetype->face->size->metrics.x_ppem != 0) {
1280             QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1281             unlockFace();
1282             const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1283         } else {
1284             unlockFace();
1285         }
1286     }
1287     QFontEngine::doKerning(g, flags);
1288 }
1289
1290 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1291 {
1292     if (matrix.type() > QTransform::TxShear)
1293         return 0;
1294
1295     // FT_Set_Transform only supports scalable fonts
1296     if (!FT_IS_SCALABLE(freetype->face))
1297         return 0;
1298
1299     FT_Matrix m;
1300     m.xx = FT_Fixed(matrix.m11() * 65536);
1301     m.xy = FT_Fixed(-matrix.m21() * 65536);
1302     m.yx = FT_Fixed(-matrix.m12() * 65536);
1303     m.yy = FT_Fixed(matrix.m22() * 65536);
1304
1305     QGlyphSet *gs = 0;
1306
1307     for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1308         const QGlyphSet &g = transformedGlyphSets.at(i);
1309         if (g.transformationMatrix.xx == m.xx
1310             && g.transformationMatrix.xy == m.xy
1311             && g.transformationMatrix.yx == m.yx
1312             && g.transformationMatrix.yy == m.yy) {
1313
1314             // found a match, move it to the front
1315             transformedGlyphSets.move(i, 0);
1316             gs = &transformedGlyphSets[0];
1317             break;
1318         }
1319     }
1320
1321     if (!gs) {
1322         // don't try to load huge fonts
1323         bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1324         if (draw_as_outline)
1325             return 0;
1326
1327         // don't cache more than 10 transformations
1328         if (transformedGlyphSets.count() >= 10) {
1329             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1330         } else {
1331             transformedGlyphSets.prepend(QGlyphSet());
1332         }
1333         gs = &transformedGlyphSets[0];
1334         gs->clear();
1335         gs->transformationMatrix = m;
1336         gs->outline_drawing = draw_as_outline;
1337     }
1338
1339     return gs;
1340 }
1341
1342 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1343                                const QFixedPoint *positions,
1344                                GlyphFormat format)
1345 {
1346     FT_Face face = 0;
1347
1348     for (int i = 0; i < num_glyphs; ++i) {
1349         QFixed spp = subPixelPositionForX(positions[i].x);
1350         Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1351         if (glyph == 0 || glyph->format != format) {
1352             if (!face) {
1353                 face = lockFace();
1354                 FT_Matrix m = matrix;
1355                 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1356                 FT_Set_Transform(face, &m, 0);
1357                 freetype->matrix = m;
1358             }
1359             if (!loadGlyph(gs, glyphs[i], spp, format)) {
1360                 unlockFace();
1361                 return false;
1362             }
1363         }
1364     }
1365
1366     if (face)
1367         unlockFace();
1368
1369     return true;
1370 }
1371
1372 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1373 {
1374     FT_Face face = lockFace(Unscaled);
1375     FT_Set_Transform(face, 0, 0);
1376     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1377
1378     int left  = face->glyph->metrics.horiBearingX;
1379     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1380     int top    = face->glyph->metrics.horiBearingY;
1381     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1382
1383     QFixedPoint p;
1384     p.x = 0;
1385     p.y = 0;
1386
1387     metrics->width = QFixed::fromFixed(right-left);
1388     metrics->height = QFixed::fromFixed(top-bottom);
1389     metrics->x = QFixed::fromFixed(left);
1390     metrics->y = QFixed::fromFixed(-top);
1391     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1392
1393     if (!FT_IS_SCALABLE(freetype->face))
1394         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1395     else
1396         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1397
1398     FT_Set_Transform(face, &freetype->matrix, 0);
1399     unlockFace();
1400 }
1401
1402 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1403 {
1404     uint ucs4 = str[i].unicode();
1405     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1406         ++i;
1407         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1408     }
1409     return ucs4;
1410 }
1411
1412 bool QFontEngineFT::canRender(const QChar *string, int len)
1413 {
1414     FT_Face face = freetype->face;
1415 #if 0
1416     if (_cmap != -1) {
1417         lockFace();
1418         for ( int i = 0; i < len; i++ ) {
1419             unsigned int uc = getChar(string, i, len);
1420             if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1421                 allExist = false;
1422                 break;
1423             }
1424         }
1425         unlockFace();
1426     } else
1427 #endif
1428     {
1429         for ( int i = 0; i < len; i++ ) {
1430             unsigned int uc = getChar(string, i, len);
1431             if (!FT_Get_Char_Index(face, uc))
1432                     return false;
1433         }
1434     }
1435     return true;
1436 }
1437
1438 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1439 {
1440     if (!glyphs.numGlyphs)
1441         return;
1442
1443     if (FT_IS_SCALABLE(freetype->face)) {
1444         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1445     } else {
1446         QVarLengthArray<QFixedPoint> positions;
1447         QVarLengthArray<glyph_t> positioned_glyphs;
1448         QTransform matrix;
1449         matrix.translate(x, y);
1450         getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1451
1452         FT_Face face = lockFace(Unscaled);
1453         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1454             FT_UInt glyph = positioned_glyphs[gl];
1455             FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1456             freetype->addBitmapToPath(face->glyph, positions[gl], path);
1457         }
1458         unlockFace();
1459     }
1460 }
1461
1462 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1463                                     QPainterPath *path, QTextItem::RenderFlags)
1464 {
1465     FT_Face face = lockFace(Unscaled);
1466
1467     for (int gl = 0; gl < numGlyphs; gl++) {
1468         FT_UInt glyph = glyphs[gl];
1469
1470         FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1471
1472         FT_GlyphSlot g = face->glyph;
1473         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1474             continue;
1475         if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1476         if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1477         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1478     }
1479     unlockFace();
1480 }
1481
1482 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1483                                  QTextEngine::ShaperFlags flags) const
1484 {
1485     if (*nglyphs < len) {
1486         *nglyphs = len;
1487         return false;
1488     }
1489
1490     bool mirrored = flags & QTextEngine::RightToLeft;
1491     int glyph_pos = 0;
1492     if (freetype->symbol_map) {
1493         FT_Face face = freetype->face;
1494         for ( int i = 0; i < len; ++i ) {
1495             unsigned int uc = getChar(str, i, len);
1496             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1497             if ( !glyphs->glyphs[glyph_pos] ) {
1498                 glyph_t glyph;
1499 #if !defined(QT_NO_FONTCONFIG)
1500                 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1501 #else
1502                 if (false) {
1503 #endif
1504                 redo0:
1505                     glyph = FT_Get_Char_Index(face, uc);
1506                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1507                         uc = 0x20;
1508                         goto redo0;
1509                     }
1510                 } else {
1511                     FT_Set_Charmap(face, freetype->symbol_map);
1512                     glyph = FT_Get_Char_Index(face, uc);
1513                     FT_Set_Charmap(face, freetype->unicode_map);
1514                 }
1515                 glyphs->glyphs[glyph_pos] = glyph;
1516                 if (uc < QFreetypeFace::cmapCacheSize)
1517                     freetype->cmapCache[uc] = glyph;
1518             }
1519             ++glyph_pos;
1520         }
1521     } else {
1522         FT_Face face = freetype->face;
1523         for (int i = 0; i < len; ++i) {
1524             unsigned int uc = getChar(str, i, len);
1525             if (mirrored)
1526                 uc = QChar::mirroredChar(uc);
1527             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1528             if (!glyphs->glyphs[glyph_pos]) {
1529 #if !defined(QT_NO_FONTCONFIG)
1530                 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1531 #endif
1532                 {
1533                 redo:
1534                     glyph_t glyph = FT_Get_Char_Index(face, uc);
1535                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1536                         uc = 0x20;
1537                         goto redo;
1538                     }
1539                     glyphs->glyphs[glyph_pos] = glyph;
1540                     if (uc < QFreetypeFace::cmapCacheSize)
1541                         freetype->cmapCache[uc] = glyph;
1542                 }
1543             }
1544             ++glyph_pos;
1545         }
1546     }
1547
1548     *nglyphs = glyph_pos;
1549     glyphs->numGlyphs = glyph_pos;
1550
1551     if (flags & QTextEngine::GlyphIndicesOnly)
1552         return true;
1553
1554     recalcAdvances(glyphs, flags);
1555
1556     return true;
1557 }
1558
1559 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1560 {
1561     FT_Face face = 0;
1562     bool design = (default_hint_style == HintNone ||
1563                    default_hint_style == HintLight ||
1564                    (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1565     for (int i = 0; i < glyphs->numGlyphs; i++) {
1566         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1567         if (g) {
1568             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1569         } else {
1570             if (!face)
1571                 face = lockFace();
1572             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1573             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1574                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1575         }
1576         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1577             glyphs->advances_x[i] = glyphs->advances_x[i].round();
1578         glyphs->advances_y[i] = 0;
1579     }
1580     if (face)
1581         unlockFace();
1582 }
1583
1584 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1585 {
1586     FT_Face face = 0;
1587
1588     glyph_metrics_t overall;
1589     // initialize with line height, we get the same behaviour on all platforms
1590     overall.y = -ascent();
1591     overall.height = ascent() + descent();
1592
1593     QFixed ymax = 0;
1594     QFixed xmax = 0;
1595     for (int i = 0; i < glyphs.numGlyphs; i++) {
1596         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1597         if (!g) {
1598             if (!face)
1599                 face = lockFace();
1600             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1601         }
1602         if (g) {
1603             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1604             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1605             overall.x = qMin(overall.x, x);
1606             overall.y = qMin(overall.y, y);
1607             xmax = qMax(xmax, x + g->width);
1608             ymax = qMax(ymax, y + g->height);
1609             overall.xoff += g->advance;
1610         } else {
1611             int left  = FLOOR(face->glyph->metrics.horiBearingX);
1612             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1613             int top    = CEIL(face->glyph->metrics.horiBearingY);
1614             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1615
1616             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1617             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1618             overall.x = qMin(overall.x, x);
1619             overall.y = qMin(overall.y, y);
1620             xmax = qMax(xmax, x + TRUNC(right - left));
1621             ymax = qMax(ymax, y + TRUNC(top - bottom));
1622             overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1623         }
1624     }
1625     overall.height = qMax(overall.height, ymax - overall.y);
1626     overall.width = xmax - overall.x;
1627
1628     if (face)
1629         unlockFace();
1630
1631     return overall;
1632 }
1633
1634 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1635 {
1636     FT_Face face = 0;
1637     glyph_metrics_t overall;
1638     Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1639     if (!g) {
1640         face = lockFace();
1641         g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1642     }
1643     if (g) {
1644         overall.x = g->x;
1645         overall.y = -g->y;
1646         overall.width = g->width;
1647         overall.height = g->height;
1648         overall.xoff = g->advance;
1649         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1650             overall.xoff = overall.xoff.round();
1651     } else {
1652         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1653         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1654         int top    = CEIL(face->glyph->metrics.horiBearingY);
1655         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1656
1657         overall.width = TRUNC(right-left);
1658         overall.height = TRUNC(top-bottom);
1659         overall.x = TRUNC(left);
1660         overall.y = -TRUNC(top);
1661         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1662     }
1663     if (face)
1664         unlockFace();
1665     return overall;
1666 }
1667
1668 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1669 {
1670     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1671 }
1672
1673 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1674 {
1675     FT_Matrix m;
1676
1677     m.xx = FT_Fixed(matrix.m11() * 65536);
1678     m.xy = FT_Fixed(-matrix.m21() * 65536);
1679     m.yx = FT_Fixed(-matrix.m12() * 65536);
1680     m.yy = FT_Fixed(matrix.m22() * 65536);
1681
1682     return m;
1683 }
1684
1685 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1686 {
1687     FT_Face face = 0;
1688     glyph_metrics_t overall;
1689     QGlyphSet *glyphSet = 0;
1690     FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1691     if (cacheEnabled) {
1692         if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1693             // TODO move everything here to a method of its own to access glyphSets
1694             // to be shared with a new method that will replace loadTransformedGlyphSet()
1695             for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1696                 const QGlyphSet &g = transformedGlyphSets.at(i);
1697                 if (g.transformationMatrix.xx == ftMatrix.xx
1698                     && g.transformationMatrix.xy == ftMatrix.xy
1699                     && g.transformationMatrix.yx == ftMatrix.yx
1700                     && g.transformationMatrix.yy == ftMatrix.yy) {
1701
1702                     // found a match, move it to the front
1703                     transformedGlyphSets.move(i, 0);
1704                     glyphSet = &transformedGlyphSets[0];
1705                     break;
1706                 }
1707             }
1708
1709             if (!glyphSet) {
1710                 // don't cache more than 10 transformations
1711                 if (transformedGlyphSets.count() >= 10) {
1712                     transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1713                 } else {
1714                     transformedGlyphSets.prepend(QGlyphSet());
1715                 }
1716                 glyphSet = &transformedGlyphSets[0];
1717                 glyphSet->clear();
1718                 glyphSet->transformationMatrix = ftMatrix;
1719             }
1720             Q_ASSERT(glyphSet);
1721         } else {
1722             glyphSet = &defaultGlyphSet;
1723         }
1724     }
1725     Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1726     if (!g || g->format != format) {
1727         face = lockFace();
1728         FT_Matrix m = this->matrix;
1729         FT_Matrix_Multiply(&ftMatrix, &m);
1730         freetype->matrix = m;
1731         g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1732     }
1733
1734     if (g) {
1735         overall.x = g->x;
1736         overall.y = -g->y;
1737         overall.width = g->width;
1738         overall.height = g->height;
1739         overall.xoff = g->advance;
1740     } else {
1741         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1742         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1743         int top    = CEIL(face->glyph->metrics.horiBearingY);
1744         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1745
1746         overall.width = TRUNC(right-left);
1747         overall.height = TRUNC(top-bottom);
1748         overall.x = TRUNC(left);
1749         overall.y = -TRUNC(top);
1750         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1751     }
1752     if (face)
1753         unlockFace();
1754     return overall;
1755 }
1756
1757 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1758                                               QFontEngine::GlyphFormat neededFormat,
1759                                               const QTransform &t, QPoint *offset)
1760 {
1761     Q_ASSERT(currentlyLockedAlphaMap.isNull());
1762     lockFace();
1763
1764     if (isBitmapFont())
1765         neededFormat = Format_Mono;
1766     else if (neededFormat == Format_None && defaultFormat != Format_None)
1767         neededFormat = defaultFormat;
1768     else if (neededFormat == Format_None)
1769         neededFormat = Format_A8;
1770
1771     QImage::Format format;
1772     switch (neededFormat) {
1773     case Format_Mono:
1774         format = QImage::Format_Mono;
1775         break;
1776     case Format_A8:
1777         format = QImage::Format_Indexed8;
1778         break;
1779     case Format_A32:
1780         format = QImage::Format_ARGB32;
1781         break;
1782     default:
1783         Q_ASSERT(false);
1784         format = QImage::Format_Invalid;
1785     };
1786
1787     QFontEngineFT::Glyph *glyph;
1788     if (cacheEnabled) {
1789         QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1790         if (t.type() >= QTransform::TxScale) {
1791             if (t.isAffine())
1792                 gset = loadTransformedGlyphSet(t);
1793             else
1794                 gset = 0;
1795         }
1796
1797         if (gset) {
1798             FT_Matrix m = matrix;
1799             FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1800             FT_Set_Transform(freetype->face, &m, 0);
1801             freetype->matrix = m;
1802         }
1803
1804         if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1805                                                          neededFormat)) {
1806             return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1807                                                        offset);
1808         }
1809
1810         glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1811     } else {
1812         FT_Matrix m = matrix;
1813         FT_Matrix extra = QTransformToFTMatrix(t);
1814         FT_Matrix_Multiply(&extra, &m);
1815         FT_Set_Transform(freetype->face, &m, 0);
1816         freetype->matrix = m;
1817         glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1818     }
1819
1820     if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1821         unlockFace();
1822         return 0;
1823     }
1824
1825     int pitch;
1826     switch (neededFormat) {
1827     case Format_Mono:
1828         pitch = ((glyph->width + 31) & ~31) >> 3;
1829         break;
1830     case Format_A8:
1831         pitch = (glyph->width + 3) & ~3;
1832         break;
1833     case Format_A32:
1834         pitch = glyph->width * 4;
1835         break;
1836     default:
1837         Q_ASSERT(false);
1838         pitch = 0;
1839     };
1840
1841     if (offset != 0)
1842         *offset = QPoint(glyph->x, -glyph->y);
1843
1844     currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1845     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1846
1847     QImageData *data = currentlyLockedAlphaMap.data_ptr();
1848     data->is_locked = true;
1849
1850     return &currentlyLockedAlphaMap;
1851 }
1852
1853 void QFontEngineFT::unlockAlphaMapForGlyph()
1854 {
1855     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1856     unlockFace();
1857     currentlyLockedAlphaMap = QImage();
1858 }
1859
1860 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1861 {
1862     return defaultGlyphSet.outline_drawing ? 0 :
1863             loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1864 }
1865
1866 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1867 {
1868     lockFace();
1869
1870     Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1871     if (!glyph) {
1872         unlockFace();
1873         return QFontEngine::alphaMapForGlyph(g);
1874     }
1875
1876     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1877
1878     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1879     if (antialias) {
1880         QVector<QRgb> colors(256);
1881         for (int i=0; i<256; ++i)
1882             colors[i] = qRgba(0, 0, 0, i);
1883         img.setColorTable(colors);
1884     } else {
1885         QVector<QRgb> colors(2);
1886         colors[0] = qRgba(0, 0, 0, 0);
1887         colors[1] = qRgba(0, 0, 0, 255);
1888         img.setColorTable(colors);
1889     }
1890     Q_ASSERT(img.bytesPerLine() == pitch);
1891     if (glyph->width) {
1892         for (int y = 0; y < glyph->height; ++y)
1893             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1894     }
1895     unlockFace();
1896
1897     return img;
1898 }
1899
1900 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
1901 {
1902     if (t.type() > QTransform::TxTranslate)
1903         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1904
1905     lockFace();
1906
1907     Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1908     if (!glyph) {
1909         unlockFace();
1910         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
1911     }
1912
1913     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1914     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1915     unlockFace();
1916
1917     return img;
1918 }
1919
1920 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1921 {
1922     defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1923 }
1924
1925 int QFontEngineFT::glyphCount() const
1926 {
1927     int count = 0;
1928     FT_Face face = lockFace();
1929     if (face) {
1930         count = face->num_glyphs;
1931         unlockFace();
1932     }
1933     return count;
1934 }
1935
1936 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1937 {
1938     freetype->lock();
1939     FT_Face face = freetype->face;
1940     if (scale == Unscaled) {
1941         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1942         freetype->xsize = face->units_per_EM << 6;
1943         freetype->ysize = face->units_per_EM << 6;
1944     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1945         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1946         freetype->xsize = xsize;
1947         freetype->ysize = ysize;
1948     }
1949     if (freetype->matrix.xx != matrix.xx ||
1950         freetype->matrix.yy != matrix.yy ||
1951         freetype->matrix.xy != matrix.xy ||
1952         freetype->matrix.yx != matrix.yx) {
1953         freetype->matrix = matrix;
1954         FT_Set_Transform(face, &freetype->matrix, 0);
1955     }
1956
1957     return face;
1958 }
1959
1960 void QFontEngineFT::unlockFace() const
1961 {
1962     freetype->unlock();
1963 }
1964
1965 FT_Face QFontEngineFT::non_locked_face() const
1966 {
1967     return freetype->face;
1968 }
1969
1970
1971 QFontEngineFT::QGlyphSet::QGlyphSet()
1972     : outline_drawing(false)
1973 {
1974     transformationMatrix.xx = 0x10000;
1975     transformationMatrix.yy = 0x10000;
1976     transformationMatrix.xy = 0;
1977     transformationMatrix.yx = 0;
1978     memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1979     fast_glyph_count = 0;
1980 }
1981
1982 QFontEngineFT::QGlyphSet::~QGlyphSet()
1983 {
1984     clear();
1985 }
1986
1987 void QFontEngineFT::QGlyphSet::clear()
1988 {
1989     if (fast_glyph_count > 0) {
1990         for (int i = 0; i < 256; ++i) {
1991             if (fast_glyph_data[i]) {
1992                 delete fast_glyph_data[i];
1993                 fast_glyph_data[i] = 0;
1994             }
1995         }
1996         fast_glyph_count = 0;
1997     }
1998     qDeleteAll(glyph_data);
1999     glyph_data.clear();
2000 }
2001
2002 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2003 {
2004     if (useFastGlyphData(index, subPixelPosition)) {
2005         if (fast_glyph_data[index]) {
2006             delete fast_glyph_data[index];
2007             fast_glyph_data[index] = 0;
2008             if (fast_glyph_count > 0)
2009                 --fast_glyph_count;
2010         }
2011     } else {
2012         delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2013     }
2014 }
2015
2016 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2017 {
2018     if (useFastGlyphData(index, subPixelPosition)) {
2019         if (!fast_glyph_data[index])
2020             ++fast_glyph_count;
2021         fast_glyph_data[index] = glyph;
2022     } else {
2023         glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2024     }
2025 }
2026
2027 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2028 {
2029     lockFace();
2030     bool hsubpixel = true;
2031     int vfactor = 1;
2032     int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2033     HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2034     unlockFace();
2035     return result;
2036 }
2037
2038 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2039 {
2040     if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2041         return false;
2042
2043     // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2044     // will be using it
2045     freetype->ref.ref();
2046
2047     default_load_flags = fe->default_load_flags;
2048     default_hint_style = fe->default_hint_style;
2049     antialias = fe->antialias;
2050     transform = fe->transform;
2051     embolden = fe->embolden;
2052     obliquen = fe->obliquen;
2053     subpixelType = fe->subpixelType;
2054     lcdFilterType = fe->lcdFilterType;
2055     embeddedbitmap = fe->embeddedbitmap;
2056
2057     return true;
2058 }
2059
2060 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2061 {
2062     QFontDef fontDef(this->fontDef);
2063     fontDef.pixelSize = pixelSize;
2064     QFontEngineFT *fe = new QFontEngineFT(fontDef);
2065     if (!fe->initFromFontEngine(this)) {
2066         delete fe;
2067         return 0;
2068     } else {
2069         return fe;
2070     }
2071 }
2072
2073 QT_END_NAMESPACE
2074
2075 #endif // QT_NO_FREETYPE