1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include "qmetatype.h"
44 #include "qtextstream.h"
46 #include "qfontengine_ft_p.h"
48 #ifndef QT_NO_FREETYPE
51 #include "qabstractfileengine.h"
52 #include "qthreadstorage.h"
54 #include <private/qharfbuzz_p.h>
56 #include "qfontengine_ft_p.h"
58 #include FT_FREETYPE_H
60 #include FT_SYNTHESIS_H
61 #include FT_TRUETYPE_TABLES_H
62 #include FT_TYPE1_TABLES_H
65 #if defined(FT_LCD_FILTER_H)
66 #include FT_LCD_FILTER_H
69 #if defined(FT_CONFIG_OPTIONS_H)
70 #include FT_CONFIG_OPTIONS_H
73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
74 #define QT_USE_FREETYPE_LCDFILTER
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.
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)
92 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
93 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
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)
100 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
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)
108 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
110 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
111 FT_Face face = (FT_Face)font;
112 FT_ULong ftlen = *length;
115 if ( !FT_IS_SFNT(face) )
116 return HB_Err_Invalid_Argument;
118 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
120 return (HB_Error)error;
122 return HB_Err_Invalid_Argument;
126 // -------------------------- Freetype support ------------------------------
136 QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
140 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
142 QtFreetypeData *qt_getFreetypeData()
144 return theFreetypeData();
147 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
149 QtFreetypeData *qt_getFreetypeData()
151 QtFreetypeData *&freetypeData = theFreetypeData()->localData();
153 freetypeData = new QtFreetypeData;
158 FT_Library qt_getFreetype()
160 QtFreetypeData *freetypeData = qt_getFreetypeData();
161 if (!freetypeData->library)
162 FT_Init_FreeType(&freetypeData->library);
163 return freetypeData->library;
166 int QFreetypeFace::fsType() const
169 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
171 fsType = os2->fsType;
175 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
177 if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags))
180 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
181 return HB_Err_Invalid_SubTable;
183 *nPoints = face->glyph->outline.n_points;
187 if (point > *nPoints)
188 return HB_Err_Invalid_SubTable;
190 *xpos = face->glyph->outline.points[point].x;
191 *ypos = face->glyph->outline.points[point].y;
197 * One font file can contain more than one font (bold/italic for example)
198 * find the right one and return it.
200 * Returns the freetype face or 0 in case of an empty file or any other problems
201 * (like not being able to open the file)
203 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
204 const QByteArray &fontData)
206 if (face_id.filename.isEmpty() && fontData.isEmpty())
209 QtFreetypeData *freetypeData = qt_getFreetypeData();
210 if (!freetypeData->library)
211 FT_Init_FreeType(&freetypeData->library);
213 QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
217 QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
219 if (!face_id.filename.isEmpty()) {
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/'
227 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
229 newFreetype->fontData = QByteArray();
230 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
231 if (!file.open(QIODevice::ReadOnly)) {
234 newFreetype->fontData = file.readAll();
237 newFreetype->fontData = fontData;
239 if (!newFreetype->fontData.isEmpty()) {
240 if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
243 } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
246 newFreetype->face = face;
248 newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
249 Q_CHECK_PTR(newFreetype->hbFace);
250 newFreetype->ref = 1;
251 newFreetype->xsize = 0;
252 newFreetype->ysize = 0;
253 newFreetype->matrix.xx = 0x10000;
254 newFreetype->matrix.yy = 0x10000;
255 newFreetype->matrix.xy = 0;
256 newFreetype->matrix.yx = 0;
257 newFreetype->unicode_map = 0;
258 newFreetype->symbol_map = 0;
259 #ifndef QT_NO_FONTCONFIG
260 newFreetype->charset = 0;
263 memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
265 for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
266 FT_CharMap cm = newFreetype->face->charmaps[i];
267 switch(cm->encoding) {
268 case FT_ENCODING_UNICODE:
269 newFreetype->unicode_map = cm;
271 case FT_ENCODING_APPLE_ROMAN:
272 case FT_ENCODING_ADOBE_LATIN_1:
273 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
274 newFreetype->unicode_map = cm;
276 case FT_ENCODING_ADOBE_CUSTOM:
277 case FT_ENCODING_MS_SYMBOL:
278 if (!newFreetype->symbol_map)
279 newFreetype->symbol_map = cm;
286 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
287 FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
290 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
291 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
292 newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
293 newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
294 newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
296 for (int i = 0; i < 256; i += 8)
297 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
298 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
299 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
300 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
301 FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
304 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
306 freetypeData->faces.insert(face_id, newFreetype.data());
308 newFreetype.take()->release(face_id);
309 // we could return null in principle instead of throwing
312 freetype = newFreetype.take();
317 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
319 QtFreetypeData *freetypeData = qt_getFreetypeData();
323 #ifndef QT_NO_FONTCONFIG
325 FcCharSetDestroy(charset);
327 if(freetypeData->faces.contains(face_id))
328 freetypeData->faces.take(face_id);
331 if (freetypeData->faces.isEmpty()) {
332 FT_Done_FreeType(freetypeData->library);
333 freetypeData->library = 0;
338 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
340 *ysize = qRound(fontDef.pixelSize * 64);
341 *xsize = *ysize * fontDef.stretch / 100;
342 *outline_drawing = false;
345 * Bitmap only faces must match exactly, so find the closest
346 * one (height dominant search)
348 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
350 for (int i = 1; i < face->num_fixed_sizes; i++) {
351 if (qAbs(*ysize - Y_SIZE(face,i)) <
352 qAbs (*ysize - Y_SIZE(face, best)) ||
353 (qAbs (*ysize - Y_SIZE(face, i)) ==
354 qAbs (*ysize - Y_SIZE(face, best)) &&
355 qAbs (*xsize - X_SIZE(face, i)) <
356 qAbs (*xsize - X_SIZE(face, best)))) {
360 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
361 *xsize = X_SIZE(face, best);
362 *ysize = Y_SIZE(face, best);
365 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
366 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
367 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
368 if (err && face->num_fixed_sizes == 1)
369 err = 0; //even more of a workaround...
376 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
380 QFontEngine::Properties QFreetypeFace::properties() const
382 QFontEngine::Properties p;
383 p.postscriptName = FT_Get_Postscript_Name(face);
384 PS_FontInfoRec font_info;
385 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
386 p.copyright = font_info.notice;
387 if (FT_IS_SCALABLE(face)) {
388 p.ascent = face->ascender;
389 p.descent = -face->descender;
390 p.leading = face->height - face->ascender + face->descender;
391 p.emSquare = face->units_per_EM;
392 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
393 face->bbox.xMax - face->bbox.xMin,
394 face->bbox.yMax - face->bbox.yMin);
396 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
397 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
398 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
399 p.emSquare = face->size->metrics.y_ppem;
400 // p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
401 p.boundingBox = QRectF(0, -p.ascent.toReal(),
402 face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
405 p.capHeight = p.ascent;
406 p.lineWidth = face->underline_thickness;
410 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
413 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
414 if (FT_IS_SFNT(face)) {
415 FT_ULong len = *length;
416 result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
423 /* Some fonts (such as MingLiu rely on hinting to scale different
424 components to their correct sizes. While this is really broken (it
425 should be done in the component glyph itself, not the hinter) we
426 will have to live with it.
428 This means we can not use FT_LOAD_NO_HINTING to get the glyph
429 outline. All we can do is to load the unscaled glyph and scale it
430 down manually when required.
432 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
434 x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
435 y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
436 FT_Vector *p = g->outline.points;
437 const FT_Vector *e = p + g->outline.n_points;
439 p->x = FT_MulFix(p->x, x_scale);
440 p->y = FT_MulFix(p->y, y_scale);
445 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
447 const qreal factor = 1/64.;
448 scaleOutline(face, g, x_scale, y_scale);
450 QPointF cp = point.toPointF();
452 // convert the outline to a painter path
454 for (int j = 0; j < g->outline.n_contours; ++j) {
455 int last_point = g->outline.contours[j];
456 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
457 if(!(g->outline.tags[i] & 1)) {
458 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
461 // qDebug("contour: %d -- %d", i, g->outline.contours[j]);
462 // qDebug("first point at %f %f", start.x(), start.y());
468 while (i < last_point) {
470 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
471 // qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
473 switch (g->outline.tags[i] & 3) {
475 // cubic bezier element
478 c[3] = (c[3] + c[2])/2;
482 // quadratic bezier element
485 c[3] = (c[1] + c[2])/2;
486 c[2] = (2*c[1] + c[3])/3;
487 c[1] = (2*c[1] + c[0])/3;
493 // qDebug() << "lineTo" << c[1];
500 c[2] = (2*c[1] + c[3])/3;
501 c[1] = (2*c[1] + c[0])/3;
505 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
506 path->cubicTo(c[1], c[2], c[3]);
511 // qDebug() << "closeSubpath";
512 path->closeSubpath();
516 c[2] = (2*c[1] + c[3])/3;
517 c[1] = (2*c[1] + c[0])/3;
519 // qDebug() << "cubicTo" << c[1] << c[2] << c[3];
520 path->cubicTo(c[1], c[2], c[3]);
526 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
528 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
530 if (slot->format != FT_GLYPH_FORMAT_BITMAP
531 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
534 QPointF cp = point.toPointF();
535 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
536 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
539 QFontEngineFT::Glyph::~Glyph()
544 static const uint subpixel_filter[3][3] = {
550 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
554 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
555 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
556 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
557 res = (mid << 24) + (high << 16) + (mid << 8) + low;
560 res = (alpha << 24) + (red << 16) + (green << 8) + blue;
565 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
568 const int offs = bgr ? -1 : 1;
569 const int w = width * 3;
572 for (int x = 0; x < w; x += 3) {
573 uint red = src[x+1-offs];
574 uint green = src[x+1];
575 uint blue = src[x+1+offs];
576 *dd = filterPixel(red, green, blue, legacyFilter);
584 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
587 const int offs = bgr ? -src_pitch : src_pitch;
589 for (int x = 0; x < width; x++) {
590 uint red = src[x+src_pitch-offs];
591 uint green = src[x+src_pitch];
592 uint blue = src[x+src_pitch+offs];
593 dst[x] = filterPixel(red, green, blue, legacyFilter);
600 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
602 // convolute the bitmap with a triangle filter to get rid of color fringes
603 // If we take account for a gamma value of 2, we end up with
604 // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
605 // as this nicely sums up to 16 :)
610 for (int x = 2; x < width - 2; ++x) {
611 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
612 dst[x] = (uchar) (sum >> 4);
614 dst[width - 2] = dst[width - 1] = 0;
620 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
628 kerning_pairs_loaded = false;
633 default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
634 default_hint_style = HintNone;
635 subpixelType = Subpixel_None;
637 #if defined(FT_LCD_FILTER_H)
638 lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
640 defaultFormat = Format_None;
641 canUploadGlyphsToServer = false;
642 embeddedbitmap = false;
645 QFontEngineFT::~QFontEngineFT()
648 freetype->release(face_id);
649 hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
652 void QFontEngineFT::freeGlyphSets()
654 freeServerGlyphSet(defaultGlyphSet.id);
655 for (int i = 0; i < transformedGlyphSets.count(); ++i)
656 freeServerGlyphSet(transformedGlyphSets.at(i).id);
659 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
660 const QByteArray &fontData)
662 return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
665 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
666 QFreetypeFace *freetypeFace)
668 freetype = freetypeFace;
674 defaultFormat = format;
675 this->antialias = antialias;
678 glyphFormat = QFontEngineGlyphCache::Raster_Mono;
679 else if (format == Format_A8)
680 glyphFormat = QFontEngineGlyphCache::Raster_A8;
681 else if (format == Format_A32)
682 glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
686 symbol = freetype->symbol_map != 0;
687 PS_FontInfoRec psrec;
688 // don't assume that type1 fonts are symbol fonts by default
689 if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
690 symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
693 freetype->hbFace->isSymbolFont = symbol;
695 lbearing = rbearing = SHRT_MIN;
696 freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
698 FT_Face face = lockFace();
700 if (FT_IS_SCALABLE(face)) {
701 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
703 matrix.xy = 0x10000*3/10;
704 FT_Set_Transform(face, &matrix, 0);
705 freetype->matrix = matrix;
709 if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
712 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
713 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
715 // copied from QFontEngineQPF
717 int score = fontDef.weight * fontDef.pixelSize;
718 line_thickness = score / 700;
719 // looks better with thicker line for small pointsizes
720 if (line_thickness < 2 && score >= 1050)
722 underline_position = ((line_thickness * 2) + 3) / 6;
724 if (line_thickness < 1)
727 hbFont.x_ppem = face->size->metrics.x_ppem;
728 hbFont.y_ppem = face->size->metrics.y_ppem;
729 hbFont.x_scale = face->size->metrics.x_scale;
730 hbFont.y_scale = face->size->metrics.y_scale;
732 hbFace = freetype->hbFace;
734 metrics = face->size->metrics;
736 #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
738 TrueType fonts with embedded bitmaps may have a bitmap font specific
739 ascent/descent in the EBLC table. There is no direct public API
740 to extract those values. The only way we've found is to trick freetype
741 into thinking that it's not a scalable font in FT_SelectSize so that
742 the metrics are retrieved from the bitmap strikes.
744 if (FT_IS_SCALABLE(face)) {
745 for (int i = 0; i < face->num_fixed_sizes; ++i) {
746 if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
747 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
749 FT_Select_Size(face, i);
750 metrics.ascender = face->size->metrics.ascender;
751 metrics.descender = face->size->metrics.descender;
752 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
754 face->face_flags |= FT_FACE_FLAG_SCALABLE;
763 fsType = freetype->fsType();
764 defaultGlyphSet.id = allocateServerGlyphSet();
768 void QFontEngineFT::setDefaultHintStyle(HintStyle style)
770 default_hint_style = style;
773 int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
774 bool &hsubpixel, int &vfactor) const
776 int load_flags = FT_LOAD_DEFAULT | default_load_flags;
777 int load_target = default_hint_style == HintLight
778 ? FT_LOAD_TARGET_LIGHT
779 : FT_LOAD_TARGET_NORMAL;
781 if (format == Format_Mono) {
782 load_target = FT_LOAD_TARGET_MONO;
783 } else if (format == Format_A32) {
784 if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
785 if (default_hint_style == HintFull)
786 load_target = FT_LOAD_TARGET_LCD;
788 } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
789 if (default_hint_style == HintFull)
790 load_target = FT_LOAD_TARGET_LCD_V;
795 if (set && set->outline_drawing)
796 load_flags = FT_LOAD_NO_BITMAP;
798 if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || set->outline_drawing)
799 load_flags |= FT_LOAD_NO_HINTING;
801 load_flags |= load_target;
806 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
807 QFixed subPixelPosition,
809 bool fetchMetricsOnly) const
811 // Q_ASSERT(freetype->lock == 1);
813 bool uploadToServer = false;
814 if (format == Format_None) {
815 if (defaultFormat != Format_None) {
816 format = defaultFormat;
817 if (canUploadGlyphsToServer)
818 uploadToServer = true;
820 format = Format_Mono;
824 Glyph *g = set->getGlyph(glyph, subPixelPosition);
825 if (g && g->format == format) {
826 if (uploadToServer && !g->uploadedToServer) {
827 set->setGlyph(glyph, subPixelPosition, 0);
835 QFontEngineFT::GlyphInfo info;
837 Q_ASSERT(format != Format_None);
838 bool hsubpixel = false;
840 int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
843 if (format != Format_Mono && !embeddedbitmap)
844 load_flags |= FT_LOAD_NO_BITMAP;
847 FT_Matrix matrix = freetype->matrix;
848 bool transform = matrix.xx != 0x10000
849 || matrix.yy != 0x10000
854 load_flags |= FT_LOAD_NO_BITMAP;
856 FT_Face face = freetype->face;
859 v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
861 FT_Set_Transform(face, &freetype->matrix, &v);
863 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
864 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
865 load_flags &= ~FT_LOAD_NO_BITMAP;
866 err = FT_Load_Glyph(face, glyph, load_flags);
868 if (err == FT_Err_Too_Few_Arguments) {
869 // this is an error in the bytecode interpreter, just try to run without it
870 load_flags |= FT_LOAD_FORCE_AUTOHINT;
871 err = FT_Load_Glyph(face, glyph, load_flags);
873 if (err != FT_Err_Ok)
874 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
876 if (set->outline_drawing && fetchMetricsOnly)
879 FT_GlyphSlot slot = face->glyph;
880 if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
881 FT_Library library = qt_getFreetype();
883 info.xOff = TRUNC(ROUND(slot->advance.x));
886 uchar *glyph_buffer = 0;
887 int glyph_buffer_size = 0;
888 #if defined(QT_USE_FREETYPE_LCDFILTER)
889 bool useFreetypeRenderGlyph = false;
890 if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
891 err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
892 if (err == FT_Err_Ok)
893 useFreetypeRenderGlyph = true;
896 if (useFreetypeRenderGlyph) {
897 err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
899 if (err != FT_Err_Ok)
900 qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
902 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
904 info.height = slot->bitmap.rows / vfactor;
905 info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
906 info.x = -slot->bitmap_left;
907 info.y = slot->bitmap_top;
909 glyph_buffer_size = info.width * info.height * 4;
910 glyph_buffer = new uchar[glyph_buffer_size];
913 convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
914 else if (vfactor != 1)
915 convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
919 int left = slot->metrics.horiBearingX;
920 int right = slot->metrics.horiBearingX + slot->metrics.width;
921 int top = slot->metrics.horiBearingY;
922 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
923 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
928 FT_Vector_Transform(&vector, &matrix);
933 FT_Vector_Transform(&vector, &matrix);
934 if (l > vector.x) l = vector.x;
935 if (r < vector.x) r = vector.x;
936 if (t < vector.y) t = vector.y;
937 if (b > vector.y) b = vector.y;
940 FT_Vector_Transform(&vector, &matrix);
941 if (l > vector.x) l = vector.x;
942 if (r < vector.x) r = vector.x;
943 if (t < vector.y) t = vector.y;
944 if (b > vector.y) b = vector.y;
947 FT_Vector_Transform(&vector, &matrix);
948 if (l > vector.x) l = vector.x;
949 if (r < vector.x) r = vector.x;
950 if (t < vector.y) t = vector.y;
951 if (b > vector.y) b = vector.y;
959 bottom = FLOOR(bottom);
962 int hpixels = TRUNC(right - left);
963 // subpixel position requires one more pixel
964 if (subPixelPosition > 0 && format != Format_Mono)
968 hpixels = hpixels*3 + 8;
969 info.width = hpixels;
970 info.height = TRUNC(top - bottom);
971 info.x = -TRUNC(left);
978 bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
979 || ((uchar)(info.width) != info.width)
980 || ((uchar)(info.height) != info.height)
981 || ((signed char)(info.x) != info.x)
982 || ((signed char)(info.y) != info.y)
983 || ((signed char)(info.xOff) != info.xOff));
986 delete [] glyph_buffer;
990 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
991 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
992 glyph_buffer_size = pitch * info.height;
993 glyph_buffer = new uchar[glyph_buffer_size];
995 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
997 bitmap.rows = info.height*vfactor;
998 bitmap.width = hpixels;
999 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1000 if (!hsubpixel && vfactor == 1)
1001 bitmap.buffer = glyph_buffer;
1003 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1004 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1005 bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
1007 matrix.xx = (hsubpixel ? 3 : 1) << 16;
1008 matrix.yy = vfactor << 16;
1009 matrix.yx = matrix.xy = 0;
1011 FT_Outline_Transform(&slot->outline, &matrix);
1012 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1013 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1015 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1016 Q_ASSERT(antialias);
1017 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1018 bool useLegacyLcdFilter = false;
1019 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1020 useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
1022 uchar *buffer = bitmap.buffer;
1023 if (!useLegacyLcdFilter) {
1024 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
1025 buffer = convoluted;
1027 convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
1028 delete [] convoluted;
1029 } else if (vfactor != 1) {
1030 convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
1033 if (bitmap.buffer != glyph_buffer)
1034 delete [] bitmap.buffer;
1035 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1036 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1037 uchar *src = slot->bitmap.buffer;
1038 uchar *dst = glyph_buffer;
1039 int h = slot->bitmap.rows;
1040 if (format == Format_Mono) {
1041 int bytes = ((info.width + 7) & ~7) >> 3;
1043 memcpy (dst, src, bytes);
1045 src += slot->bitmap.pitch;
1050 uint *dd = (uint *)dst;
1052 for (int x = 0; x < slot->bitmap.width; x++) {
1053 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1058 src += slot->bitmap.pitch;
1060 } else if (vfactor != 1) {
1062 uint *dd = (uint *)dst;
1063 for (int x = 0; x < slot->bitmap.width; x++) {
1064 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1068 src += slot->bitmap.pitch;
1072 for (int x = 0; x < slot->bitmap.width; x++) {
1073 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1077 src += slot->bitmap.pitch;
1082 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
1083 delete [] glyph_buffer;
1091 g->uploadedToServer = false;
1095 g->linearAdvance = slot->linearHoriAdvance >> 10;
1096 g->width = info.width;
1097 g->height = info.height;
1100 g->advance = info.xOff;
1103 g->data = glyph_buffer;
1105 if (uploadToServer) {
1106 uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
1109 set->setGlyph(glyph, subPixelPosition, g);
1114 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1120 Q_UNUSED(glyphDataSize);
1124 QFontEngine::FaceId QFontEngineFT::faceId() const
1129 QFontEngine::Properties QFontEngineFT::properties() const
1131 Properties p = freetype->properties();
1132 if (p.postscriptName.isEmpty()) {
1133 p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
1136 return freetype->properties();
1139 QFixed QFontEngineFT::emSquareSize() const
1141 if (FT_IS_SCALABLE(freetype->face))
1142 return freetype->face->units_per_EM;
1144 return freetype->face->size->metrics.y_ppem;
1147 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1149 return freetype->getSfntTable(tag, buffer, length);
1152 int QFontEngineFT::synthesized() const
1155 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
1156 s = SynthesizedItalic;
1157 if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
1158 s |= SynthesizedBold;
1159 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
1160 s |= SynthesizedStretch;
1164 QFixed QFontEngineFT::ascent() const
1166 return QFixed::fromFixed(metrics.ascender);
1169 QFixed QFontEngineFT::descent() const
1171 // subtract a pixel to work around QFontMetrics's built-in + 1
1172 return QFixed::fromFixed(-metrics.descender - 64);
1175 QFixed QFontEngineFT::leading() const
1177 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
1180 QFixed QFontEngineFT::xHeight() const
1182 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1183 if (os2 && os2->sxHeight) {
1185 QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1189 return QFontEngine::xHeight();
1192 QFixed QFontEngineFT::averageCharWidth() const
1194 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
1195 if (os2 && os2->xAvgCharWidth) {
1197 QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
1201 return QFontEngine::averageCharWidth();
1204 qreal QFontEngineFT::maxCharWidth() const
1206 return metrics.max_advance >> 6;
1209 static const ushort char_table[] = {
1230 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1233 qreal QFontEngineFT::minLeftBearing() const
1235 if (lbearing == SHRT_MIN)
1236 (void) minRightBearing(); // calculates both
1237 return lbearing.toReal();
1240 qreal QFontEngineFT::minRightBearing() const
1242 if (rbearing == SHRT_MIN) {
1243 lbearing = rbearing = 0;
1244 const QChar *ch = (const QChar *)(const void*)char_table;
1245 QGlyphLayoutArray<char_table_entries> glyphs;
1246 int ng = char_table_entries;
1247 stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
1249 if (glyphs.glyphs[ng]) {
1250 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
1251 lbearing = qMin(lbearing, gi.x);
1252 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1256 return rbearing.toReal();
1259 QFixed QFontEngineFT::lineThickness() const
1261 return line_thickness;
1264 QFixed QFontEngineFT::underlinePosition() const
1266 return underline_position;
1269 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1271 if (!kerning_pairs_loaded) {
1272 kerning_pairs_loaded = true;
1274 if (freetype->face->size->metrics.x_ppem != 0) {
1275 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
1277 const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
1282 QFontEngine::doKerning(g, flags);
1285 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
1287 if (matrix.type() > QTransform::TxShear)
1290 // FT_Set_Transform only supports scalable fonts
1291 if (!FT_IS_SCALABLE(freetype->face))
1295 m.xx = FT_Fixed(matrix.m11() * 65536);
1296 m.xy = FT_Fixed(-matrix.m21() * 65536);
1297 m.yx = FT_Fixed(-matrix.m12() * 65536);
1298 m.yy = FT_Fixed(matrix.m22() * 65536);
1302 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1303 const QGlyphSet &g = transformedGlyphSets.at(i);
1304 if (g.transformationMatrix.xx == m.xx
1305 && g.transformationMatrix.xy == m.xy
1306 && g.transformationMatrix.yx == m.yx
1307 && g.transformationMatrix.yy == m.yy) {
1309 // found a match, move it to the front
1310 transformedGlyphSets.move(i, 0);
1311 gs = &transformedGlyphSets[0];
1317 // don't try to load huge fonts
1318 bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
1319 if (draw_as_outline)
1322 // don't cache more than 10 transformations
1323 if (transformedGlyphSets.count() >= 10) {
1324 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1325 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1327 transformedGlyphSets.prepend(QGlyphSet());
1329 gs = &transformedGlyphSets[0];
1333 gs->id = allocateServerGlyphSet();
1335 gs->transformationMatrix = m;
1336 gs->outline_drawing = draw_as_outline;
1342 QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
1344 int m_subPixelPositionCount = 4;
1345 if (!supportsSubPixelPositions())
1348 QFixed subPixelPosition;
1350 subPixelPosition = x - x.floor();
1351 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
1352 subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
1354 return subPixelPosition;
1357 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
1358 const QFixedPoint *positions,
1363 for (int i = 0; i < num_glyphs; ++i) {
1364 QFixed spp = subPixelPositionForX(positions[i].x);
1365 Glyph *glyph = gs->getGlyph(glyphs[i], spp);
1366 if (glyph == 0 || glyph->format != format) {
1369 FT_Matrix m = matrix;
1370 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
1371 FT_Set_Transform(face, &m, 0);
1372 freetype->matrix = m;
1374 if (!loadGlyph(gs, glyphs[i], spp, format)) {
1387 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1389 FT_Face face = lockFace(Unscaled);
1390 FT_Set_Transform(face, 0, 0);
1391 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1393 int left = face->glyph->metrics.horiBearingX;
1394 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
1395 int top = face->glyph->metrics.horiBearingY;
1396 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
1402 metrics->width = QFixed::fromFixed(right-left);
1403 metrics->height = QFixed::fromFixed(top-bottom);
1404 metrics->x = QFixed::fromFixed(left);
1405 metrics->y = QFixed::fromFixed(-top);
1406 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
1408 if (!FT_IS_SCALABLE(freetype->face))
1409 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
1411 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
1413 FT_Set_Transform(face, &freetype->matrix, 0);
1417 static inline unsigned int getChar(const QChar *str, int &i, const int len)
1419 unsigned int uc = str[i].unicode();
1420 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
1421 uint low = str[i+1].unicode();
1422 if (low >= 0xdc00 && low < 0xe000) {
1423 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
1430 bool QFontEngineFT::canRender(const QChar *string, int len)
1432 FT_Face face = freetype->face;
1436 for ( int i = 0; i < len; i++ ) {
1437 unsigned int uc = getChar(string, i, len);
1438 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1447 for ( int i = 0; i < len; i++ ) {
1448 unsigned int uc = getChar(string, i, len);
1449 if (!FT_Get_Char_Index(face, uc))
1456 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1458 if (!glyphs.numGlyphs)
1461 if (FT_IS_SCALABLE(freetype->face)) {
1462 QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
1464 QVarLengthArray<QFixedPoint> positions;
1465 QVarLengthArray<glyph_t> positioned_glyphs;
1467 matrix.translate(x, y);
1468 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1470 FT_Face face = lockFace(Unscaled);
1471 for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1472 FT_UInt glyph = positioned_glyphs[gl];
1473 FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
1474 freetype->addBitmapToPath(face->glyph, positions[gl], path);
1480 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
1481 QPainterPath *path, QTextItem::RenderFlags)
1483 FT_Face face = lockFace(Unscaled);
1485 for (int gl = 0; gl < numGlyphs; gl++) {
1486 FT_UInt glyph = glyphs[gl];
1488 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
1490 FT_GlyphSlot g = face->glyph;
1491 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1493 QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
1498 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
1499 QTextEngine::ShaperFlags flags) const
1501 if (*nglyphs < len) {
1506 #if !defined(QT_NO_FONTCONFIG)
1507 extern QMutex *qt_fontdatabase_mutex();
1511 bool mirrored = flags & QTextEngine::RightToLeft;
1513 if (freetype->symbol_map) {
1514 FT_Face face = freetype->face;
1515 for ( int i = 0; i < len; ++i ) {
1516 unsigned int uc = getChar(str, i, len);
1517 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1518 if ( !glyphs->glyphs[glyph_pos] ) {
1520 #if !defined(QT_NO_FONTCONFIG)
1522 mtx = qt_fontdatabase_mutex();
1526 if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
1531 glyph = FT_Get_Char_Index(face, uc);
1532 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1537 FT_Set_Charmap(face, freetype->symbol_map);
1538 glyph = FT_Get_Char_Index(face, uc);
1539 FT_Set_Charmap(face, freetype->unicode_map);
1541 glyphs->glyphs[glyph_pos] = glyph;
1542 if (uc < QFreetypeFace::cmapCacheSize)
1543 freetype->cmapCache[uc] = glyph;
1548 FT_Face face = freetype->face;
1549 for (int i = 0; i < len; ++i) {
1550 unsigned int uc = getChar(str, i, len);
1552 uc = QChar::mirroredChar(uc);
1553 glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
1554 if (!glyphs->glyphs[glyph_pos]) {
1555 #if !defined(QT_NO_FONTCONFIG)
1557 mtx = qt_fontdatabase_mutex();
1561 if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
1565 glyph_t glyph = FT_Get_Char_Index(face, uc);
1566 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1570 glyphs->glyphs[glyph_pos] = glyph;
1571 if (uc < QFreetypeFace::cmapCacheSize)
1572 freetype->cmapCache[uc] = glyph;
1579 *nglyphs = glyph_pos;
1580 glyphs->numGlyphs = glyph_pos;
1582 #if !defined(QT_NO_FONTCONFIG)
1587 if (flags & QTextEngine::GlyphIndicesOnly)
1590 recalcAdvances(glyphs, flags);
1595 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1598 bool design = (default_hint_style == HintNone ||
1599 default_hint_style == HintLight ||
1600 (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
1601 for (int i = 0; i < glyphs->numGlyphs; i++) {
1602 Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
1604 glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
1608 g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
1609 glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
1610 : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
1612 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1613 glyphs->advances_x[i] = glyphs->advances_x[i].round();
1614 glyphs->advances_y[i] = 0;
1620 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
1625 glyph_metrics_t overall;
1626 // initialize with line height, we get the same behaviour on all platforms
1627 overall.y = -ascent();
1628 overall.height = ascent() + descent() + 1;
1632 for (int i = 0; i < glyphs.numGlyphs; i++) {
1633 Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
1637 g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
1640 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
1641 QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
1642 overall.x = qMin(overall.x, x);
1643 overall.y = qMin(overall.y, y);
1644 xmax = qMax(xmax, x + g->width);
1645 ymax = qMax(ymax, y + g->height);
1646 overall.xoff += qRound(g->advance);
1648 int left = FLOOR(face->glyph->metrics.horiBearingX);
1649 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1650 int top = CEIL(face->glyph->metrics.horiBearingY);
1651 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1653 QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
1654 QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
1655 overall.x = qMin(overall.x, x);
1656 overall.y = qMin(overall.y, y);
1657 xmax = qMax(xmax, x + TRUNC(right - left));
1658 ymax = qMax(ymax, y + TRUNC(top - bottom));
1659 overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1662 overall.height = qMax(overall.height, ymax - overall.y);
1663 overall.width = xmax - overall.x;
1671 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1674 glyph_metrics_t overall;
1675 Glyph *g = defaultGlyphSet.getGlyph(glyph);
1678 g = loadGlyph(glyph, 0, Format_None, true);
1683 overall.width = g->width;
1684 overall.height = g->height;
1685 overall.xoff = g->advance;
1686 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
1687 overall.xoff = overall.xoff.round();
1689 int left = FLOOR(face->glyph->metrics.horiBearingX);
1690 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1691 int top = CEIL(face->glyph->metrics.horiBearingY);
1692 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1694 overall.width = TRUNC(right-left);
1695 overall.height = TRUNC(top-bottom);
1696 overall.x = TRUNC(left);
1697 overall.y = -TRUNC(top);
1698 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1705 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
1707 return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
1710 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
1713 glyph_metrics_t overall;
1714 QGlyphSet *glyphSet = 0;
1715 if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
1716 // TODO move everything here to a method of its own to access glyphSets
1717 // to be shared with a new method that will replace loadTransformedGlyphSet()
1719 m.xx = FT_Fixed(matrix.m11() * 65536);
1720 m.xy = FT_Fixed(-matrix.m21() * 65536);
1721 m.yx = FT_Fixed(-matrix.m12() * 65536);
1722 m.yy = FT_Fixed(matrix.m22() * 65536);
1723 for (int i = 0; i < transformedGlyphSets.count(); ++i) {
1724 const QGlyphSet &g = transformedGlyphSets.at(i);
1725 if (g.transformationMatrix.xx == m.xx
1726 && g.transformationMatrix.xy == m.xy
1727 && g.transformationMatrix.yx == m.yx
1728 && g.transformationMatrix.yy == m.yy) {
1730 // found a match, move it to the front
1731 transformedGlyphSets.move(i, 0);
1732 glyphSet = &transformedGlyphSets[0];
1738 // don't cache more than 10 transformations
1739 if (transformedGlyphSets.count() >= 10) {
1740 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
1741 freeServerGlyphSet(transformedGlyphSets.at(0).id);
1743 transformedGlyphSets.prepend(QGlyphSet());
1745 glyphSet = &transformedGlyphSets[0];
1747 glyphSet->id = allocateServerGlyphSet();
1748 glyphSet->transformationMatrix = m;
1752 glyphSet = &defaultGlyphSet;
1754 Glyph * g = glyphSet->getGlyph(glyph);
1755 if (!g || g->format != format) {
1757 FT_Matrix m = this->matrix;
1758 FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
1759 freetype->matrix = m;
1760 g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
1766 overall.width = g->width;
1767 overall.height = g->height;
1768 overall.xoff = g->advance;
1770 int left = FLOOR(face->glyph->metrics.horiBearingX);
1771 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1772 int top = CEIL(face->glyph->metrics.horiBearingY);
1773 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1775 overall.width = TRUNC(right-left);
1776 overall.height = TRUNC(top-bottom);
1777 overall.x = TRUNC(left);
1778 overall.y = -TRUNC(top);
1779 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1786 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
1790 GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
1792 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1795 return QFontEngine::alphaMapForGlyph(g);
1798 const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
1800 QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
1802 QVector<QRgb> colors(256);
1803 for (int i=0; i<256; ++i)
1804 colors[i] = qRgba(0, 0, 0, i);
1805 img.setColorTable(colors);
1807 QVector<QRgb> colors(2);
1808 colors[0] = qRgba(0, 0, 0, 0);
1809 colors[1] = qRgba(0, 0, 0, 255);
1810 img.setColorTable(colors);
1812 Q_ASSERT(img.bytesPerLine() == pitch);
1814 for (int y = 0; y < glyph->height; ++y)
1815 memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
1822 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
1824 if (t.type() > QTransform::TxTranslate)
1825 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1829 GlyphFormat glyph_format = Format_A32;
1831 Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
1834 return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
1837 QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
1838 memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
1844 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
1846 defaultGlyphSet.removeGlyphFromCache(glyph, 0);
1849 int QFontEngineFT::glyphCount() const
1852 FT_Face face = lockFace();
1854 count = face->num_glyphs;
1860 FT_Face QFontEngineFT::lockFace(Scaling scale) const
1863 FT_Face face = freetype->face;
1864 if (scale == Unscaled) {
1865 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
1866 freetype->xsize = face->units_per_EM << 6;
1867 freetype->ysize = face->units_per_EM << 6;
1868 } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
1869 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
1870 freetype->xsize = xsize;
1871 freetype->ysize = ysize;
1873 if (freetype->matrix.xx != matrix.xx ||
1874 freetype->matrix.yy != matrix.yy ||
1875 freetype->matrix.xy != matrix.xy ||
1876 freetype->matrix.yx != matrix.yx) {
1877 freetype->matrix = matrix;
1878 FT_Set_Transform(face, &freetype->matrix, 0);
1884 void QFontEngineFT::unlockFace() const
1889 FT_Face QFontEngineFT::non_locked_face() const
1891 return freetype->face;
1895 QFontEngineFT::QGlyphSet::QGlyphSet()
1896 : id(0), outline_drawing(false)
1898 transformationMatrix.xx = 0x10000;
1899 transformationMatrix.yy = 0x10000;
1900 transformationMatrix.xy = 0;
1901 transformationMatrix.yx = 0;
1902 memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
1903 fast_glyph_count = 0;
1906 QFontEngineFT::QGlyphSet::~QGlyphSet()
1911 void QFontEngineFT::QGlyphSet::clear()
1913 if (fast_glyph_count > 0) {
1914 for (int i = 0; i < 256; ++i) {
1915 if (fast_glyph_data[i]) {
1916 delete fast_glyph_data[i];
1917 fast_glyph_data[i] = 0;
1920 fast_glyph_count = 0;
1922 qDeleteAll(glyph_data);
1926 void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
1928 if (useFastGlyphData(index, subPixelPosition)) {
1929 if (fast_glyph_data[index]) {
1930 delete fast_glyph_data[index];
1931 fast_glyph_data[index] = 0;
1932 if (fast_glyph_count > 0)
1936 delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
1940 void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
1942 if (useFastGlyphData(index, subPixelPosition)) {
1943 if (!fast_glyph_data[index])
1945 fast_glyph_data[index] = glyph;
1947 glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
1951 unsigned long QFontEngineFT::allocateServerGlyphSet()
1956 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
1961 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
1964 bool hsubpixel = true;
1966 int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
1967 HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
1972 bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
1974 if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
1977 // Increase the reference of this QFreetypeFace since one more QFontEngineFT
1979 freetype->ref.ref();
1981 default_load_flags = fe->default_load_flags;
1982 default_hint_style = fe->default_hint_style;
1983 antialias = fe->antialias;
1984 transform = fe->transform;
1985 embolden = fe->embolden;
1986 subpixelType = fe->subpixelType;
1987 lcdFilterType = fe->lcdFilterType;
1988 canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
1989 embeddedbitmap = fe->embeddedbitmap;
1994 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
1997 fontDef.pixelSize = pixelSize;
1998 QFontEngineFT *fe = new QFontEngineFT(fontDef);
1999 if (!fe->initFromFontEngine(this)) {
2009 #endif // QT_NO_FREETYPE