Subversion Repositories Scribus

Rev

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