Subversion Repositories Scribus

Rev

Rev 16365 | Rev 16506 | Go to most recent revision | 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>
16365 mrdocs 11
#include <QDebug>
5979 avox 12
 
13
#include <sys/types.h>
14
 
15
#include "fonts/scface_ttf.h"
16
#include "fonts/scfontmetrics.h"
17
#include "util.h"
18
#include "scconfig.h"
19
 
16365 mrdocs 20
KernFeature::KernFeature ( FT_Face face )
21
                :m_valid ( true )
22
{
23
        FontName = QString ( face->family_name ) + " " + QString ( face->style_name )   ;
24
//      qDebug() <<"KF"<<FontName;
25
//      QTime t;
26
//      t.start();
27
        FT_ULong length = 0;
28
        if ( !FT_Load_Sfnt_Table ( face, TTAG_GPOS , 0, NULL, &length ) )
29
        {
30
//              qDebug() <<"\t"<<"GPOS table len"<<length;
31
                if ( length > 32 )
32
                {
33
                        GPOSTableRaw.resize ( length );
34
                        FT_Load_Sfnt_Table ( face, TTAG_GPOS, 0, reinterpret_cast<FT_Byte*> ( GPOSTableRaw.data() ), &length );
5979 avox 35
 
16365 mrdocs 36
                        makeCoverage();
37
                }
38
                else
39
                        m_valid = false;
5979 avox 40
 
16365 mrdocs 41
                GPOSTableRaw.clear();
42
                coverages.clear();
43
        }
44
        else
45
                m_valid = false;
46
 
47
        if ( !m_valid )
48
                pairs.clear();
49
//      qDebug() <<"\t"<<m_valid;
50
//      qDebug() <<"\t"<<t.elapsed();
51
}
52
 
53
KernFeature::KernFeature ( const KernFeature & kf )
54
{
55
        m_valid = kf.m_valid;
56
        if ( m_valid )
57
                pairs = kf.pairs;
58
 
59
}
60
 
61
 
62
KernFeature::~ KernFeature()
63
{
64
}
65
 
66
double KernFeature::getPairValue ( unsigned int glyph1, unsigned int glyph2 ) const
67
{
68
        if ( m_valid )
69
        {
70
                if ( pairs.contains ( glyph1 ) )
71
                {
72
                        if ( pairs[glyph1].contains ( glyph2 ) )
73
                        {
74
                                return pairs[glyph1][glyph2];
75
                        }
76
                }
77
        }
78
        return 0.0;
79
}
80
 
81
void KernFeature::makeCoverage()
82
{
83
        if ( GPOSTableRaw.isEmpty() )
84
                return;
85
 
86
        quint16 FeatureList_Offset= toUint16 ( 6 );
87
        quint16 LookupList_Offset = toUint16 ( 8 );
88
 
89
        // Find the offsets of the kern feature tables
90
        quint16 FeatureCount = toUint16 ( FeatureList_Offset );;
91
        QList<quint16> FeatureKern_Offset;
92
        for ( quint16 FeatureRecord ( 0 ); FeatureRecord < FeatureCount; ++ FeatureRecord )
93
        {
94
                int rawIdx ( FeatureList_Offset + 2 + ( 6 * FeatureRecord ) );
95
                quint32 tag ( FT_MAKE_TAG ( GPOSTableRaw.at ( rawIdx ),
96
                                            GPOSTableRaw.at ( rawIdx + 1 ),
97
                                            GPOSTableRaw.at ( rawIdx + 2 ),
98
                                            GPOSTableRaw.at ( rawIdx + 3 ) ) );
99
                if ( tag == TTAG_kern )
100
                {
101
                        FeatureKern_Offset << ( toUint16 ( rawIdx + 4 ) + FeatureList_Offset );
102
 
103
                }
104
        }
105
 
106
        // Extract indices of lookups for feture kern
107
        QList<quint16> LookupListIndex;
108
        foreach ( quint16 kern, FeatureKern_Offset )
109
        {
110
                quint16 LookupCount ( toUint16 ( kern + 2 ) );
111
                for ( int llio ( 0 ) ; llio < LookupCount; ++llio )
112
                {
113
                        quint16 Idx ( toUint16 ( kern + 4 + ( llio * 2 ) ) );
114
                        if ( !LookupListIndex.contains ( Idx ) )
115
                        {
116
                                LookupListIndex <<Idx ;
117
                        }
118
                }
119
        }
120
 
121
 
122
        // Extract offsets of lookup tables for feature kern
123
        QList<quint16> LookupTables;
124
        QList<quint16> PairAdjustmentSubTables;
125
        for ( int i ( 0 ); i < LookupListIndex.count(); ++i )
126
        {
127
                int rawIdx ( LookupList_Offset + 2 + ( LookupListIndex[i] * 2 ) );
128
                quint16 Lookup ( toUint16 ( rawIdx )  + LookupList_Offset );
129
                quint16 SubTableCount ( toUint16 ( Lookup + 4 ) );
130
                for ( int stIdx ( 0 ); stIdx < SubTableCount; ++ stIdx )
131
                {
132
                        quint16 SubTable ( toUint16 ( Lookup + 6 + ( 2 * stIdx ) ) + Lookup );
133
 
134
//                      quint16 PosFormat ( toUint16 ( SubTable ) );
135
                        quint16 Coverage_Offset ( toUint16 ( SubTable + 2 ) + SubTable );
136
                        quint16 CoverageFormat ( toUint16 ( Coverage_Offset ) );
137
 
138
                        if ( 1 == CoverageFormat ) // glyph indices based
139
                        {
140
                                quint16 GlyphCount ( toUint16 ( Coverage_Offset + 2 ) );
141
                                quint16 GlyphID ( Coverage_Offset + 4 );
16455 jghali 142
                                if (GlyphCount == 0) continue;
16365 mrdocs 143
 
144
                                for ( unsigned int gl ( 0 ); gl < GlyphCount; ++gl )
145
                                {
146
                                        coverages[SubTable] << toUint16 ( GlyphID + ( gl * 2 ) );
147
                                }
148
                        }
149
                        else if ( 2 == CoverageFormat ) // Coverage Format2 => ranges based
150
                        {
151
                                quint16 RangeCount ( toUint16 ( Coverage_Offset + 2 ) );
16455 jghali 152
                                if (RangeCount == 0) continue;
16365 mrdocs 153
 
154
//                              int gl_base ( 0 );
155
                                for ( int r ( 0 ); r < RangeCount; ++r )
156
                                {
157
                                        quint16 rBase ( Coverage_Offset + 4 + ( r * 6 ) );
158
                                        quint16 Start ( toUint16 ( rBase ) );
159
                                        quint16 End ( toUint16 ( rBase + 2 ) );
160
//                                      quint16 StartCoverageIndex ( toUint16 ( rBase + 4 ) );
16455 jghali 161
                                        // #9842 : for some font such as Gabriola Regular
162
                                        // the range maybe be specified in reverse order
163
                                        if (Start <= End)
164
                                        {
165
                                                for ( unsigned int gl ( Start ); gl <= End; ++gl )
166
                                                        coverages[SubTable]  << gl;
167
                                        }
168
                                        else
169
                                        {
170
                                                for ( unsigned int gl ( Start ); gl >= End; --gl )
171
                                                        coverages[SubTable]  << gl;
172
                                        }
16365 mrdocs 173
                                }
174
                        }
175
                        else
176
                        {
177
//                              qDebug() <<"Unknow Coverage Format:"<<CoverageFormat;
178
                                continue;
179
                        }
180
 
181
                        makePairs ( SubTable );
182
                }
183
 
184
        }
185
 
186
 
187
}
188
 
189
 
