📄 qfontsubset.cpp
字号:
<< quint16(0)// quint16 unitsPerEm Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines. << quint16(2048)// qint64 created Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer << head.created// qint64 modified Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer << head.modified// qint16 xMin For all glyph bounding boxes.// qint16 yMin For all glyph bounding boxes.// qint16 xMax For all glyph bounding boxes.// qint16 yMax For all glyph bounding boxes. << head.xMin << head.yMin << head.xMax << head.yMax// quint16 macStyle Bit 0: Bold (if set to 1);// Bit 1: Italic (if set to 1)// Bit 2: Underline (if set to 1)// Bit 3: Outline (if set to 1)// Bit 4: Shadow (if set to 1)// Bit 5: Condensed (if set to 1)// Bit 6: Extended (if set to 1)// Bits 7-15: Reserved (set to 0). << head.macStyle// quint16 lowestRecPPEM Smallest readable size in pixels. << quint16(6) // just a wild guess// qint16 fontDirectionHint 0: Fully mixed directional glyphs; << qint16(0)// 1: Only strongly left to right;// 2: Like 1 but also contains neutrals;// -1: Only strongly right to left;// -2: Like -1 but also contains neutrals. 1// qint16 indexToLocFormat 0 for short offsets, 1 for long. << head.indexToLocFormat// qint16 glyphDataFormat 0 for current format. << qint16(0); Q_ASSERT(s.offset() == head_size); return t;}static QTtfTable generateHhea(const qttf_hhea_table &hhea){ const int hhea_size = 36; QTtfTable t; t.tag = MAKE_TAG('h', 'h', 'e', 'a'); t.data.resize(hhea_size); QTtfStream s(t.data);// qint32 Table version number 0x00010000 for version 1.0. s << qint32(0x00010000)// qint16 Ascender Typographic ascent. (Distance from baseline of highest ascender) << hhea.ascender// qint16 Descender Typographic descent. (Distance from baseline of lowest descender) << hhea.descender// qint16 LineGap Typographic line gap.// Negative LineGap values are treated as zero// in Windows 3.1, System 6, and// System 7. << hhea.lineGap// quint16 advanceWidthMax Maximum advance width value in 'hmtx' table. << hhea.maxAdvanceWidth// qint16 minLeftSideBearing Minimum left sidebearing value in 'hmtx' table. << hhea.minLeftSideBearing// qint16 minRightSideBearing Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)). << hhea.minRightSideBearing// qint16 xMaxExtent Max(lsb + (xMax - xMin)). << hhea.xMaxExtent// qint16 caretSlopeRise Used to calculate the slope of the cursor (rise/run); 1 for vertical. << qint16(1)// qint16 caretSlopeRun 0 for vertical. << qint16(0)// qint16 caretOffset The amount by which a slanted highlight on a glyph needs to be shifted to produce the best appearance. Set to 0 for non-slanted fonts << qint16(0)// qint16 (reserved) set to 0 << qint16(0)// qint16 (reserved) set to 0 << qint16(0)// qint16 (reserved) set to 0 << qint16(0)// qint16 (reserved) set to 0 << qint16(0)// qint16 metricDataFormat 0 for current format. << qint16(0)// quint16 numberOfHMetrics Number of hMetric entries in 'hmtx' table << hhea.numberOfHMetrics; Q_ASSERT(s.offset() == hhea_size); return t;}static QTtfTable generateMaxp(const qttf_maxp_table &maxp){ const int maxp_size = 32; QTtfTable t; t.tag = MAKE_TAG('m', 'a', 'x', 'p'); t.data.resize(maxp_size); QTtfStream s(t.data);// qint32 Table version number 0x00010000 for version 1.0. s << qint32(0x00010000)// quint16 numGlyphs The number of glyphs in the font. << maxp.numGlyphs// quint16 maxPoints Maximum points in a non-composite glyph. << maxp.maxPoints// quint16 maxContours Maximum contours in a non-composite glyph. << maxp.maxContours// quint16 maxCompositePoints Maximum points in a composite glyph. << maxp.maxCompositePoints// quint16 maxCompositeContours Maximum contours in a composite glyph. << maxp.maxCompositeContours// quint16 maxZones 1 if instructions do not use the twilight zone (Z0), or 2 if instructions do use Z0; should be set to 2 in most cases. << quint16(1) // we do not embed instructions// quint16 maxTwilightPoints Maximum points used in Z0. << quint16(0)// quint16 maxStorage Number of Storage Area locations. << quint16(0)// quint16 maxFunctionDefs Number of FDEFs. << quint16(0)// quint16 maxInstructionDefs Number of IDEFs. << quint16(0)// quint16 maxStackElements Maximum stack depth2. << quint16(0)// quint16 maxSizeOfInstructions Maximum byte count for glyph instructions. << quint16(0)// quint16 maxComponentElements Maximum number of components referenced at "top level" for any composite glyph. << maxp.maxComponentElements// quint16 maxComponentDepth Maximum levels of recursion; 1 for simple components. << maxp.maxComponentDepth; Q_ASSERT(s.offset() == maxp_size); return t;}struct QTtfNameRecord { quint16 nameId; QString value;};static QTtfTable generateName(const QList<QTtfNameRecord> &name);static QTtfTable generateName(const qttf_name_table &name){ QList<QTtfNameRecord> list; QTtfNameRecord rec; rec.nameId = 0; rec.value = name.copyright; list.append(rec); rec.nameId = 1; rec.value = name.family; list.append(rec); rec.nameId = 2; rec.value = name.subfamily; list.append(rec); rec.nameId = 4; rec.value = name.family; if (name.subfamily != QLatin1String("Regular")) rec.value += QLatin1Char(' ') + name.subfamily; list.append(rec); rec.nameId = 6; rec.value = name.postscript_name; list.append(rec); return generateName(list);}// ####### should probably generate Macintosh/Roman name entries as wellstatic QTtfTable generateName(const QList<QTtfNameRecord> &name){ const int char_size = 2; QTtfTable t; t.tag = MAKE_TAG('n', 'a', 'm', 'e'); const int name_size = 6 + 12*name.size(); int string_size = 0; for (int i = 0; i < name.size(); ++i) { string_size += name.at(i).value.length()*char_size; } t.data.resize(name_size + string_size); QTtfStream s(t.data);// quint16 format Format selector (=0). s << quint16(0)// quint16 count Number of name records. << quint16(name.size())// quint16 stringOffset Offset to start of string storage (from start of table). << quint16(name_size);// NameRecord nameRecord[count] The name records where count is the number of records.// (Variable) int off = 0; for (int i = 0; i < name.size(); ++i) { int len = name.at(i).value.length()*char_size;// quint16 platformID Platform ID.// quint16 encodingID Platform-specific encoding ID.// quint16 languageID Language ID. s << quint16(3) << quint16(1) << quint16(0x0409) // en_US// quint16 nameId Name ID. << name.at(i).nameId// quint16 length String length (in bytes). << quint16(len)// quint16 offset String offset from start of storage area (in bytes). << quint16(off); off += len; } for (int i = 0; i < name.size(); ++i) { const QString &n = name.at(i).value; const ushort *uc = n.utf16(); for (int i = 0; i < n.length(); ++i) { s << quint16(*uc); ++uc; } } return t;}enum Flags { OffCurve = 0, OnCurve = (1 << 0), XShortVector = (1 << 1), YShortVector = (1 << 2), Repeat = (1 << 3), XSame = (1 << 4), XShortPositive = (1 << 4), YSame = (1 << 5), YShortPositive = (1 << 5)};struct TTF_POINT { qint16 x; qint16 y; quint8 flags;};Q_DECLARE_TYPEINFO(TTF_POINT, Q_PRIMITIVE_TYPE);static void convertPath(const QPainterPath &path, QList<TTF_POINT> *points, QList<int> *endPoints, qreal ppem){ int numElements = path.elementCount(); for (int i = 0; i < numElements - 1; ++i) { const QPainterPath::Element &e = path.elementAt(i); TTF_POINT p; p.x = qRound(e.x * 2048. / ppem); p.y = qRound(-e.y * 2048. / ppem); switch(e.type) { case QPainterPath::MoveToElement: if (i != 0) { // see if start and end points of the last contour agree 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); } // fall through case QPainterPath::LineToElement: p.flags = OnCurve; break; case QPainterPath::CurveToElement: { // cubic bezier curve, we need to reduce to a list of quadratic curves TTF_POINT list[3*16 + 4]; // we need max 16 subdivisions list[3] = points->at(points->size() - 1); list[2] = p; const QPainterPath::Element &e2 = path.elementAt(++i); list[1].x = qRound(e2.x * 2048. / ppem); list[1].y = qRound(-e2.y * 2048. / ppem); const QPainterPath::Element &e3 = path.elementAt(++i); list[0].x = qRound(e3.x * 2048. / ppem); list[0].y = qRound(-e3.y * 2048. / ppem); TTF_POINT *base = list; bool try_reduce = points->size() > 1 && points->at(points->size() - 1).flags == OnCurve && points->at(points->size() - 2).flags == OffCurve;// qDebug("generating beziers:"); while (base >= list) { const int split_limit = 3;// {// qDebug("iteration:");// TTF_POINT *x = list;// while (x <= base + 3) {// qDebug() << " " << QPoint(x->x, x->y);// ++x;// }// } Q_ASSERT(base - list < 3*16 + 1); // first see if we can easily reduce the cubic to a quadratic bezier curve int i1_x = base[1].x + ((base[1].x - base[0].x) >> 1); int i1_y = base[1].y + ((base[1].y - base[0].y) >> 1); int i2_x = base[2].x + ((base[2].x - base[3].x) >> 1); int i2_y = base[2].y + ((base[2].y - base[3].y) >> 1);// qDebug() << "checking: i1=" << QPoint(i1_x, i1_y) << " i2=" << QPoint(i2_x, i2_y); if (qAbs(i1_x - i2_x) <= split_limit && qAbs(i1_y - i2_y) <= split_limit) { // got a quadratic bezier curve TTF_POINT np; np.x = (i1_x + i2_x) >> 1; np.y = (i1_y + i2_y) >> 1; if (try_reduce) { // see if we can optimise out the last onCurve point int mx = (points->at(points->size() - 2).x + base[2].x) >> 1; int my = (points->at(points->size() - 2).y + base[2].y) >> 1; if (qAbs(mx - base[3].x) <= split_limit && qAbs(my = base[3].y) <= split_limit) points->takeLast(); try_reduce = false; } np.flags = OffCurve; points->append(np);// qDebug() << " appending offcurve point " << QPoint(np.x, np.y); base -= 3; } else { // need to split// qDebug() << " -> splitting"; qint16 a, b, c, d; base[6].x = base[3].x; c = base[1].x; d = base[2].x; base[1].x = a = ( base[0].x + c ) >> 1; base[5].x = b = ( base[3].x + d ) >> 1; c = ( c + d ) >> 1; base[2].x = a = ( a + c ) >> 1; base[4].x = b = ( b + c ) >> 1; base[3].x = ( a + b ) >> 1; base[6].y = base[3].y; c = base[1].y; d = base[2].y; base[1].y = a = ( base[0].y + c ) >> 1; base[5].y = b = ( base[3].y + d ) >> 1; c = ( c + d ) >> 1; base[2].y = a = ( a + c ) >> 1; base[4].y = b = ( b + c ) >> 1; base[3].y = ( a + b ) >> 1; base += 3; } } p = list[0]; p.flags = OnCurve; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -