6845c67463210894cb713cc5d69116570c614355
[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.store(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     embeddedbitmap = false;
659     cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").toInt() == 0;
660     m_subPixelPositionCount = 4;
661 }
662
663 QFontEngineFT::~QFontEngineFT()
664 {
665     if (freetype)
666         freetype->release(face_id);
667     hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
668 }
669
670 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
671                          const QByteArray &fontData)
672 {
673     return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
674 }
675
676 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
677                          QFreetypeFace *freetypeFace)
678 {
679     freetype = freetypeFace;
680     if (!freetype) {
681         xsize = 0;
682         ysize = 0;
683         return false;
684     }
685     defaultFormat = format;
686     this->antialias = antialias;
687
688     if (!antialias)
689         glyphFormat = QFontEngineGlyphCache::Raster_Mono;
690     else if (format == Format_A8)
691         glyphFormat = QFontEngineGlyphCache::Raster_A8;
692     else if (format == Format_A32)
693         glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
694
695     face_id = faceId;
696
697     symbol = freetype->symbol_map != 0;
698     PS_FontInfoRec psrec;
699     // don't assume that type1 fonts are symbol fonts by default
700     if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
701         symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
702     }
703     // #####
704     freetype->hbFace->isSymbolFont = symbol;
705
706     lbearing = rbearing = SHRT_MIN;
707     freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
708
709     FT_Face face = lockFace();
710
711     if (FT_IS_SCALABLE(face)) {
712         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
713         if (fake_oblique) {
714 #if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
715             matrix.xy = 0x10000*3/10;
716             transform = true;
717 #else
718             obliquen = true;
719 #endif
720         }
721         FT_Set_Transform(face, &matrix, 0);
722         freetype->matrix = matrix;
723         // fake bold
724         if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
725             embolden = true;
726         // underline metrics
727         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
728         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
729     } else {
730         // copied from QFontEngineQPF
731         // ad hoc algorithm
732         int score = fontDef.weight * fontDef.pixelSize;
733         line_thickness = score / 700;
734         // looks better with thicker line for small pointsizes
735         if (line_thickness < 2 && score >= 1050)
736             line_thickness = 2;
737         underline_position =  ((line_thickness * 2) + 3) / 6;
738     }
739     if (line_thickness < 1)
740         line_thickness = 1;
741
742     hbFont.x_ppem  = face->size->metrics.x_ppem;
743     hbFont.y_ppem  = face->size->metrics.y_ppem;
744     hbFont.x_scale = face->size->metrics.x_scale;
745     hbFont.y_scale = face->size->metrics.y_scale;
746
747     hbFace = freetype->hbFace;
748
749     metrics = face->size->metrics;
750
751     /*
752        TrueType fonts with embedded bitmaps may have a bitmap font specific
753        ascent/descent in the EBLC table. There is no direct public API
754        to extract those values. The only way we've found is to trick freetype
755        into thinking that it's not a scalable font in FT_SelectSize so that
756        the metrics are retrieved from the bitmap strikes.
757     */
758     if (FT_IS_SCALABLE(face)) {
759         for (int i = 0; i < face->num_fixed_sizes; ++i) {
760             if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
761                 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
762
763                 FT_Select_Size(face, i);
764                 metrics.ascender = face->size->metrics.ascender;
765                 metrics.descender = face->size->metrics.descender;
766                 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
767
768                 face->face_flags |= FT_FACE_FLAG_SCALABLE;
769                 break;
770             }
771         }
772     }
773
774     fontDef.styleName = QString::fromUtf8(face->style_name);
775
776     unlockFace();
777
778     fsType = freetype->fsType();
779     return true;
780 }
781
782 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
783 {
784     default_hint_style = style;
785 }
786
787 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
788                              bool &hsubpixel, int &vfactor) const
789 {
790     int load_flags = FT_LOAD_DEFAULT | default_load_flags;
791     int load_target = default_hint_style == HintLight
792                       ? FT_LOAD_TARGET_LIGHT
793                       : FT_LOAD_TARGET_NORMAL;
794
795     if (format == Format_Mono) {
796         load_target = FT_LOAD_TARGET_MONO;
797     } else if (format == Format_A32) {
798         if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
799             if (default_hint_style == HintFull)
800                 load_target = FT_LOAD_TARGET_LCD;
801             hsubpixel = true;
802         } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
803             if (default_hint_style == HintFull)
804                 load_target = FT_LOAD_TARGET_LCD_V;
805             vfactor = 3;
806         }
807     }
808
809     if (set && set->outline_drawing)
810         load_flags = FT_LOAD_NO_BITMAP;
811
812     if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
813         load_flags |= FT_LOAD_NO_HINTING;
814     else
815         load_flags |= load_target;
816
817     return load_flags;
818 }
819
820 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
821                                                QFixed subPixelPosition,
822                                                GlyphFormat format,
823                                                bool fetchMetricsOnly) const
824 {
825 //     Q_ASSERT(freetype->lock == 1);
826
827     if (format == Format_None) {
828         if (defaultFormat != Format_None) {
829             format = defaultFormat;
830         } else {
831             format = Format_Mono;
832         }
833     }
834
835     Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
836     if (g && g->format == format)
837         return g;
838
839     QFontEngineFT::GlyphInfo info;
840
841     Q_ASSERT(format != Format_None);
842     bool hsubpixel = false;
843     int vfactor = 1;
844     int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
845
846     if (format != Format_Mono && !embeddedbitmap)
847         load_flags |= FT_LOAD_NO_BITMAP;
848
849     FT_Matrix matrix = freetype->matrix;
850     bool transform = matrix.xx != 0x10000
851                      || matrix.yy != 0x10000
852                      || matrix.xy != 0
853                      || matrix.yx != 0;
854
855     if (transform)
856         load_flags |= FT_LOAD_NO_BITMAP;
857
858     FT_Face face = freetype->face;
859
860     FT_Vector v;
861     v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
862     v.y = 0;
863     FT_Set_Transform(face, &freetype->matrix, &v);
864
865     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
866     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
867         load_flags &= ~FT_LOAD_NO_BITMAP;
868         err = FT_Load_Glyph(face, glyph, load_flags);
869     }
870     if (err == FT_Err_Too_Few_Arguments) {
871         // this is an error in the bytecode interpreter, just try to run without it
872         load_flags |= FT_LOAD_FORCE_AUTOHINT;
873         err = FT_Load_Glyph(face, glyph, load_flags);
874     }
875     if (err != FT_Err_Ok)
876         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
877
878     if ((!set || set->outline_drawing) && fetchMetricsOnly)
879         return 0;
880
881     FT_GlyphSlot slot = face->glyph;
882     if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
883     if (obliquen) {
884         Q_FT_GLYPHSLOT_OBLIQUE(slot);
885
886         // While Embolden alters the metrics of the slot, oblique does not, so we need
887         // to fix this ourselves.
888         transform = true;
889         FT_Matrix m;
890         m.xx = 0x10000;
891         m.yx = 0x0;
892         m.xy = 0x6000;
893         m.yy = 0x10000;
894
895         FT_Matrix_Multiply(&m, &matrix);
896     }
897
898     FT_Library library = qt_getFreetype();
899
900     info.xOff = TRUNC(ROUND(slot->advance.x));
901     info.yOff = 0;
902
903     uchar *glyph_buffer = 0;
904     int glyph_buffer_size = 0;
905 #if defined(QT_USE_FREETYPE_LCDFILTER)
906     bool useFreetypeRenderGlyph = false;
907     if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
908         err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
909         if (err == FT_Err_Ok)
910             useFreetypeRenderGlyph = true;
911     }
912
913     if (useFreetypeRenderGlyph) {
914         err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
915
916         if (err != FT_Err_Ok)
917             qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
918
919         FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
920
921         info.height = slot->bitmap.rows / vfactor;
922         info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
923         info.x = -slot->bitmap_left;
924         info.y = slot->bitmap_top;
925
926         glyph_buffer_size = info.width * info.height * 4;
927         glyph_buffer = new uchar[glyph_buffer_size];
928
929         if (hsubpixel)
930             convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
931         else if (vfactor != 1)
932             convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
933     } else
934 #endif
935     {
936     int left  = slot->metrics.horiBearingX;
937     int right = slot->metrics.horiBearingX + slot->metrics.width;
938     int top    = slot->metrics.horiBearingY;
939     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
940     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
941         int l, r, t, b;
942         FT_Vector vector;
943         vector.x = left;
944         vector.y = top;
945         FT_Vector_Transform(&vector, &matrix);
946         l = r = vector.x;
947         t = b = vector.y;
948         vector.x = right;
949         vector.y = top;
950         FT_Vector_Transform(&vector, &matrix);
951         if (l > vector.x) l = vector.x;
952         if (r < vector.x) r = vector.x;
953         if (t < vector.y) t = vector.y;
954         if (b > vector.y) b = vector.y;
955         vector.x = right;
956         vector.y = bottom;
957         FT_Vector_Transform(&vector, &matrix);
958         if (l > vector.x) l = vector.x;
959         if (r < vector.x) r = vector.x;
960         if (t < vector.y) t = vector.y;
961         if (b > vector.y) b = vector.y;
962         vector.x = left;
963         vector.y = bottom;
964         FT_Vector_Transform(&vector, &matrix);
965         if (l > vector.x) l = vector.x;
966         if (r < vector.x) r = vector.x;
967         if (t < vector.y) t = vector.y;
968         if (b > vector.y) b = vector.y;
969         left = l;
970         right = r;
971         top = t;
972         bottom = b;
973     }
974     left = FLOOR(left);
975     right = CEIL(right);
976     bottom = FLOOR(bottom);
977     top = CEIL(top);
978
979     int hpixels = TRUNC(right - left);
980     // subpixel position requires one more pixel
981     if (subPixelPosition > 0 && format != Format_Mono)
982         hpixels++;
983
984     if (hsubpixel)
985         hpixels = hpixels*3 + 8;
986     info.width = hpixels;
987     info.height = TRUNC(top - bottom);
988     info.x = -TRUNC(left);
989     info.y = TRUNC(top);
990     if (hsubpixel) {
991         info.width /= 3;
992         info.x += 1;
993     }
994
995     bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
996                         || ((uchar)(info.width) != info.width)
997                         || ((uchar)(info.height) != info.height)
998                         || ((signed char)(info.x) != info.x)
999                         || ((signed char)(info.y) != info.y)
1000                         || ((signed char)(info.xOff) != info.xOff));
1001
1002     if (large_glyph) {
1003         delete [] glyph_buffer;
1004         return 0;
1005     }
1006
1007     int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1008                  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1009     glyph_buffer_size = pitch * info.height;
1010     glyph_buffer = new uchar[glyph_buffer_size];
1011
1012     if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1013         FT_Bitmap bitmap;
1014         bitmap.rows = info.height*vfactor;
1015         bitmap.width = hpixels;
1016         bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1017         if (!hsubpixel && vfactor == 1)
1018             bitmap.buffer = glyph_buffer;
1019         else
1020             bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1021         memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1022         bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1023         FT_Matrix matrix;
1024         matrix.xx = (hsubpixel ? 3 : 1) << 16;
1025         matrix.yy = vfactor << 16;
1026         matrix.yx = matrix.xy = 0;
1027
1028         FT_Outline_Transform(&slot->outline, &matrix);
1029         FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1030         FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1031         if (hsubpixel) {
1032             Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1033             Q_ASSERT(antialias);
1034             uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1035             bool useLegacyLcdFilter = false;
1036 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1037             useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1038 #endif
1039             uchar *buffer = bitmap.buffer;
1040             if (!useLegacyLcdFilter) {
1041                 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1042                 buffer = convoluted;
1043             }
1044             convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1045             delete [] convoluted;
1046         } else if (vfactor != 1) {
1047             convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1048         }
1049
1050         if (bitmap.buffer != glyph_buffer)
1051             delete [] bitmap.buffer;
1052     } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1053         Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1054         uchar *src = slot->bitmap.buffer;
1055         uchar *dst = glyph_buffer;
1056         int h = slot->bitmap.rows;
1057         if (format == Format_Mono) {
1058             int bytes = ((info.width + 7) & ~7) >> 3;
1059             while (h--) {
1060                 memcpy (dst, src, bytes);
1061                 dst += pitch;
1062                 src += slot->bitmap.pitch;
1063             }
1064         } else {
1065             if (hsubpixel) {
1066                 while (h--) {
1067                     uint *dd = (uint *)dst;
1068                     *dd++ = 0;
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                     *dd++ = 0;
1074                     dst += pitch;
1075                     src += slot->bitmap.pitch;
1076                 }
1077             } else if (vfactor != 1) {
1078                 while (h--) {
1079                     uint *dd = (uint *)dst;
1080                     for (int x = 0; x < slot->bitmap.width; x++) {
1081                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1082                         *dd++ = a;
1083                     }
1084                     dst += pitch;
1085                     src += slot->bitmap.pitch;
1086                 }
1087             } else {
1088                 while (h--) {
1089                     for (int x = 0; x < slot->bitmap.width; x++) {
1090                         unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1091                         dst[x] = a;
1092                     }
1093                     dst += pitch;
1094                     src += slot->bitmap.pitch;
1095                 }
1096             }
1097         }
1098     } else {
1099         qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1100         delete [] glyph_buffer;
1101         return 0;
1102     }
1103     }
1104
1105
1106     if (!g) {
1107         g = new Glyph;
1108         g->data = 0;
1109     }
1110
1111     g->linearAdvance = slot->linearHoriAdvance >> 10;
1112     g->width = info.width;
1113     g->height = info.height;
1114     g->x = -info.x;
1115     g->y = info.y;
1116     g->advance = info.xOff;
1117     g->format = format;
1118     delete [] g->data;
1119     g->data = glyph_buffer;
1120
1121     if (set)
1122         set->setGlyph(glyph, subPixelPosition, g);
1123
1124     return g;
1125 }
1126
1127 QFontEngine::FaceId QFontEngineFT::faceId() const
1128 {
1129     return face_id;
1130 }
1131
1132 QFontEngine::Properties QFontEngineFT::properties() const
1133 {
1134     Properties p = freetype->properties();
1135     if (p.postscriptName.isEmpty()) {
1136         p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1137     }
1138
1139     return freetype->properties();
1140 }
1141
1142 QFixed QFontEngineFT::emSquareSize() const
1143 {
1144     if (FT_IS_SCALABLE(freetype->face))
1145         return freetype->face->units_per_EM;
1146     else
1147         return freetype->face->size->metrics.y_ppem;
1148 }
1149
1150 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1151 {
1152     return freetype->getSfntTable(tag, buffer, length);
1153 }
1154
1155 int QFontEngineFT::synthesized() const
1156 {
1157     int s = 0;
1158     if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1159         s = SynthesizedItalic;
1160     if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1161         s |= SynthesizedBold;
1162     if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1163         s |= SynthesizedStretch;
1164     return s;
1165 }
1166
1167 QFixed QFontEngineFT::ascent() const
1168 {
1169     return QFixed::fromFixed(metrics.ascender);
1170 }
1171
1172 QFixed QFontEngineFT::descent() const
1173 {
1174     // subtract a pixel to work around QFontMetrics's built-in + 1
1175     return QFixed::fromFixed(-metrics.descender - 64);
1176 }
1177
1178 QFixed QFontEngineFT::leading() const
1179 {
1180     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1181 }
1182
1183 QFixed QFontEngineFT::xHeight() const
1184 {
1185     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1186     if (os2 && os2->sxHeight) {
1187         lockFace();
1188         QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1189         unlockFace();
1190         return answer;
1191     }
1192     return QFontEngine::xHeight();
1193 }
1194
1195 QFixed QFontEngineFT::averageCharWidth() const
1196 {
1197     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1198     if (os2 && os2->xAvgCharWidth) {
1199         lockFace();
1200         QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1201         unlockFace();
1202         return answer;
1203     }
1204     return QFontEngine::averageCharWidth();
1205 }
1206
1207 qreal QFontEngineFT::maxCharWidth() const
1208 {
1209     return metrics.max_advance >> 6;
1210 }
1211
1212 static const ushort char_table[] = {
1213         40,
1214         67,
1215         70,
1216         75,
1217         86,
1218         88,
1219         89,
1220         91,
1221         102,
1222         114,
1223         124,
1224         127,
1225         205,
1226         645,
1227         884,
1228         922,
1229         1070,
1230         12386
1231 };
1232
1233 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1234
1235
1236 qreal QFontEngineFT::minLeftBearing() const
1237 {
1238     if (lbearing == SHRT_MIN)
1239         (void) minRightBearing(); // calculates both
1240     return lbearing.toReal();
1241 }
1242
1243 qreal QFontEngineFT::minRightBearing() const
1244 {
1245     if (rbearing == SHRT_MIN) {
1246         lbearing = rbearing = 0;
1247         const QChar *ch = (const QChar *)(const void*)char_table;
1248         QGlyphLayoutArray<char_table_entries> glyphs;
1249         int ng = char_table_entries;
1250         stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1251         while (--ng) {
1252             if (glyphs.glyphs[ng]) {
1253                 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1254                 lbearing = qMin(lbearing, gi.x);
1255                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1256             }
1257         }
1258     }
1259     return rbearing.toReal();
1260 }
1261
1262 QFixed QFontEngineFT::lineThickness() const
1263 {
1264     return line_thickness;
1265 }
1266
1267 QFixed QFontEngineFT::underlinePosition() const
1268 {
1269     return underline_position;
1270 }
1271
1272 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1273 {
1274     if (!kerning_pairs_loaded) {
1275         kerning_pairs_loaded = true;
1276         lockFace();
1277         if (freetype->face->size->metrics.x_ppem != 0) {
1278             QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1279             unlockFace();
1280             const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1281         } else {
1282             unlockFace();
1283         }
1284     }
1285     QFontEngine::doKerning(g, flags);
1286 }
1287
1288 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1289 {
1290     if (matrix.type() > QTransform::TxShear)
1291         return 0;
1292
1293     // FT_Set_Transform only supports scalable fonts
1294     if (!FT_IS_SCALABLE(freetype->face))
1295         return 0;
1296
1297     FT_Matrix m;
1298     m.xx = FT_Fixed(matrix.m11() * 65536);
1299     m.xy = FT_Fixed(-matrix.m21() * 65536);
1300     m.yx = FT_Fixed(-matrix.m12() * 65536);
1301     m.yy = FT_Fixed(matrix.m22() * 65536);
1302
1303     QGlyphSet *gs = 0;
1304
1305     for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1306         const QGlyphSet &g = transformedGlyphSets.at(i);
1307         if (g.transformationMatrix.xx == m.xx
1308             && g.transformationMatrix.xy == m.xy
1309             && g.transformationMatrix.yx == m.yx
1310             && g.transformationMatrix.yy == m.yy) {
1311
1312             // found a match, move it to the front
1313             transformedGlyphSets.move(i, 0);
1314             gs = &transformedGlyphSets[0];
1315             break;
1316         }
1317     }
1318
1319     if (!gs) {
1320         // don't try to load huge fonts
1321         bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
1322         if (draw_as_outline)
1323             return 0;
1324
1325         // don't cache more than 10 transformations
1326         if (transformedGlyphSets.count() >= 10) {
1327             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1328         } else {
1329             transformedGlyphSets.prepend(QGlyphSet());
1330         }
1331         gs = &transformedGlyphSets[0];
1332         gs->clear();
1333         gs->transformationMatrix = m;
1334         gs->outline_drawing = draw_as_outline;
1335     }
1336
1337     return gs;
1338 }
1339
1340 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1341                                const QFixedPoint *positions,
1342                                GlyphFormat format)
1343 {
1344     FT_Face face = 0;
1345
1346     for (int i = 0; i < num_glyphs; ++i) {
1347         QFixed spp = subPixelPositionForX(positions[i].x);
1348         Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
1349         if (glyph == 0 || glyph->format != format) {
1350             if (!face) {
1351                 face = lockFace();
1352                 FT_Matrix m = matrix;
1353                 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1354                 FT_Set_Transform(face, &m, 0);
1355                 freetype->matrix = m;
1356             }
1357             if (!loadGlyph(gs, glyphs[i], spp, format)) {
1358                 unlockFace();
1359                 return false;
1360             }
1361         }
1362     }
1363
1364     if (face)
1365         unlockFace();
1366
1367     return true;
1368 }
1369
1370 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1371 {
1372     FT_Face face = lockFace(Unscaled);
1373     FT_Set_Transform(face, 0, 0);
1374     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1375
1376     int left  = face->glyph->metrics.horiBearingX;
1377     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1378     int top    = face->glyph->metrics.horiBearingY;
1379     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1380
1381     QFixedPoint p;
1382     p.x = 0;
1383     p.y = 0;
1384
1385     metrics->width = QFixed::fromFixed(right-left);
1386     metrics->height = QFixed::fromFixed(top-bottom);
1387     metrics->x = QFixed::fromFixed(left);
1388     metrics->y = QFixed::fromFixed(-top);
1389     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1390
1391     if (!FT_IS_SCALABLE(freetype->face))
1392         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1393     else
1394         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1395
1396     FT_Set_Transform(face, &freetype->matrix, 0);
1397     unlockFace();
1398 }
1399
1400 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1401 {
1402     uint ucs4 = str[i].unicode();
1403     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
1404         ++i;
1405         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
1406     }
1407     return ucs4;
1408 }
1409
1410 bool QFontEngineFT::canRender(const QChar *string, int len)
1411 {
1412     FT_Face face = freetype->face;
1413 #if 0
1414     if (_cmap != -1) {
1415         lockFace();
1416         for ( int i = 0; i < len; i++ ) {
1417             unsigned int uc = getChar(string, i, len);
1418             if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1419                 allExist = false;
1420                 break;
1421             }
1422         }
1423         unlockFace();
1424     } else
1425 #endif
1426     {
1427         for ( int i = 0; i < len; i++ ) {
1428             unsigned int uc = getChar(string, i, len);
1429             if (!FT_Get_Char_Index(face, uc))
1430                     return false;
1431         }
1432     }
1433     return true;
1434 }
1435
1436 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1437 {
1438     if (!glyphs.numGlyphs)
1439         return;
1440
1441     if (FT_IS_SCALABLE(freetype->face)) {
1442         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1443     } else {
1444         QVarLengthArray<QFixedPoint> positions;
1445         QVarLengthArray<glyph_t> positioned_glyphs;
1446         QTransform matrix;
1447         matrix.translate(x, y);
1448         getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1449
1450         FT_Face face = lockFace(Unscaled);
1451         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1452             FT_UInt glyph = positioned_glyphs[gl];
1453             FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1454             freetype->addBitmapToPath(face->glyph, positions[gl], path);
1455         }
1456         unlockFace();
1457     }
1458 }
1459
1460 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1461                                     QPainterPath *path, QTextItem::RenderFlags)
1462 {
1463     FT_Face face = lockFace(Unscaled);
1464
1465     for (int gl = 0; gl < numGlyphs; gl++) {
1466         FT_UInt glyph = glyphs[gl];
1467
1468         FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1469
1470         FT_GlyphSlot g = face->glyph;
1471         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1472             continue;
1473         if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
1474         if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
1475         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1476     }
1477     unlockFace();
1478 }
1479
1480 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1481                                  QTextEngine::ShaperFlags flags) const
1482 {
1483     if (*nglyphs < len) {
1484         *nglyphs = len;
1485         return false;
1486     }
1487
1488 #if !defined(QT_NO_FONTCONFIG)
1489     extern QMutex *qt_fontdatabase_mutex();
1490     QMutex *mtx = 0;
1491 #endif
1492
1493     bool mirrored = flags & QTextEngine::RightToLeft;
1494     int glyph_pos = 0;
1495     if (freetype->symbol_map) {
1496         FT_Face face = freetype->face;
1497         for ( int i = 0; i < len; ++i ) {
1498             unsigned int uc = getChar(str, i, len);
1499             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1500             if ( !glyphs->glyphs[glyph_pos] ) {
1501                 glyph_t glyph;
1502 #if !defined(QT_NO_FONTCONFIG)
1503                 if (!mtx) {
1504                     mtx = qt_fontdatabase_mutex();
1505                     mtx->lock();
1506                 }
1507
1508                 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1509 #else
1510                 if (false) {
1511 #endif
1512                 redo0:
1513                     glyph = FT_Get_Char_Index(face, uc);
1514                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1515                         uc = 0x20;
1516                         goto redo0;
1517                     }
1518                 } else {
1519                     FT_Set_Charmap(face, freetype->symbol_map);
1520                     glyph = FT_Get_Char_Index(face, uc);
1521                     FT_Set_Charmap(face, freetype->unicode_map);
1522                 }
1523                 glyphs->glyphs[glyph_pos] = glyph;
1524                 if (uc < QFreetypeFace::cmapCacheSize)
1525                     freetype->cmapCache[uc] = glyph;
1526             }
1527             ++glyph_pos;
1528         }
1529     } else {
1530         FT_Face face = freetype->face;
1531         for (int i = 0; i < len; ++i) {
1532             unsigned int uc = getChar(str, i, len);
1533             if (mirrored)
1534                 uc = QChar::mirroredChar(uc);
1535             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1536             if (!glyphs->glyphs[glyph_pos]) {
1537 #if !defined(QT_NO_FONTCONFIG)
1538                 if (!mtx) {
1539                     mtx = qt_fontdatabase_mutex();
1540                     mtx->lock();
1541                 }
1542
1543                 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1544 #endif
1545                 {
1546                 redo:
1547                     glyph_t glyph = FT_Get_Char_Index(face, uc);
1548                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1549                         uc = 0x20;
1550                         goto redo;
1551                     }
1552                     glyphs->glyphs[glyph_pos] = glyph;
1553                     if (uc < QFreetypeFace::cmapCacheSize)
1554                         freetype->cmapCache[uc] = glyph;
1555                 }
1556             }
1557             ++glyph_pos;
1558         }
1559     }
1560
1561     *nglyphs = glyph_pos;
1562     glyphs->numGlyphs = glyph_pos;
1563
1564 #if !defined(QT_NO_FONTCONFIG)
1565     if (mtx)
1566         mtx->unlock();
1567 #endif
1568
1569     if (flags & QTextEngine::GlyphIndicesOnly)
1570         return true;
1571
1572     recalcAdvances(glyphs, flags);
1573
1574     return true;
1575 }
1576
1577 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1578 {
1579     FT_Face face = 0;
1580     bool design = (default_hint_style == HintNone ||
1581                    default_hint_style == HintLight ||
1582                    (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1583     for (int i = 0; i < glyphs->numGlyphs; i++) {
1584         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
1585         if (g) {
1586             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1587         } else {
1588             if (!face)
1589                 face = lockFace();
1590             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
1591             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1592                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1593         }
1594         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1595             glyphs->advances_x[i] = glyphs->advances_x[i].round();
1596         glyphs->advances_y[i] = 0;
1597     }
1598     if (face)
1599         unlockFace();
1600 }
1601
1602 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1603 {
1604     FT_Face face = 0;
1605
1606     glyph_metrics_t overall;
1607     // initialize with line height, we get the same behaviour on all platforms
1608     overall.y = -ascent();
1609     overall.height = ascent() + descent() + 1;
1610
1611     QFixed ymax = 0;
1612     QFixed xmax = 0;
1613     for (int i = 0; i < glyphs.numGlyphs; i++) {
1614         Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
1615         if (!g) {
1616             if (!face)
1617                 face = lockFace();
1618             g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
1619         }
1620         if (g) {
1621             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1622             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1623             overall.x = qMin(overall.x, x);
1624             overall.y = qMin(overall.y, y);
1625             xmax = qMax(xmax, x + g->width);
1626             ymax = qMax(ymax, y + g->height);
1627             overall.xoff += g->advance;
1628         } else {
1629             int left  = FLOOR(face->glyph->metrics.horiBearingX);
1630             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1631             int top    = CEIL(face->glyph->metrics.horiBearingY);
1632             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1633
1634             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1635             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1636             overall.x = qMin(overall.x, x);
1637             overall.y = qMin(overall.y, y);
1638             xmax = qMax(xmax, x + TRUNC(right - left));
1639             ymax = qMax(ymax, y + TRUNC(top - bottom));
1640             overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
1641         }
1642     }
1643     overall.height = qMax(overall.height, ymax - overall.y);
1644     overall.width = xmax - overall.x;
1645
1646     if (face)
1647         unlockFace();
1648
1649     return overall;
1650 }
1651
1652 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1653 {
1654     FT_Face face = 0;
1655     glyph_metrics_t overall;
1656     Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
1657     if (!g) {
1658         face = lockFace();
1659         g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
1660     }
1661     if (g) {
1662         overall.x = g->x;
1663         overall.y = -g->y;
1664         overall.width = g->width;
1665         overall.height = g->height;
1666         overall.xoff = g->advance;
1667         if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1668             overall.xoff = overall.xoff.round();
1669     } else {
1670         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1671         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1672         int top    = CEIL(face->glyph->metrics.horiBearingY);
1673         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1674
1675         overall.width = TRUNC(right-left);
1676         overall.height = TRUNC(top-bottom);
1677         overall.x = TRUNC(left);
1678         overall.y = -TRUNC(top);
1679         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1680     }
1681     if (face)
1682         unlockFace();
1683     return overall;
1684 }
1685
1686 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1687 {
1688     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1689 }
1690
1691 static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
1692 {
1693     FT_Matrix m;
1694
1695     m.xx = FT_Fixed(matrix.m11() * 65536);
1696     m.xy = FT_Fixed(-matrix.m21() * 65536);
1697     m.yx = FT_Fixed(-matrix.m12() * 65536);
1698     m.yy = FT_Fixed(matrix.m22() * 65536);
1699
1700     return m;
1701 }
1702
1703 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1704 {
1705     FT_Face face = 0;
1706     glyph_metrics_t overall;
1707     QGlyphSet *glyphSet = 0;
1708     FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
1709     if (cacheEnabled) {
1710         if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1711             // TODO move everything here to a method of its own to access glyphSets
1712             // to be shared with a new method that will replace loadTransformedGlyphSet()
1713             for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1714                 const QGlyphSet &g = transformedGlyphSets.at(i);
1715                 if (g.transformationMatrix.xx == ftMatrix.xx
1716                     && g.transformationMatrix.xy == ftMatrix.xy
1717                     && g.transformationMatrix.yx == ftMatrix.yx
1718                     && g.transformationMatrix.yy == ftMatrix.yy) {
1719
1720                     // found a match, move it to the front
1721                     transformedGlyphSets.move(i, 0);
1722                     glyphSet = &transformedGlyphSets[0];
1723                     break;
1724                 }
1725             }
1726
1727             if (!glyphSet) {
1728                 // don't cache more than 10 transformations
1729                 if (transformedGlyphSets.count() >= 10) {
1730                     transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1731                 } else {
1732                     transformedGlyphSets.prepend(QGlyphSet());
1733                 }
1734                 glyphSet = &transformedGlyphSets[0];
1735                 glyphSet->clear();
1736                 glyphSet->transformationMatrix = ftMatrix;
1737             }
1738             Q_ASSERT(glyphSet);
1739         } else {
1740             glyphSet = &defaultGlyphSet;
1741         }
1742     }
1743     Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
1744     if (!g || g->format != format) {
1745         face = lockFace();
1746         FT_Matrix m = this->matrix;
1747         FT_Matrix_Multiply(&ftMatrix, &m);
1748         freetype->matrix = m;
1749         g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
1750     }
1751
1752     if (g) {
1753         overall.x = g->x;
1754         overall.y = -g->y;
1755         overall.width = g->width;
1756         overall.height = g->height;
1757         overall.xoff = g->advance;
1758     } else {
1759         int left  = FLOOR(face->glyph->metrics.horiBearingX);
1760         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1761         int top    = CEIL(face->glyph->metrics.horiBearingY);
1762         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1763
1764         overall.width = TRUNC(right-left);
1765         overall.height = TRUNC(top-bottom);
1766         overall.x = TRUNC(left);
1767         overall.y = -TRUNC(top);
1768         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1769     }
1770     if (face)
1771         unlockFace();
1772     return overall;
1773 }
1774
1775 QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
1776                                               QFontEngine::GlyphFormat neededFormat,
1777                                               const QTransform &t, QPoint *offset)
1778 {
1779     Q_ASSERT(currentlyLockedAlphaMap.isNull());
1780     lockFace();
1781
1782     if (isBitmapFont())
1783         neededFormat = Format_Mono;
1784     else if (neededFormat == Format_None && defaultFormat != Format_None)
1785         neededFormat = defaultFormat;
1786     else if (neededFormat == Format_None)
1787         neededFormat = Format_A8;
1788
1789     QImage::Format format;
1790     switch (neededFormat) {
1791     case Format_Mono:
1792         format = QImage::Format_Mono;
1793         break;
1794     case Format_A8:
1795         format = QImage::Format_Indexed8;
1796         break;
1797     case Format_A32:
1798         format = QImage::Format_ARGB32;
1799         break;
1800     default:
1801         Q_ASSERT(false);
1802         format = QImage::Format_Invalid;
1803     };
1804
1805     QFontEngineFT::Glyph *glyph;
1806     if (cacheEnabled) {
1807         QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
1808         if (t.type() >= QTransform::TxScale) {
1809             if (t.isAffine())
1810                 gset = loadTransformedGlyphSet(t);
1811             else
1812                 gset = 0;
1813         }
1814
1815         if (gset) {
1816             FT_Matrix m = matrix;
1817             FT_Matrix_Multiply(&gset->transformationMatrix, &m);
1818             FT_Set_Transform(freetype->face, &m, 0);
1819             freetype->matrix = m;
1820         }
1821
1822         if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
1823                                                          neededFormat)) {
1824             return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
1825                                                        offset);
1826         }
1827
1828         glyph = gset->getGlyph(glyphIndex, subPixelPosition);
1829     } else {
1830         FT_Matrix m = matrix;
1831         FT_Matrix extra = QTransformToFTMatrix(t);
1832         FT_Matrix_Multiply(&extra, &m);
1833         FT_Set_Transform(freetype->face, &m, 0);
1834         freetype->matrix = m;
1835         glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
1836     }
1837
1838     if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
1839         unlockFace();
1840         return 0;
1841     }
1842
1843     int pitch;
1844     switch (neededFormat) {
1845     case Format_Mono:
1846         pitch = ((glyph->width + 31) & ~31) >> 3;
1847         break;
1848     case Format_A8:
1849         pitch = (glyph->width + 3) & ~3;
1850         break;
1851     case Format_A32:
1852         pitch = glyph->width * 4;
1853         break;
1854     default:
1855         Q_ASSERT(false);
1856         pitch = 0;
1857     };
1858
1859     if (offset != 0)
1860         *offset = QPoint(glyph->x, -glyph->y);
1861
1862     currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
1863     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1864
1865     QImageData *data = currentlyLockedAlphaMap.data_ptr();
1866     data->is_locked = true;
1867
1868     return &currentlyLockedAlphaMap;
1869 }
1870
1871 void QFontEngineFT::unlockAlphaMapForGlyph()
1872 {
1873     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
1874     unlockFace();
1875     currentlyLockedAlphaMap = QImage();
1876 }
1877
1878 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
1879 {
1880     return defaultGlyphSet.outline_drawing ? 0 :
1881             loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
1882 }
1883
1884 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1885 {
1886     lockFace();
1887
1888     Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
1889     if (!glyph) {
1890         unlockFace();
1891         return QFontEngine::alphaMapForGlyph(g);
1892     }
1893
1894     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1895
1896     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1897     if (antialias) {
1898         QVector<QRgb> colors(256);
1899         for (int i=0; i<256; ++i)
1900             colors[i] = qRgba(0, 0, 0, i);
1901         img.setColorTable(colors);
1902     } else {
1903         QVector<QRgb> colors(2);
1904         colors[0] = qRgba(0, 0, 0, 0);
1905         colors[1] = qRgba(0, 0, 0, 255);
1906         img.setColorTable(colors);
1907     }
1908     Q_ASSERT(img.bytesPerLine() == pitch);
1909     if (glyph->width) {
1910         for (int y = 0; y < glyph->height; ++y)
1911             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1912     }
1913     unlockFace();
1914
1915     return img;
1916 }
1917
1918 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1919 {
1920     if (t.type() > QTransform::TxTranslate)
1921         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1922
1923     lockFace();
1924
1925     Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
1926     if (!glyph) {
1927         unlockFace();
1928         return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1929     }
1930
1931     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1932     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1933     unlockFace();
1934
1935     return img;
1936 }
1937
1938 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1939 {
1940     defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1941 }
1942
1943 int QFontEngineFT::glyphCount() const
1944 {
1945     int count = 0;
1946     FT_Face face = lockFace();
1947     if (face) {
1948         count = face->num_glyphs;
1949         unlockFace();
1950     }
1951     return count;
1952 }
1953
1954 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1955 {
1956     freetype->lock();
1957     FT_Face face = freetype->face;
1958     if (scale == Unscaled) {
1959         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1960         freetype->xsize = face->units_per_EM << 6;
1961         freetype->ysize = face->units_per_EM << 6;
1962     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1963         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1964         freetype->xsize = xsize;
1965         freetype->ysize = ysize;
1966     }
1967     if (freetype->matrix.xx != matrix.xx ||
1968         freetype->matrix.yy != matrix.yy ||
1969         freetype->matrix.xy != matrix.xy ||
1970         freetype->matrix.yx != matrix.yx) {
1971         freetype->matrix = matrix;
1972         FT_Set_Transform(face, &freetype->matrix, 0);
1973     }
1974
1975     return face;
1976 }
1977
1978 void QFontEngineFT::unlockFace() const
1979 {
1980     freetype->unlock();
1981 }
1982
1983 FT_Face QFontEngineFT::non_locked_face() const
1984 {
1985     return freetype->face;
1986 }
1987
1988
1989 QFontEngineFT::QGlyphSet::QGlyphSet()
1990     : outline_drawing(false)
1991 {
1992     transformationMatrix.xx = 0x10000;
1993     transformationMatrix.yy = 0x10000;
1994     transformationMatrix.xy = 0;
1995     transformationMatrix.yx = 0;
1996     memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1997     fast_glyph_count = 0;
1998 }
1999
2000 QFontEngineFT::QGlyphSet::~QGlyphSet()
2001 {
2002     clear();
2003 }
2004
2005 void QFontEngineFT::QGlyphSet::clear()
2006 {
2007     if (fast_glyph_count > 0) {
2008         for (int i = 0; i < 256; ++i) {
2009             if (fast_glyph_data[i]) {
2010                 delete fast_glyph_data[i];
2011                 fast_glyph_data[i] = 0;
2012             }
2013         }
2014         fast_glyph_count = 0;
2015     }
2016     qDeleteAll(glyph_data);
2017     glyph_data.clear();
2018 }
2019
2020 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
2021 {
2022     if (useFastGlyphData(index, subPixelPosition)) {
2023         if (fast_glyph_data[index]) {
2024             delete fast_glyph_data[index];
2025             fast_glyph_data[index] = 0;
2026             if (fast_glyph_count > 0)
2027                 --fast_glyph_count;
2028         }
2029     } else {
2030         delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
2031     }
2032 }
2033
2034 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
2035 {
2036     if (useFastGlyphData(index, subPixelPosition)) {
2037         if (!fast_glyph_data[index])
2038             ++fast_glyph_count;
2039         fast_glyph_data[index] = glyph;
2040     } else {
2041         glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
2042     }
2043 }
2044
2045 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
2046 {
2047     lockFace();
2048     bool hsubpixel = true;
2049     int vfactor = 1;
2050     int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
2051     HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
2052     unlockFace();
2053     return result;
2054 }
2055
2056 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
2057 {
2058     if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2059         return false;
2060
2061     // Increase the reference of this QFreetypeFace since one more QFontEngineFT
2062     // will be using it
2063     freetype->ref.ref();
2064
2065     default_load_flags = fe->default_load_flags;
2066     default_hint_style = fe->default_hint_style;
2067     antialias = fe->antialias;
2068     transform = fe->transform;
2069     embolden = fe->embolden;
2070     obliquen = fe->obliquen;
2071     subpixelType = fe->subpixelType;
2072     lcdFilterType = fe->lcdFilterType;
2073     embeddedbitmap = fe->embeddedbitmap;
2074
2075     return true;
2076 }
2077
2078 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
2079 {
2080     QFontDef fontDef;
2081     fontDef.pixelSize = pixelSize;
2082     QFontEngineFT *fe = new QFontEngineFT(fontDef);
2083     if (!fe->initFromFontEngine(this)) {
2084         delete fe;
2085         return 0;
2086     } else {
2087         return fe;
2088     }
2089 }
2090
2091 QT_END_NAMESPACE
2092
2093 #endif // QT_NO_FREETYPE