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