📄 qfontsubset.cpp
字号:
} case QPainterPath::CurveToDataElement: Q_ASSERT(false); break; }// qDebug() << " appending oncurve point " << QPoint(p.x, p.y); points->append(p); } int start = endPoints->size() ? endPoints->at(endPoints->size()-1) + 1 : 0; int end = points->size() - 1; if (points->at(end).x == points->at(start).x && points->at(end).y == points->at(start).y) points->takeLast(); endPoints->append(points->size() - 1);}static void getBounds(const QList<TTF_POINT> &points, qint16 *xmin, qint16 *xmax, qint16 *ymin, qint16 *ymax){ *xmin = points.at(0).x; *xmax = *xmin; *ymin = points.at(0).y; *ymax = *ymin; for (int i = 1; i < points.size(); ++i) { *xmin = qMin(*xmin, points.at(i).x); *xmax = qMax(*xmax, points.at(i).x); *ymin = qMin(*ymin, points.at(i).y); *ymax = qMax(*ymax, points.at(i).y); }}static int convertToRelative(QList<TTF_POINT> *points){ // convert points to relative and setup flags// qDebug() << "relative points:"; qint16 prev_x = 0; qint16 prev_y = 0; int point_array_size = 0; for (int i = 0; i < points->size(); ++i) { const int x = points->at(i).x; const int y = points->at(i).y; TTF_POINT rel; rel.x = x - prev_x; rel.y = y - prev_y; rel.flags = points->at(i).flags; Q_ASSERT(rel.flags < 2); if (!rel.x) { rel.flags |= XSame; } else if (rel.x > 0 && rel.x < 256) { rel.flags |= XShortVector|XShortPositive; point_array_size++; } else if (rel.x < 0 && rel.x > -256) { rel.flags |= XShortVector; rel.x = -rel.x; point_array_size++; } else { point_array_size += 2; } if (!rel.y) { rel.flags |= YSame; } else if (rel.y > 0 && rel.y < 256) { rel.flags |= YShortVector|YShortPositive; point_array_size++; } else if (rel.y < 0 && rel.y > -256) { rel.flags |= YShortVector; rel.y = -rel.y; point_array_size++; } else { point_array_size += 2; } (*points)[i] = rel;// #define toString(x) ((rel.flags & x) ? #x : "")// qDebug() << " " << QPoint(rel.x, rel.y) << "flags="// << toString(OnCurve) << toString(XShortVector)// << (rel.flags & XShortVector ? toString(XShortPositive) : toString(XSame))// << toString(YShortVector)// << (rel.flags & YShortVector ? toString(YShortPositive) : toString(YSame)); prev_x = x; prev_y = y; } return point_array_size;}static void getGlyphData(QTtfGlyph *glyph, const QList<TTF_POINT> &points, const QList<int> &endPoints, int point_array_size){ const int max_size = 5*sizeof(qint16) // header + endPoints.size()*sizeof(quint16) // end points of contours + sizeof(quint16) // instruction length == 0 + points.size()*(1) // flags + point_array_size; // coordinates glyph->data.resize(max_size); QTtfStream s(glyph->data); s << qint16(endPoints.size()) << glyph->xMin << glyph->yMin << glyph->xMax << glyph->yMax; for (int i = 0; i < endPoints.size(); ++i) s << quint16(endPoints.at(i)); s << quint16(0); // instruction length // emit flags for (int i = 0; i < points.size(); ++i) s << quint8(points.at(i).flags); // emit points for (int i = 0; i < points.size(); ++i) { quint8 flags = points.at(i).flags; qint16 x = points.at(i).x; if (flags & XShortVector) s << quint8(x); else if (!(flags & XSame)) s << qint16(x); } for (int i = 0; i < points.size(); ++i) { quint8 flags = points.at(i).flags; qint16 y = points.at(i).y; if (flags & YShortVector) s << quint8(y); else if (!(flags & YSame)) s << qint16(y); }// qDebug() << "offset=" << s.offset() << "max_size=" << max_size << "point_array_size=" << point_array_size; Q_ASSERT(s.offset() == max_size); glyph->numContours = endPoints.size(); glyph->numPoints = points.size();}static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem){ QList<TTF_POINT> points; QList<int> endPoints; QTtfGlyph glyph; glyph.index = index; glyph.advanceWidth = qRound(advance * 2048. / ppem); glyph.lsb = qRound(lsb * 2048. / ppem); if (!path.elementCount()) { //qDebug("glyph %d is empty", index); lsb = 0; glyph.xMin = glyph.xMax = glyph.yMin = glyph.yMax = 0; glyph.numContours = 0; glyph.numPoints = 0; return glyph; } convertPath(path, &points, &endPoints, ppem);// qDebug() << "number of contours=" << endPoints.size();// for (int i = 0; i < points.size(); ++i)// qDebug() << " point[" << i << "] = " << QPoint(points.at(i).x, points.at(i).y) << " flags=" << points.at(i).flags;// qDebug() << "endPoints:";// for (int i = 0; i < endPoints.size(); ++i)// qDebug() << endPoints.at(i); getBounds(points, &glyph.xMin, &glyph.xMax, &glyph.yMin, &glyph.yMax); int point_array_size = convertToRelative(&points); getGlyphData(&glyph, points, endPoints, point_array_size); return glyph;}static bool operator <(const QTtfGlyph &g1, const QTtfGlyph &g2){ return g1.index < g2.index;}static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs){ const int max_size_small = 65536*2; QList<QTtfGlyph> glyphs = _glyphs; qSort(glyphs); Q_ASSERT(tables.maxp.numGlyphs == glyphs.at(glyphs.size()-1).index + 1); int nGlyphs = tables.maxp.numGlyphs; int glyf_size = 0; for (int i = 0; i < glyphs.size(); ++i) glyf_size += (glyphs.at(i).data.size() + 3) & ~3; tables.head.indexToLocFormat = glyf_size < max_size_small ? 0 : 1; tables.hhea.numberOfHMetrics = nGlyphs; QTtfTable glyf; glyf.tag = MAKE_TAG('g', 'l', 'y', 'f'); QTtfTable loca; loca.tag = MAKE_TAG('l', 'o', 'c', 'a'); loca.data.resize(glyf_size < max_size_small ? (nGlyphs+1)*sizeof(quint16) : (nGlyphs+1)*sizeof(quint32)); QTtfStream ls(loca.data); QTtfTable hmtx; hmtx.tag = MAKE_TAG('h', 'm', 't', 'x'); hmtx.data.resize(nGlyphs*4); QTtfStream hs(hmtx.data); int pos = 0; for (int i = 0; i < nGlyphs; ++i) { int gpos = glyf.data.size(); quint16 advance = 0; qint16 lsb = 0; if (glyphs[pos].index == i) { // emit glyph// qDebug("emitting glyph %d: size=%d", i, glyphs.at(i).data.size()); glyf.data += glyphs.at(pos).data; while (glyf.data.size() & 1) glyf.data.append('\0'); advance = glyphs.at(pos).advanceWidth; lsb = glyphs.at(pos).lsb; ++pos; } if (glyf_size < max_size_small) { // use short loca format ls << quint16(gpos>>1); } else { // use long loca format ls << quint32(gpos); } hs << advance << lsb; } if (glyf_size < max_size_small) { // use short loca format ls << quint16(glyf.data.size()>>1); } else { // use long loca format ls << quint32(glyf.data.size()); } Q_ASSERT(loca.data.size() == ls.offset()); Q_ASSERT(hmtx.data.size() == hs.offset()); QList<QTtfTable> list; list.append(glyf); list.append(loca); list.append(hmtx); return list;}static bool operator <(const QTtfTable &t1, const QTtfTable &t2){ return t1.tag < t2.tag;}static QByteArray bindFont(const QList<QTtfTable>& _tables){ QList<QTtfTable> tables = _tables; qSort(tables); QByteArray font; const int header_size = sizeof(qint32) + 4*sizeof(quint16); const int directory_size = 4*sizeof(quint32)*tables.size(); font.resize(header_size + directory_size); int log2 = 0; int pow = 1; int n = tables.size() >> 1; while (n) { ++log2; pow <<= 1; n >>= 1; } quint32 head_offset = 0; { QTtfStream f(font);// Offset Table// Type Name Description// qint32 sfnt version 0x00010000 for version 1.0.// quint16 numTables Number of tables.// quint16 searchRange (Maximum power of 2 <= numTables) x 16.// quint16 entrySelector Log2(maximum power of 2 <= numTables).// quint16 rangeShift NumTables x 16-searchRange. f << qint32(0x00010000) << quint16(tables.size()) << quint16(16*pow) << quint16(log2) << quint16(16*(tables.size() - pow));// Table Directory// Type Name Description// quint32 tag 4 -byte identifier.// quint32 checkSum CheckSum for this table.// quint32 offset Offset from beginning of TrueType font file.// quint32 length Length of this table. quint32 table_offset = header_size + directory_size; for (int i = 0; i < tables.size(); ++i) { const QTtfTable &t = tables.at(i); const quint32 size = (t.data.size() + 3) & ~3; if (t.tag == MAKE_TAG('h', 'e', 'a', 'd')) head_offset = table_offset; f << t.tag << checksum(t.data) << table_offset << t.data.size(); table_offset += size;#define TAG(x) char(t.tag >> 24) << char((t.tag >> 16) & 0xff) << char((t.tag >> 8) & 0xff) << char(t.tag & 0xff) //qDebug() << "table " << TAG(t.tag) << "has size " << t.data.size() << "stream at " << f.offset(); } } for (int i = 0; i < tables.size(); ++i) { const QByteArray &t = tables.at(i).data; font += t; int s = t.size(); while (s & 3) { font += '\0'; ++s; } } if (!head_offset) { qWarning("QFontSubset: Font misses 'head' table"); return QByteArray(); } // calculate the fonts checksum and qToBigEndian into 'head's checksum_adjust quint32 checksum_adjust = 0xB1B0AFBA - checksum(font); qToBigEndian(checksum_adjust, (uchar *)font.data() + head_offset + 8); return font;}/* PDF requires the following tables: head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm This means we don't have to add a os/2, post or name table. cvt , prep and fpgm could be empty if really required.*/QByteArray QFontSubset::toTruetype() const{ qttf_font_tables font; memset(&font, 0, sizeof(qttf_font_tables)); qreal ppem = fontEngine->fontDef.pixelSize;#define TO_TTF(x) qRound(x * 2048. / ppem) QList<QTtfGlyph> glyphs; QFontEngine::Properties properties = fontEngine->properties(); // initialize some stuff needed in createWidthArray emSquare = 2048; widths.resize(nGlyphs());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -