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