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

Last change on this file since 605 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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