190
void KernFeature::makePairs ( quint16 subtableOffset )
191
{
192
        /*
193
        Lookup Type 2:
194
        Pair Adjustment Positioning Subtable
195
        */
196
 
197
        quint16 PosFormat ( toUint16 ( subtableOffset ) );
198
 
199
        if ( PosFormat == 1 )
200
        {
201
                quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
202
                quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
203
                quint16 PairSetCount ( toUint16 ( subtableOffset +8 ) );
204
                if ( ValueFormat1 && ValueFormat2 )
205
                {
206
                        for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
207
                        {
208
                                unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
209
                                quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
210
                                quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
211
                                quint16 PairValueRecord ( PairSetOffset + 2 );
212
                                for ( int pvIdx ( 0 );pvIdx < PairValueCount; ++pvIdx )
213
                                {
214
                                        quint16 recordBase ( PairValueRecord + ( ( 2 + 2 + 2 ) * pvIdx ) );
215
                                        quint16 SecondGlyph ( toUint16 ( recordBase ) );
216
                                        qint16 Value1 ( toInt16 ( recordBase + 2 ) );
217
                                        pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
218
 
219
                                }
220
 
221
                        }
222
                }
223
                else if ( ValueFormat1 && ( !ValueFormat2 ) )
224
                {
225
                        for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
226
                        {
227
                                unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
228
                                quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
229
                                quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
230
                                quint16 PairValueRecord ( PairSetOffset + 2 );
231
                                for ( int pvIdx ( 0 );pvIdx < PairValueCount; ++pvIdx )
232
                                {
233
                                        quint16 recordBase ( PairValueRecord + ( ( 2 + 2 ) * pvIdx ) );
234
                                        quint16 SecondGlyph ( toUint16 ( recordBase ) );
235
                                        qint16 Value1 ( toInt16 ( recordBase + 2 ) );
236
                                        pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
237
 
238
                                }
239
 
240
                        }
241
                }
242
                else
243
                {
244
//                      qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
245
                }
246
 
247
        }
248
        else if ( PosFormat == 2 )
249
        {
250
                quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
251
                quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
252
                quint16 ClassDef1 ( toUint16 ( subtableOffset +8 )  + subtableOffset );
253
                quint16 ClassDef2 ( toUint16 ( subtableOffset +10 ) + subtableOffset );
254
                quint16 Class1Count ( toUint16 ( subtableOffset +12 ) );
255
                quint16 Class2Count ( toUint16 ( subtableOffset +14 ) );
256
                quint16 Class1Record ( subtableOffset +16 );
257
 
258
                // first extract classses
259
                ClassDefTable Class1Data ( getClass ( ClassDef1 , subtableOffset ) );
260
                ClassDefTable Class2Data ( getClass ( ClassDef2 , subtableOffset ) );
261
 
262
                if ( ValueFormat1 && ValueFormat2 )
263
                {
264
                        for ( quint16 C1 ( 0 );C1 < Class1Count; ++C1 )
265
                        {
266
                                QList<quint16> Class1 ( Class1Data[C1] );
267
                                quint16 Class2Record ( Class1Record + ( C1 * ( 2 * 2 * Class2Count ) ) );
268
                                for ( quint16 C2 ( 0 );C2 < Class2Count; ++C2 )
269
                                {
270
                                        qint16 Value1 ( toInt16 ( Class2Record + ( C2 * ( 2 * 2 ) ) ) );
271
                                        QList<quint16> Class2 ( Class2Data[C2] );
272
                                        // keep it barbarian :D
273
                                        foreach ( quint16 FirstGlyph, Class1 )
274
                                        {
275
                                                foreach ( quint16 SecondGlyph, Class2 )
276
                                                {
277
                                                        if ( Value1 )
278
                                                                pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
279
                                                }
280
                                        }
281
                                }
282
                        }
283
                }
284
                else if ( ValueFormat1 && ( !ValueFormat2 ) )
285
                {
286
                        for ( quint16 C1 ( 0 );C1 < Class1Count; ++C1 )
287
                        {
288
                                QString cdbg ( QString::number ( C1 ).rightJustified ( 5,QChar ( 32 ) ) );
289
                                QList<quint16> Class1 ( Class1Data[C1] );
290
                                quint16 Class2Record ( Class1Record + ( C1 * ( 2 * Class2Count ) ) );
291
                                for ( quint16 C2 ( 0 );C2 < Class2Count; ++C2 )
292
                                {
293
                                        qint16 Value1 ( toInt16 ( Class2Record + ( C2 * 2 ) ) );
294
                                        QList<quint16> Class2 ( Class2Data[C2] );
295
 
296
                                        foreach ( quint16 FirstGlyph, Class1 )
297
                                        {
298
                                                foreach ( quint16 SecondGlyph, Class2 )
299
                                                {
300
                                                        if ( Value1 )
301
                                                                pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
302
                                                }
303
                                        }
304
                                }
305
                        }
306
                }
307
                else
308
                {
309
//                      qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
310
                }
311
 
312
        }
313
        else
314
                qDebug() <<"unknown PosFormat"<<PosFormat;
315
}
316
 
317
KernFeature::ClassDefTable KernFeature::getClass ( quint16 classDefOffset, quint16 coverageId )
318
{
319
        ClassDefTable ret;
320
        ret[0] = coverages[coverageId];
321
        quint16 ClassFormat ( toUint16 ( classDefOffset ) );
322
        if ( ClassFormat == 1 )
323
        {
324
                quint16 StartGlyph ( toUint16 ( classDefOffset +2 ) );
325
                quint16 GlyphCount ( toUint16 ( classDefOffset +4 ) );
326
                quint16 ClassValueArray ( classDefOffset + 6 );
327
 
328
                for ( quint16 CV ( 0 );CV < GlyphCount; ++CV )
329
                {
330
                        ret[0].removeAll ( StartGlyph + CV );
331
                        ret[ toUint16 ( ClassValueArray + ( CV * 2 ) ) ] << StartGlyph + CV;
332
                }
333
        }
334
        else if ( ClassFormat == 2 )
335
        {
336
                quint16 ClassRangeCount ( toUint16 ( classDefOffset + 2 ) );
337
                quint16 ClassRangeRecord ( classDefOffset + 4 );
338
                for ( int CRR ( 0 ); CRR < ClassRangeCount; ++CRR )
339
                {
340
                        quint16 Start ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) ) );
341
                        quint16 End ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 2 ) );
342
                        quint16 Class ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 4 ) );
343
 
344
                        for ( quint16 gl ( Start ); gl <= End; ++gl )
345
                        {
346
                                ret[0].removeAll ( gl );
347
                                ret[Class] << gl;
348
                        }
349
                }
350
        }
351
        else
352
                qDebug() <<"Unknown Class Table type";
353
 
354
        return ret;
355
}
356
 
357
quint16 KernFeature::toUint16 ( quint16 index )
358
{
359
        if ( ( index + 2 ) > GPOSTableRaw.count() )
360
        {
361
//                qDebug() << "HORROR!" << index << GPOSTableRaw.count() << FontName ;
362
                // Rather no kerning at all than random kerning
363
//              m_valid = false;
364
                return 0;
365
        }
366
        // FIXME I just do not know how it has to be done *properly*
367
        quint16 c1 ( GPOSTableRaw.at ( index ) );
368
        quint16 c2 ( GPOSTableRaw.at ( index + 1 ) );
369
        c1 &= 0xFF;
370
        c2 &= 0xFF;
371
        quint16 ret ( ( c1 << 8 ) | c2 );
372
        return ret;
373
}
374
 
375
qint16 KernFeature::toInt16 ( quint16 index )
376
{
377
        if ( ( index + 2 ) > GPOSTableRaw.count() )
378
        {
379
                return 0;
380
        }
381
        // FIXME I just do not know how it has to be done *properly*
382
        quint16 c1 ( GPOSTableRaw.at ( index ) );
383
        quint16 c2 ( GPOSTableRaw.at ( index + 1 ) );
384
        c1 &= 0xFF;
385
        c2 &= 0xFF;
386
        qint16 ret ( ( c1 << 8 ) | c2 );
387
        return ret;
388
}
389
 
390
 
13345 pierre 391
namespace {
392
uint word(QByteArray const & bb, uint pos)
5979 avox 393
{
13345 pierre 394
        const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
395
        return pp[0] << 24 | pp[1] << 16 | pp[2] << 8 | pp[3];
5979 avox 396
}
13345 pierre 397
uint word16(QByteArray const & bb, uint pos)
5979 avox 398
{
13345 pierre 399
        const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
400
        return pp[0] << 8 | pp[1];
5979 avox 401
}
13345 pierre 402
QString tag(QByteArray const & bb, uint pos)
5979 avox 403
{
13345 pierre 404
        char buf[5] = "1234";
405
        buf[0] = bb.data()[pos];
406
        buf[1] = bb.data()[pos+1];
407
        buf[2] = bb.data()[pos+2];
408
        buf[3] = bb.data()[pos+3];
409
        return buf;
5979 avox 410
}
13345 pierre 411
bool copy(QByteArray & dst, uint to, QByteArray & src, uint from, uint len)
5979 avox 412
{
13345 pierre 413
        if (!dst.data())
414
                return false;
415
        if (!src.data())
416
                return false;
417
        if (to + len > static_cast<uint>(dst.size()))
418
                return false;
419
        if (from + len > static_cast<uint>(src.size()))
420
                return false;
421
 
422
        memcpy(dst.data() + to, src.data() + from, len);
423
        return true;
5979 avox 424
}
425
} //namespace
426
 
16365 mrdocs 427
ScFace_ttf::ScFace_ttf ( QString fam, QString sty, QString alt, QString scname, QString psname, QString path, int face )
428
                : FtFace ( fam, sty, alt, scname, psname, path, face )
429
{
430
        formatCode = ScFace::SFNT;
431
        kernFeature = 0;
432
}
5979 avox 433
 
16365 mrdocs 434
ScFace_ttf::~ ScFace_ttf()
435
{
436
        if ( kernFeature )
437
                delete kernFeature;
438
}
439
 
440
 
441
void ScFace_ttf::load() const
442
{
443
        if ( !kernFeature )
444
                kernFeature = new KernFeature ( ftFace() );
445
        FtFace::load();
446
}
447
 
448
void ScFace_ttf::unload() const
449
{
450
        if ( kernFeature )
451
                delete kernFeature;
452
        kernFeature = 0;
453
        FtFace::unload();
454
}
455
 
456
qreal ScFace_ttf::glyphKerning ( uint gl1, uint gl2, qreal sz ) const
457
{
458
        if ( kernFeature->isValid() )
459
        {
460
                return kernFeature->getPairValue ( gl1,gl2 ) / m_uniEM * sz;
461
 
462
        }
463
        else
464
                return FtFace::glyphKerning ( gl1, gl2, sz );
465
}
466
 
467
 
13345 pierre 468
void ScFace_ttf::RawData(QByteArray & bb) const {
469
        if (formatCode == ScFace::TTCF) {
5979 avox 470
                QByteArray coll;
13345 pierre 471
                FtFace::RawData(coll);
5979 avox 472
                // access table for faceIndex
13345 pierre 473
                if (faceIndex >= static_cast<int>(word(coll, 8)))
5979 avox 474
                {
13345 pierre 475
                        bb.resize(0);
5979 avox 476
                        return;
477
                }
478
                static const uint OFFSET_TABLE_LEN = 12;
479
                static const uint   TDIR_ENTRY_LEN = 16;
13345 pierre 480
                uint faceOffset = word(coll, 12 + 4 * faceIndex);
481
                uint nTables    = word16(coll, faceOffset + 4);
482
                sDebug(QObject::tr("extracting face %1 from font %2 (offset=%3, nTables=%4)").arg(faceIndex).arg(fontFile).arg(faceOffset).arg(nTables));
5979 avox 483
                uint headerLength = OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * nTables;
484
                uint tableLengths = 0;
485
                // sum table lengths incl padding
13345 pierre 486
                for (uint i=0; i < nTables; ++i)
5979 avox 487
                {
13345 pierre 488
                        tableLengths += word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 12);
489
                        tableLengths = (tableLengths+3) & ~3;
5979 avox 490
                }
13345 pierre 491
                bb.resize(headerLength + tableLengths);
492
                if (! bb.data())
5979 avox 493
                        return;
494
                // write header
13345 pierre 495
                sDebug(QObject::tr("memcpy header: %1 %2 %3").arg(0).arg(faceOffset).arg(headerLength));
496
                if (!copy(bb, 0, coll, faceOffset, headerLength))
5979 avox 497
                        return;
498
 
499
                uint pos = headerLength;
13345 pierre 500
                for (uint i=0; i < nTables; ++i)
5979 avox 501
                {
13345 pierre 502
                        uint tableSize  = word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 12);
503
                        uint tableStart = word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8);
504
                        sDebug(QObject::tr("table '%1'").arg(tag(coll, tableStart)));
505
                        sDebug(QObject::tr("memcpy table: %1 %2 %3").arg(pos).arg(tableStart).arg(tableSize));
506
                        if (!copy(bb, pos, coll, tableStart, tableSize)) break;
5979 avox 507
                        // write new offset to table entry
13345 pierre 508
                        sDebug(QObject::tr("memcpy offset: %1 %2 %3").arg(OFFSET_TABLE_LEN + TDIR_ENTRY_LEN*i + 8).arg(pos).arg(4));
509
                        memcpy(bb.data() + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8, &pos, 4);
5979 avox 510
                        pos += tableSize;
511
                        // pad
13345 pierre 512
                        while ((pos & 3) != 0)
513
                                bb.data()[pos++] = '\0';
5979 avox 514
                }
13345 pierre 515
        }      
516
        else if (formatCode == ScFace::TYPE42) {
517
                FtFace::RawData(bb);
5979 avox 518
        }
13345 pierre 519
        else {
520
                FtFace::RawData(bb);
5979 avox 521
        }
522
}
523
 
13345 pierre 524
bool ScFace_ttf::EmbedFont(QString &str) const
5979 avox 525
{
13345 pierre 526
        if (formatCode == ScFace::TYPE42) {
5979 avox 527
                //easy:
528
                QByteArray bb;
13345 pierre 529
                FtFace::RawData(bb);
5979 avox 530
                str += bb;
531
                return true;
532
        }
533
        QString tmp4;
534
        QString tmp2 = "";
535
        QString tmp3 = "";
536
        int counter = 0;
537
        char *buf[50];
538
        FT_ULong  charcode;
539
        FT_UInt   gindex;
540
        FT_Face face = ftFace();
13345 pierre 541
        if (!face) {
5979 avox 542
                return false;
543
        }
544
        const FT_Stream fts = face->stream;
13345 pierre 545
        if (ftIOFunc(fts, 0L, NULL, 0)) {
546
                return(false);
5979 avox 547
        }
548
        str+="%!PS-TrueTypeFont\n";
549
        str+="11 dict begin\n";
550
        str+="/FontName /" + psName + " def\n";
551
        str+="/Encoding /ISOLatin1Encoding where {pop ISOLatin1Encoding} {StandardEncoding} ifelse def\n";
552
        str+="/PaintType 0 def\n/FontMatrix [1 0 0 1 0 0] def\n";
553
        str+="/FontBBox ["+FontBBox+"] def\n";
554
        str+="/FontType 42 def\n";
555
        str+="/FontInfo 8 dict dup begin\n";
556
        str+="/FamilyName (" + psName + ") def\n";
557
        str+="end readonly def\n";
558
        unsigned char *tmp = new unsigned char[65535];
559
        int length;
560
        char linebuf[80];
561
        str += "/sfnts [";
562
        int poso=0;
13345 pierre 563
        do {
5979 avox 564
                int posi=0;
565
                length= fts->size - fts->pos;
13345 pierre 566
                if (length > 65534) {
5979 avox 567
                        length = 65534;
568
                }
13345 pierre 569
                if (!ftIOFunc(fts, 0L, tmp, length))
5979 avox 570
                {
571
                        str+="\n<\n";
13345 pierre 572
                        for (int j = 0; j < length; j++)
5979 avox 573
                        {
574
                                unsigned char u=tmp[posi];
13345 pierre 575
                                linebuf[poso]=((u >> 4) & 15) + '0';
576
                                if(u>0x9f) linebuf[poso]+='a'-':';
5979 avox 577
                                ++poso;
578
                                u&=15; linebuf[poso]=u + '0';
13345 pierre 579
                                if(u>0x9) linebuf[poso]+='a'-':';
5979 avox 580
                                ++posi;
581
                                ++poso;
13345 pierre 582
                                if (poso > 70)
5979 avox 583
                                {
584
                                        linebuf[poso++]='\n';
585
                                        linebuf[poso++]=0;
586
                                        str += linebuf;
587
                                        poso = 0;
588
                                }
589
                        }
590
                        linebuf[poso++]=0;
591
                        str += linebuf;
592
                        poso = 0;
593
                        str += "00\n>";
594
                }
13345 pierre 595
                else {
596
                        sDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(fontFile));
5979 avox 597
                        str += "\n] def\n";
13345 pierre 598
                        status = qMax(status,ScFace::BROKENGLYPHS);
5979 avox 599
                        return false;
600
                }
13345 pierre 601
        } while (length==65534);
602
 
5979 avox 603
        str += "\n] def\n";
9556 avox 604
        delete[] tmp;
5979 avox 605
        gindex = 0;
13345 pierre 606
        charcode = FT_Get_First_Char(face, &gindex );
607
        while (gindex != 0)
5979 avox 608
        {
13345 pierre 609
                FT_Get_Glyph_Name(face, gindex, buf, 50);
610
                tmp2 += "/"+QString(reinterpret_cast<char*>(buf))+" "+tmp3.setNum(gindex)+" def\n";
611
                 charcode = FT_Get_Next_Char(face, charcode, &gindex );
5979 avox 612
                counter++;
613
        }
13345 pierre 614
        tmp4.setNum(counter);
5979 avox 615
        str += "/CharStrings " + tmp4 + " dict dup begin\n"+tmp2;
616
        str += "end readonly def\n";
617
        str += "FontName currentdict end definefont pop\n";
13345 pierre 618
        return(true);
5979 avox 619
}
620