📄 qfontengine.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 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://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** 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 <qdebug.h>#include <private/qfontengine_p.h>#include "qbitmap.h"#include "qpainter.h"#include "qpainterpath.h"#include "qvarlengtharray.h"#include <private/qpdf_p.h>#include <private/qmath_p.h>#include <qendian.h>QFontEngine::QFontEngine() : QObject(){ ref = 0; cache_count = 0; fsType = 0;#if defined(Q_WS_WIN) script_cache = 0; cmap = 0;#endif symbol = false;}#ifndef Q_WS_WINQFontEngine::~QFontEngine(){}QFixed QFontEngine::lineThickness() const{ // ad hoc algorithm int score = fontDef.weight * fontDef.pixelSize; int lw = score / 700; // looks better with thicker line for small pointsizes if (lw < 2 && score >= 1050) lw = 2; if (lw == 0) lw = 1; return lw;}QFixed QFontEngine::underlinePosition() const{ return ((lineThickness() * 2) + 3) / 6;}#endifQFixed QFontEngine::xHeight() const{ QGlyphLayout glyphs[8]; int nglyphs = 7; QChar x((ushort)'x'); stringToCMap(&x, 1, glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly); glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs[0].glyph); return bb.height;}QFixed QFontEngine::averageCharWidth() const{ QGlyphLayout glyphs[8]; int nglyphs = 7; QChar x((ushort)'x'); stringToCMap(&x, 1, glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly); glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs[0].glyph); return bb.xoff;}void QFontEngine::getGlyphPositions(const QGlyphLayout *glyphs, int nglyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions){ QFixed xpos; QFixed ypos; const bool transform = matrix.m11() != 1. || matrix.m12() != 0. || matrix.m21() != 0. || matrix.m22() != 1.; if (!transform) { xpos = QFixed::fromReal(matrix.dx()); ypos = QFixed::fromReal(matrix.dy()); } int current = 0; if (flags & QTextItem::RightToLeft) { int i = nglyphs; int totalKashidas = 0; while(i--) { xpos += glyphs[i].advance.x + QFixed::fromFixed(glyphs[i].space_18d6); ypos += glyphs[i].advance.y; totalKashidas += glyphs[i].nKashidas; } positions.resize(nglyphs+totalKashidas); glyphs_out.resize(nglyphs+totalKashidas); i = 0; while(i < nglyphs) { if (glyphs[i].attributes.dontPrint) { ++i; continue; } xpos -= glyphs[i].advance.x; ypos -= glyphs[i].advance.y; QFixed gpos_x = xpos + glyphs[i].offset.x; QFixed gpos_y = ypos + glyphs[i].offset.y; if (transform) { QPointF gpos(gpos_x.toReal(), gpos_y.toReal()); gpos = gpos * matrix; gpos_x = QFixed::fromReal(gpos.x()); gpos_y = QFixed::fromReal(gpos.y()); } positions[current].x = gpos_x; positions[current].y = gpos_y; glyphs_out[current] = glyphs[i].glyph; ++current; if (glyphs[i].nKashidas) { QChar ch(0x640); // Kashida character QGlyphLayout g[8]; int nglyphs = 7; stringToCMap(&ch, 1, g, &nglyphs, 0); for (uint k = 0; k < glyphs[i].nKashidas; ++k) { xpos -= g[0].advance.x; ypos -= g[0].advance.y; QFixed gpos_x = xpos + glyphs[i].offset.x; QFixed gpos_y = ypos + glyphs[i].offset.y; if (transform) { QPointF gpos(gpos_x.toReal(), gpos_y.toReal()); gpos = gpos * matrix; gpos_x = QFixed::fromReal(gpos.x()); gpos_y = QFixed::fromReal(gpos.y()); } positions[current].x = gpos_x; positions[current].y = gpos_y; glyphs_out[current] = g[0].glyph; ++current; } } else { xpos -= QFixed::fromFixed(glyphs[i].space_18d6); } ++i; } } else { positions.resize(nglyphs); glyphs_out.resize(nglyphs); int i = 0; if (!transform) { while (i < nglyphs) { if (!glyphs[i].attributes.dontPrint) { positions[current].x = xpos + glyphs[i].offset.x; positions[current].y = ypos + glyphs[i].offset.y; glyphs_out[current] = glyphs[i].glyph; xpos += glyphs[i].advance.x + QFixed::fromFixed(glyphs[i].space_18d6); ypos += glyphs[i].advance.y; ++current; } ++i; } } else { positions.resize(nglyphs); glyphs_out.resize(nglyphs); int i = 0; while (i < nglyphs) { if (!glyphs[i].attributes.dontPrint) { QFixed gpos_x = xpos + glyphs[i].offset.x; QFixed gpos_y = ypos + glyphs[i].offset.y; QPointF gpos(gpos_x.toReal(), gpos_y.toReal()); gpos = gpos * matrix; positions[current].x = QFixed::fromReal(gpos.x()); positions[current].y = QFixed::fromReal(gpos.y()); glyphs_out[current] = glyphs[i].glyph; xpos += glyphs[i].advance.x + QFixed::fromFixed(glyphs[i].space_18d6); ypos += glyphs[i].advance.y; ++current; } ++i; } } } positions.resize(current); glyphs_out.resize(current); Q_ASSERT(positions.size() == glyphs_out.size());}glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout *glyphs, int numGlyphs){ glyph_metrics_t overall; QFixed ymax = 0; QFixed xmax = 0; for (int i = 0; i < numGlyphs; i++) { glyph_metrics_t bb = boundingBox(glyphs[i].glyph); QFixed x = overall.xoff + glyphs[i].offset.x + bb.x; QFixed y = overall.yoff + glyphs[i].offset.y + bb.y; overall.x = qMin(overall.x, x); overall.y = qMin(overall.y, y); xmax = qMax(xmax, x + bb.width); ymax = qMax(ymax, y + bb.height); overall.xoff += bb.xoff; overall.yoff += bb.yoff; } overall.height = qMax(overall.height, ymax - overall.y); overall.width = xmax - overall.x; return overall;}void QFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags){ if (!numGlyphs) return; QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> positioned_glyphs; QTransform matrix; matrix.translate(x, y); getGlyphPositions(glyphs, numGlyphs, matrix, flags, positioned_glyphs, positions); addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);}#define GRID(x, y) grid[(y)*(w+1) + (x)]#define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))enum { EdgeRight = 0x1, EdgeDown = 0x2, EdgeLeft = 0x4, EdgeUp = 0x8};static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path){ Q_UNUSED(h); path->moveTo(x + x0, y + y0); while (GRID(x, y)) { if (GRID(x, y) & EdgeRight) { while (GRID(x, y) & EdgeRight) { GRID(x, y) &= ~EdgeRight; ++x; } Q_ASSERT(x <= w); path->lineTo(x + x0, y + y0); continue; } if (GRID(x, y) & EdgeDown) { while (GRID(x, y) & EdgeDown) { GRID(x, y) &= ~EdgeDown; ++y; } Q_ASSERT(y <= h); path->lineTo(x + x0, y + y0); continue; } if (GRID(x, y) & EdgeLeft) { while (GRID(x, y) & EdgeLeft) { GRID(x, y) &= ~EdgeLeft; --x; } Q_ASSERT(x >= 0); path->lineTo(x + x0, y + y0); continue; } if (GRID(x, y) & EdgeUp) { while (GRID(x, y) & EdgeUp) { GRID(x, y) &= ~EdgeUp; --y; } Q_ASSERT(y >= 0); path->lineTo(x + x0, y + y0); continue; } } path->closeSubpath();}void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path){ uint *grid = new uint[(w+1)*(h+1)]; // set up edges for (int y = 0; y <= h; ++y) { for (int x = 0; x <= w; ++x) { bool topLeft = (x == 0)|(y == 0) ? false : SET(x - 1, y - 1); bool topRight = (x == w)|(y == 0) ? false : SET(x, y - 1); bool bottomLeft = (x == 0)|(y == h) ? false : SET(x - 1, y); bool bottomRight = (x == w)|(y == h) ? false : SET(x, y); GRID(x, y) = 0; if ((!topRight) & bottomRight) GRID(x, y) |= EdgeRight; if ((!bottomRight) & bottomLeft) GRID(x, y) |= EdgeDown; if ((!bottomLeft) & topLeft) GRID(x, y) |= EdgeLeft; if ((!topLeft) & topRight) GRID(x, y) |= EdgeUp; } } // collect edges for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { if (!GRID(x, y)) continue; // found start of a contour, follow it collectSingleContour(x0, y0, grid, x, y, w, h, path); } } delete [] grid;}#undef GRID#undef SETvoid QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags){ glyph_metrics_t metrics = boundingBox(glyphs, numGlyphs); int w = metrics.width.toInt(); int h = metrics.height.toInt(); if (w <= 0 || h <= 0) return; QBitmap bm(w, h); QPainter p(&bm); p.fillRect(0, 0, w, h, Qt::color0); p.setPen(Qt::color1); QTextItemInt item; item.flags = flags; item.ascent = -metrics.y; item.descent = metrics.height - item.ascent; item.width = metrics.width; item.chars = 0; item.num_chars = 0; item.logClusters = 0; item.glyphs = const_cast<QGlyphLayout *>(glyphs); item.num_glyphs = numGlyphs; item.fontEngine = this; item.f = 0; p.drawTextItem(QPointF(-metrics.x.toReal(), item.ascent.toReal()), item); p.end(); QImage image = bm.toImage(); image = image.convertToFormat(QImage::Format_Mono); const uchar *image_data = image.bits(); uint bpl = image.bytesPerLine(); qt_addBitmapToPath(x, y - item.ascent.toReal(), image_data, bpl, w, h, path);}void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs, QPainterPath *path, QTextItem::RenderFlags flags){ qreal x = positions[0].x.toReal(); qreal y = positions[0].y.toReal(); QVarLengthArray<QGlyphLayout> g(nGlyphs); memset(g.data(), 0, nGlyphs*sizeof(QGlyphLayout)); for (int i = 0; i < nGlyphs; ++i) { g[i].glyph = glyphs[i]; if (i < nGlyphs - 1) { g[i].advance.x = positions[i+1].x - positions[i].x; g[i].advance.y = positions[i+1].y - positions[i].y; } else { g[i].advance.x = QFixed::fromReal(maxCharWidth()); g[i].advance.y = 0; } } addBitmapFontToPath(x, y, g.data(), nGlyphs, path, flags);}QImage QFontEngine::alphaMapForGlyph(glyph_t glyph){ glyph_metrics_t gm = boundingBox(glyph); int glyph_x = qFloor(gm.x.toReal()); int glyph_y = qFloor(gm.y.toReal()); int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x; int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y; if (glyph_width <= 0 || glyph_height <= 0) return QImage(); QFixedPoint pt; pt.x = 0; pt.y = -glyph_y; // the baseline QPainterPath path; QImage im(glyph_width + qAbs(glyph_x) + 4, glyph_height, QImage::Format_ARGB32_Premultiplied); im.fill(Qt::transparent);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -