Rev 24834 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5979 | avox | 1 | /* |
2 | For general Scribus (>=1.3.2) copyright and licensing information please refer |
||
3 | to the COPYING file provided with the program. Following this notice may exist |
||
4 | a copyright and/or license notice that predates the release of Scribus 1.3.2 |
||
5 | for which a new license (GPL+exception) is in place. |
||
6 | */ |
||
7 | |||
10223 | cbradney | 8 | #include <QFile> |
9 | #include <QString> |
||
10 | #include <QObject> |
||
13531 | pierre | 11 | #include <QDebug> |
5979 | avox | 12 | |
24480 | jghali | 13 | #include <limits> |
5979 | avox | 14 | #include <sys/types.h> |
15 | |||
16 | #include "fonts/scface_ttf.h" |
||
17 | #include "fonts/scfontmetrics.h" |
||
19271 | craig | 18 | #include "util_debug.h" |
5979 | avox | 19 | #include "scconfig.h" |
20019 | avox | 20 | #include "sfnt.h" |
5979 | avox | 21 | |
20103 | avox | 22 | #include FT_TRUETYPE_IDS_H |
20019 | avox | 23 | |
5979 | avox | 24 | |
22599 | craig | 25 | ScFace_ttf::ScFace_ttf (const QString& fam, const QString& sty, const QString& alt, const QString& scname, const QString& psname, const QString& path, int face, const QStringList& features ) |
21563 | jghali | 26 | : FtFace (fam, sty, alt, scname, psname, path, face, features) |
13531 | pierre | 27 | { |
28 | formatCode = ScFace::SFNT; |
||
29 | } |
||
5979 | avox | 30 | |
23163 | craig | 31 | ScFace_ttf::~ScFace_ttf() = default; |
13531 | pierre | 32 | |
19360 | jghali | 33 | bool ScFace_ttf::isSymbolic() const |
34 | { |
||
35 | FT_Face face = ftFace(); |
||
36 | if (!face || !face->charmap) |
||
37 | return false; |
||
38 | return (m_face->charmap->encoding == FT_ENCODING_MS_SYMBOL); |
||
39 | } |
||
13531 | pierre | 40 | |
41 | void ScFace_ttf::load() const |
||
42 | { |
||
21063 | jghali | 43 | FtFace::load(); |
20019 | avox | 44 | sfnt::PostTable checkPost; |
45 | FT_Face face = ftFace(); |
||
46 | checkPost.readFrom(face); |
||
20079 | craig | 47 | // if (!checkPost.usable) |
48 | // qDebug() << "can't use post table from " << face->family_name << face->style_name << ":" << checkPost.errorMsg; |
||
49 | // else |
||
50 | // qDebug() << "posttable from" << face->family_name << face->style_name << "has names for" << checkPost.numberOfGlyphs() << "glyphs and" << maxGlyph << "glyphs in charmap"; |
||
23377 | craig | 51 | const_cast<bool&>(hasGlyphNames) = checkPost.usable() && checkPost.numberOfGlyphs() >= maxGlyph; |
13531 | pierre | 52 | } |
53 | |||
54 | void ScFace_ttf::unload() const |
||
55 | { |
||
56 | FtFace::unload(); |
||
57 | } |
||
58 | |||
19396 | jghali | 59 | bool ScFace_ttf::hasNames() const |
60 | { |
||
61 | FT_Face face = ftFace(); |
||
62 | if (!face) |
||
63 | return false; |
||
64 | |||
65 | // The glyph name table embedded in Truetype fonts is not reliable. |
||
66 | // For those fonts we consequently use Adobe Glyph names whenever possible. |
||
20001 | avox | 67 | const bool avoidFntNames = (formatCode != ScFace::TYPE42 && typeCode == ScFace::TTF) && hasMicrosoftUnicodeCmap(face); |
19396 | jghali | 68 | if (avoidFntNames) |
20103 | avox | 69 | return true; // We use Adobe Glyph List or 'uniXXXX' names in such case |
19396 | jghali | 70 | |
71 | return FtFace::hasNames(); |
||
72 | } |
||
73 | |||
24153 | jghali | 74 | bool ScFace_ttf::glyphNames(ScFace::FaceEncoding& glyphList) const |
19396 | jghali | 75 | { |
76 | FT_ULong charcode; |
||
77 | FT_UInt gindex = 0; |
||
78 | |||
79 | FT_Face face = ftFace(); |
||
80 | if (!face) |
||
81 | return false; |
||
82 | |||
83 | // The glyph name table embedded in Truetype fonts is not reliable. |
||
84 | // For those fonts we consequently use Adobe Glyph names whenever possible. |
||
20001 | avox | 85 | const bool avoidFntNames = (formatCode != ScFace::TYPE42 && typeCode == ScFace::TTF) && hasMicrosoftUnicodeCmap(face); |
19396 | jghali | 86 | if (!avoidFntNames) |
24153 | jghali | 87 | return FtFace::glyphNames(glyphList); |
19396 | jghali | 88 | |
89 | // qDebug() << "reading metrics for" << face->family_name << face->style_name; |
||
24480 | jghali | 90 | FT_UInt spaceGlyphIndex = std::numeric_limits<FT_UInt>::max(); |
24175 | jghali | 91 | |
19396 | jghali | 92 | charcode = FT_Get_First_Char(face, &gindex); |
93 | while (gindex != 0) |
||
94 | { |
||
24175 | jghali | 95 | // #16289 : Protect space character in case several characters are |
96 | // mapped to same glyph as space |
||
97 | if (charcode == ' ') |
||
98 | spaceGlyphIndex = gindex; |
||
99 | if ((gindex == spaceGlyphIndex) && (charcode != ' ')) |
||
100 | { |
||
101 | charcode = FT_Get_Next_Char(face, charcode, &gindex); |
||
102 | continue; |
||
103 | } |
||
104 | |||
22143 | jghali | 105 | ScFace::GlyphEncoding glEncoding; |
106 | glEncoding.charcode = charcode; |
||
107 | glEncoding.glyphName = adobeGlyphName(charcode); |
||
23483 | jghali | 108 | glEncoding.toUnicode = QString::asprintf("%04lX", charcode); |
24153 | jghali | 109 | glyphList.insert(gindex, glEncoding); |
110 | charcode = FT_Get_Next_Char(face, charcode, &gindex); |
||
19396 | jghali | 111 | } |
112 | |||
113 | return true; |
||
114 | } |
||
115 | |||
24128 | jghali | 116 | void ScFace_ttf::rawData(QByteArray & bb) const |
117 | { |
||
118 | if (formatCode == ScFace::TTCF) |
||
119 | { |
||
5979 | avox | 120 | QByteArray coll; |
22144 | jghali | 121 | FtFace::rawData(coll); |
5979 | avox | 122 | // access table for faceIndex |
20103 | avox | 123 | if (faceIndex >= static_cast<int>(sfnt::word(coll, 8))) |
5979 | avox | 124 | { |
16541 | jghali | 125 | bb.resize(0); |
5979 | avox | 126 | return; |
127 | } |
||
128 | static const uint OFFSET_TABLE_LEN = 12; |
||
129 | static const uint TDIR_ENTRY_LEN = 16; |
||
20103 | avox | 130 | uint faceOffset = sfnt::word(coll, 12 + 4 * faceIndex); |
131 | uint nTables = sfnt::word16(coll, faceOffset + 4); |
||
16541 | jghali | 132 | sDebug(QObject::tr("extracting face %1 from font %2 (offset=%3, nTables=%4)").arg(faceIndex).arg(fontFile).arg(faceOffset).arg(nTables)); |
5979 | avox | 133 | uint headerLength = OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * nTables; |
134 | uint tableLengths = 0; |
||
135 | // sum table lengths incl padding |
||
24128 | jghali | 136 | for (uint i = 0; i < nTables; ++i) |
5979 | avox | 137 | { |
20103 | avox | 138 | tableLengths += sfnt::word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 12); |
16541 | jghali | 139 | tableLengths = (tableLengths+3) & ~3; |
5979 | avox | 140 | } |
16541 | jghali | 141 | bb.resize(headerLength + tableLengths); |
24128 | jghali | 142 | if (!bb.data()) |
5979 | avox | 143 | return; |
144 | // write header |
||
20019 | avox | 145 | // sDebug(QObject::tr("memcpy header: %1 %2 %3").arg(0).arg(faceOffset).arg(headerLength)); |
20103 | avox | 146 | if (!sfnt::copy(bb, 0, coll, faceOffset, headerLength)) |
5979 | avox | 147 | return; |
148 | |||
149 | uint pos = headerLength; |
||
24128 | jghali | 150 | for (uint i = 0; i < nTables; ++i) |
5979 | avox | 151 | { |
20103 | avox | 152 | uint dirEntry = faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i; |
153 | uint tableSize = sfnt::word(coll, dirEntry + 12); |
||
154 | uint tableStart = sfnt::word(coll, dirEntry + 8); |
||
155 | // sDebug(QObject::tr("table '%1' %2. %3 ...").arg(QString(sfnt::tag(coll, dirEntry))) |
||
156 | // .arg(QString::number(sfnt::word16(coll,tableStart),16)) |
||
157 | // .arg(QString::number(sfnt::word16(coll,tableStart+2),16))); |
||
20019 | avox | 158 | // sDebug(QObject::tr("memcpy table: %1 %2 %3").arg(pos).arg(tableStart).arg(tableSize)); |
22634 | jghali | 159 | if (!sfnt::copy(bb, pos, coll, tableStart, tableSize)) |
160 | break; |
||
5979 | avox | 161 | // write new offset to table entry |
20019 | avox | 162 | // sDebug(QObject::tr("memcpy offset: %1 %2 %3").arg(OFFSET_TABLE_LEN + TDIR_ENTRY_LEN*i + 8).arg(pos).arg(4)); |
19998 | avox | 163 | // buggy: not endian aware: memcpy(bb.data() + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8, &pos, 4); |
20103 | avox | 164 | sfnt::putWord(bb, OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8, pos); |
5979 | avox | 165 | pos += tableSize; |
166 | // pad |
||
16541 | jghali | 167 | while ((pos & 3) != 0) |
168 | bb.data()[pos++] = '\0'; |
||
5979 | avox | 169 | } |
19104 | jghali | 170 | } |
24128 | jghali | 171 | else if (formatCode == ScFace::TYPE42) |
22144 | jghali | 172 | FtFace::rawData(bb); |
24128 | jghali | 173 | else |
22144 | jghali | 174 | FtFace::rawData(bb); |
5979 | avox | 175 | } |