📄 qfontengine_x11.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qbitmap.h"// #define FONTENGINE_DEBUG#include <qbytearray.h>#include <qdebug.h>#include <qtextcodec.h>#include "qfontdatabase.h"#include "qpaintdevice.h"#include "qpainter.h"#include "qvarlengtharray.h"#include "qwidget.h"#include "qsettings.h"#include "qfile.h"#include <private/qpaintengine_x11_p.h>#include "qfont.h"#include "qfont_p.h"#include "qfontengine_p.h"#include "qopentype_p.h"#include <qhash.h>#include <private/qpainter_p.h>#include <private/qunicodetables_p.h>#include <private/qt_x11_p.h>#include "qx11info_x11.h"#include <math.h>#include <limits.h>#ifndef QT_NO_FREETYPE#include <ft2build.h>#include FT_FREETYPE_H#include FT_OUTLINE_H#include FT_TRUETYPE_TABLES_H#include FT_TYPE1_TABLES_H/* * Freetype 2.1.7 and earlier used width/height * for matching sizes in the BDF and PCF loaders. * This has been fixed for 2.1.8. */#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)#else#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)#endif#define FLOOR(x) ((x) & -64)#define CEIL(x) (((x)+63) & -64)#define TRUNC(x) ((x) >> 6)#define ROUND(x) (((x)+32) & -64)// -------------------------- Freetype support ------------------------------struct QFreetypeFace{ void computeSize(const QFontDef &fontDef, int *xsize, int *ysize); QFontEngine::Properties properties() const; QByteArray getSfntTable(uint tag) const; static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id); void release(const QFontEngine::FaceId &face_id); void lock() { Q_ASSERT(_lock == 0); while (!_lock.testAndSet(0, 1)) usleep(100); } void unlock() { if (!_lock.testAndSet(1, 0)) Q_ASSERT(false); } FT_Face face;#ifndef QT_NO_FONTCONFIG FcCharSet *charset;#endif int xsize; // 26.6 int ysize; // 26.6 FT_Matrix matrix; FT_CharMap unicode_map; FT_CharMap symbol_map; enum { cmapCacheSize = 0x200 }; glyph_t cmapCache[cmapCacheSize]; int fsType() const;private: QFreetypeFace() {} ~QFreetypeFace() {} QAtomic ref; QAtomic _lock;};static FT_Library library = 0;static QHash<QFontEngine::FaceId, QFreetypeFace *> *freetypeFaces = 0;int QFreetypeFace::fsType() const{ int fsType = 0; TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); if (os2) fsType = os2->fsType; return fsType;}QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id){ if (face_id.filename.isEmpty()) return 0; if (!library) FT_Init_FreeType(&library); if (!freetypeFaces) freetypeFaces = new QHash<QFontEngine::FaceId, QFreetypeFace *>(); QFreetypeFace *freetype = freetypeFaces->value(face_id, 0); if (!freetype) { FT_Face face; if (FT_New_Face(library, face_id.filename, face_id.index, &face)) return 0; freetype = new QFreetypeFace; freetype->face = face; freetype->ref = 0; freetype->_lock = 0; freetype->xsize = 0; freetype->ysize = 0; freetype->matrix.xx = 0x10000; freetype->matrix.yy = 0x10000; freetype->matrix.xy = 0; freetype->matrix.yx = 0; freetype->unicode_map = 0; freetype->symbol_map = 0;#ifndef QT_NO_FONTCONFIG freetype->charset = 0;#endif memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache)); for (int i = 0; i < freetype->face->num_charmaps; ++i) { FT_CharMap cm = freetype->face->charmaps[i]; switch(cm->encoding) { case ft_encoding_unicode: freetype->unicode_map = cm; break; case ft_encoding_apple_roman: case ft_encoding_latin_1: if (!freetype->unicode_map || freetype->unicode_map->encoding != ft_encoding_unicode) freetype->unicode_map = cm; break; case ft_encoding_adobe_custom: case ft_encoding_symbol: if (!freetype->symbol_map) freetype->symbol_map = cm; break; default: break; } } if (!FT_IS_SCALABLE(freetype->face) && freetype->face->num_fixed_sizes == 1) FT_Set_Char_Size (face, X_SIZE(freetype->face, 0), Y_SIZE(freetype->face, 0), 0, 0);# if 0 FcChar8 *name; FcPatternGetString(pattern, FC_FAMILY, 0, &name); qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name, freetype->face->charmap ? freetype->face->charmap->encoding : 0, freetype->unicode_map ? freetype->unicode_map->encoding : 0, freetype->symbol_map ? freetype->symbol_map->encoding : 0); for (int i = 0; i < 256; i += 8) qDebug(" %x: %d %d %d %d %d %d %d %d", i, FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i));#endif FT_Set_Charmap(freetype->face, freetype->unicode_map); freetypeFaces->insert(face_id, freetype); } freetype->ref.ref(); return freetype;}void QFreetypeFace::release(const QFontEngine::FaceId &face_id){ if (!ref.deref()) { FT_Done_Face(face);#ifndef QT_NO_FONTCONFIG if (charset) FcCharSetDestroy(charset);#endif freetypeFaces->take(face_id); delete this; } if (!freetypeFaces->size()) { delete freetypeFaces; freetypeFaces = 0; FT_Done_FreeType(library); library = 0; }}void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize){ *ysize = fontDef.pixelSize << 6; *xsize = *ysize * fontDef.stretch / 100; /* * Bitmap only faces must match exactly, so find the closest * one (height dominant search) */ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) { int best = 0; for (int i = 1; i < face->num_fixed_sizes; i++) { if (qAbs(*ysize - Y_SIZE(face,i)) < qAbs (*ysize - Y_SIZE(face, best)) || (qAbs (*ysize - Y_SIZE(face, i)) == qAbs (*ysize - Y_SIZE(face, best)) && qAbs (*xsize - X_SIZE(face, i)) < qAbs (*xsize - X_SIZE(face, best)))) { best = i; } } if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) { *xsize = X_SIZE(face, best); *ysize = Y_SIZE(face, best); } else *xsize = *ysize = 0; }}QFontEngine::Properties QFreetypeFace::properties() const{ QFontEngine::Properties p; p.postscriptName = FT_Get_Postscript_Name(face); PS_FontInfoRec font_info; if (FT_Get_PS_Font_Info(face, &font_info) == 0) p.copyright = font_info.notice; if (FT_IS_SCALABLE(face)) { p.ascent = face->ascender; p.descent = -face->descender; p.leading = face->height - face->ascender + face->descender; p.emSquare = face->units_per_EM; p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax, face->bbox.xMax - face->bbox.xMin, face->bbox.yMax - face->bbox.yMin); } else { p.ascent = QFixed::fromFixed(face->size->metrics.ascender); p.descent = QFixed::fromFixed(-face->size->metrics.descender); p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender); p.emSquare = face->size->metrics.y_ppem; p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.); } p.italicAngle = 0; p.capHeight = p.ascent; p.lineWidth = face->underline_thickness; return p;}QByteArray QFreetypeFace::getSfntTable(uint tag) const{ QByteArray table;#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103 if (FT_IS_SFNT(face)) { FT_ULong length = 0; FT_Load_Sfnt_Table(face, tag, 0, 0, &length); if (length != 0) { table.resize(length); FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte *)table.data(), &length); } }#endif return table;}static void addGlyphToPath(FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, bool no_scale = false){ qreal factor = no_scale ? 1. : 1./64.; QPointF cp = point.toPointF(); // convert the outline to a painter path int i = 0; for (int j = 0; j < g->outline.n_contours; ++j) { int last_point = g->outline.contours[j]; QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor); if(!(g->outline.tags[i] & 1)) { start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor); start /= 2; }// qDebug("contour: %d -- %d", i, g->outline.contours[c]);// qDebug("first point at %f %f", start.x(), start.y()); path->moveTo(start); QPointF c[4]; c[0] = start; int n = 1; while (i < last_point) { ++i; c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);// qDebug() << " i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n]; ++n; switch (g->outline.tags[i] & 3) { case 2: // cubic bezier element if (n < 4) continue; c[3] = (c[3] + c[2])/2; --i; break; case 0: // quadratic bezier element if (n < 3) continue; c[3] = (c[1] + c[2])/2; c[2] = (2*c[1] + c[3])/3; c[1] = (2*c[1] + c[0])/3; --i; break; case 1: case 3: if (n == 2) {// qDebug() << "lineTo" << c[1]; path->lineTo(c[1]); c[0] = c[1]; n = 1; continue; } else if (n == 3) { c[3] = c[2]; c[2] = (2*c[1] + c[3])/3; c[1] = (2*c[1] + c[0])/3; } break; }// qDebug() << "cubicTo" << c[1] << c[2] << c[3]; path->cubicTo(c[1], c[2], c[3]); c[0] = c[3]; n = 1; } if (n == 1) {// qDebug() << "closeSubpath"; path->closeSubpath(); } else { c[3] = start; if (n == 2) { c[2] = (2*c[1] + c[3])/3; c[1] = (2*c[1] + c[0])/3; }// qDebug() << "cubicTo" << c[1] << c[2] << c[3]; path->cubicTo(c[1], c[2], c[3]); } ++i; }}static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false){ if (slot->format != FT_GLYPH_FORMAT_BITMAP || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO) return; QPointF cp = point.toPointF(); uchar *src = slot->bitmap.buffer; int h = slot->bitmap.rows; int w = slot->bitmap.width; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uchar pixel = src[x >> 3]; if (!pixel) { x += 8; continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -