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