source: trunk/src/gui/text/qfontengine_ft.cpp@ 219

Last change on this file since 219 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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