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