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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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