Subversion Repositories Scribus

Rev

Rev 24175 | 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
}
176
 
22144 jghali 177
bool ScFace_ttf::embedFont(QByteArray &str) const
5979 avox 178
{
23653 craig 179
        QByteArray bb;
180
        FtFace::rawData(bb);
22599 craig 181
        if (formatCode == ScFace::TYPE42)
182
        {
5979 avox 183
                //easy:
20103 avox 184
                str = bb;
5979 avox 185
                return true;
186
        }
23653 craig 187
 
5979 avox 188
        int counter = 0;
189
        char *buf[50];
23653 craig 190
        FT_ULong charcode;
191
        FT_UInt gindex;
5979 avox 192
        FT_Face face = ftFace();
22599 craig 193
        if (!face)
5979 avox 194
                return false;
195
        const FT_Stream fts = face->stream;
22599 craig 196
        if (ftIOFunc(fts, 0L, nullptr, 0))
16541 jghali 197
                return(false);
22599 craig 198
 
24128 jghali 199
        str += "%!PS-TrueTypeFont\n";
200
        str += "11 dict begin\n";
201
        str += "/FontName /" + psName + " def\n";
202
        str += "/Encoding /ISOLatin1Encoding where {pop ISOLatin1Encoding} {StandardEncoding} ifelse def\n";
203
        str += "/PaintType 0 def\n/FontMatrix [1 0 0 1 0 0] def\n";
204
        str += "/FontBBox ["+m_pdfFontBBox+"] def\n";
205
        str += "/FontType 42 def\n";
206
        str += "/FontInfo 8 dict dup begin\n";
207
        str += "/FamilyName (" + psName + ") def\n";
208
        str += "end readonly def\n";
5979 avox 209
        unsigned char *tmp = new unsigned char[65535];
210
        int length;
211
        char linebuf[80];
212
        str += "/sfnts [";
24128 jghali 213
        int poso = 0;
214
        do
215
        {
216
                int posi = 0;
217
                length = fts->size - fts->pos;
218
                if (length > 65534)
5979 avox 219
                        length = 65534;
16541 jghali 220
                if (!ftIOFunc(fts, 0L, tmp, length))
5979 avox 221
                {
24128 jghali 222
                        str += "\n<\n";
16541 jghali 223
                        for (int j = 0; j < length; j++)
5979 avox 224
                        {
24128 jghali 225
                                unsigned char u = tmp[posi];
226
                                linebuf[poso] = ((u >> 4) & 15) + '0';
227
                                if (u > 0x9f)
228
                                        linebuf[poso] += 'a'-':';
5979 avox 229
                                ++poso;
24128 jghali 230
                                u &= 15;
231
                                linebuf[poso] = u + '0';
232
                                if (u > 0x9)
233
                                        linebuf[poso] += 'a'-':';
5979 avox 234
                                ++posi;
235
                                ++poso;
16541 jghali 236
                                if (poso > 70)
5979 avox 237
                                {
24128 jghali 238
                                        linebuf[poso++] = '\n';
239
                                        linebuf[poso++] = 0;
5979 avox 240
                                        str += linebuf;
241
                                        poso = 0;
242
                                }
243
                        }
24128 jghali 244
                        linebuf[poso++] = 0;
5979 avox 245
                        str += linebuf;
246
                        poso = 0;
247
                        str += "00\n>";
248
                }
22599 craig 249
                else
250
                {
16541 jghali 251
                        sDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(fontFile));
5979 avox 252
                        str += "\n] def\n";
16541 jghali 253
                        status = qMax(status,ScFace::BROKENGLYPHS);
5979 avox 254
                        return false;
255
                }
24128 jghali 256
        }
257
        while (length == 65534);
16541 jghali 258
 
5979 avox 259
        str += "\n] def\n";
9556 avox 260
        delete[] tmp;
5979 avox 261
        gindex = 0;
16541 jghali 262
        charcode = FT_Get_First_Char(face, &gindex );
23653 craig 263
        QString tmp2, tmp3, tmp4;
16541 jghali 264
        while (gindex != 0)
5979 avox 265
        {
16541 jghali 266
                FT_Get_Glyph_Name(face, gindex, buf, 50);
23653 craig 267
                tmp2 += "/"+QString(reinterpret_cast<char*>(buf)) + " " + tmp3.setNum(gindex) + " def\n";
268
                charcode = FT_Get_Next_Char(face, charcode, &gindex );
5979 avox 269
                counter++;
270
        }
16541 jghali 271
        tmp4.setNum(counter);
24128 jghali 272
        str += "/CharStrings " + tmp4 + " dict dup begin\n" + tmp2;
5979 avox 273
        str += "end readonly def\n";
274
        str += "FontName currentdict end definefont pop\n";
16541 jghali 275
        return(true);
5979 avox 276
}
277