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