3
Copyright (c) 2006-2007, BBR Inc. All rights reserved.
5
Permission is hereby granted, free of charge, to any person obtaining
6
a copy of this software and associated documentation files (the
7
"Software"), to deal in the Software without restriction, including
8
without limitation the rights to use, copy, modify, merge, publish,
9
distribute, sublicense, and/or sell copies of the Software, and to
10
permit persons to whom the Software is furnished to do so, subject to
11
the following conditions:
13
The above copyright notice and this permission notice shall be included
14
in all copies or substantial portions of the Software.
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
#include <sys/types.h>
38
#include "PDFFTrueTypeFont.h"
41
#define TAG(a1,a2,a3,a4) (((a1) & 0xff) << 24 | \
42
((a2) & 0xff) << 16 | ((a3) & 0xff) << 8| ((a4) & 0xff))
44
#define TAG_TTC TAG('t','t','c','f') /* ttcf */
45
#define TAG_NAME TAG('n','a','m','e') /* name */
46
#define TAG_CMAP TAG('c','m','a','p') /* cmap */
47
#define TAG_GSUB TAG('G','S','U','B') /* GSUB */
48
#define TAG_KANA TAG('k','a','n','a') /* kana */
49
#define TAG_VERT TAG('v','e','r','t') /* vert */
50
#define TAG_VRT2 TAG('v','r','t','2') /* vrt2 */
51
#define TAG_GLYF TAG('g','l','y','f') /* glyf */
52
#define TAG_LOCA TAG('l','o','c','a') /* loca */
53
#define TAG_HEAD TAG('h','e','a','d') /* head */
54
#define TAG_HHEA TAG('h','h','e','a') /* hhea */
55
#define TAG_HMTX TAG('h','m','t','x') /* hmtx */
56
#define TAG_MAXP TAG('m','a','x','p') /* maxp */
57
#define TAG_CVT TAG('c','v','t',' ') /* cvt */
58
#define TAG_PREP TAG('p','r','e','p') /* prep */
59
#define TAG_FPGM TAG('f','p','g','m') /* fpgm */
61
#define GIDMAP_TABLE_INC 1024
62
#define OFFSET_TABLE_LEN 12
69
/* generating font specifications */
70
/* table directory entry index */
81
/* number of tables */
84
/* (Maximum power of 2 <= numTables) x 16. */
85
#define SEARCH_RANGE (8*16)
86
/* Log2(maximum power of 2 <= numTables) */
87
#define ENTRY_SELECTOR 3
90
#define HEAD_TABLE_LEN (54 + 2) /* 2 for padding */
91
#define HHEA_TABLE_LEN 36
92
#define MAXP_TABLE_LEN 32
94
/* table directory entry size */
95
#define TABLE_DIR_ENTRY_LEN 16
97
/* length of longHorMetrics entry */
98
#define LONGHORMETRIC_LEN (sizeof(USHORT)+sizeof(SHORT))
100
/* composite glyph script flags */
101
#define CG_ARG_1_AND_2_ARE_WORDS (1 << 0)
102
#define CG_ARGS_ARE_XY_VALUES (1 << 1)
103
#define CG_ROUND_XY_TO_GRID (1 << 2)
104
#define CG_WE_HAVE_A_SCALE (1 << 3)
105
#define CG_RESERVED (1 << 4)
106
#define CG_MORE_COMPONENTS (1 << 5)
107
#define CG_WE_HAVE_AN_X_AND_Y_SCALE (1 << 6)
108
#define CG_WE_HAVE_A_TWO_BY_TWO (1 << 7)
109
#define CG_WE_HAVE_INSTRUCTIONS (1 << 8)
110
#define CG_USE_MY_METRICS (1 << 9)
111
#define CG_OVERLAP_COMPOUND (1 << 10)
112
#define CG_SCALED_COMPONENTS_OFFSET (1 << 11)
113
#define CG_UNSCALED_COMPONENT_OFFSET (1 << 12)
117
unsigned long PDFFTrueTypeFont::mapGID(unsigned long orgGID)
121
if (orgGID == 0) return 0;
123
GIDMapSize = GIDMAP_TABLE_INC;
124
GIDMap = new unsigned long [GIDMapSize];
125
GIDMap[0] = 0; /* always map 0 to 0 */
127
/* check if gid is already registered */
128
for (i = 1;i < maxGID;i++) {
129
if (GIDMap[i] == orgGID) return i;
132
/* then regsiter it */
133
if (++maxGID >= GIDMapSize) {
136
unsigned int newSize;
138
newSize = GIDMapSize + GIDMAP_TABLE_INC;
139
p = new unsigned long [newSize];
140
memcpy(p,GIDMap,GIDMapSize*sizeof(unsigned long));
143
GIDMapSize = newSize;
145
GIDMap[maxGID] = orgGID;
146
//fprintf(stderr,"DEBUG:map GID %d to %d\n",orgGID,maxGID);
150
void PDFFTrueTypeFont::allocNewLGHTable()
152
/* Long version loca */
153
loca = new ULONG [maxGID+2];
159
glyf = new unsigned char [glyfSize];
162
/* all long metric */
163
hmtx = new LongHorMetric [maxGID+1];
167
void PDFFTrueTypeFont::reallocNewLHTable()
169
if (locaSize < maxGID+2) {
170
unsigned long newSize;
173
newSize = locaSize+LOCA_INC;
174
np = new ULONG [newSize];
175
memcpy(np,loca,locaSize*sizeof(ULONG));
180
if (hmtxSize < maxGID+1) {
181
unsigned long newSize;
184
newSize = hmtxSize+HMTX_INC;
185
np = new LongHorMetric [newSize];
186
memcpy(np,hmtx,hmtxSize*sizeof(LongHorMetric));
193
int PDFFTrueTypeFont::readOrgTables()
195
if (getTableDirEntry(TAG_HEAD,&(orgTDir[TDIR_HEAD])) < 0) {
196
p2pError(-1,const_cast<char *>("head table not found in font file %s"),
200
setOffset(orgTDir[TDIR_HEAD].offset);
201
if (head.read(this) < 0) {
205
if (getTableDirEntry(TAG_HHEA,&(orgTDir[TDIR_HHEA])) < 0) {
206
p2pError(-1,const_cast<char *>("hhea table not found in font file %s"),
210
setOffset(orgTDir[TDIR_HHEA].offset);
211
if (hhea.read(this) < 0) {
215
if (getTableDirEntry(TAG_MAXP,&(orgTDir[TDIR_MAXP])) < 0) {
216
p2pError(-1,const_cast<char *>("maxp table not found in font file %s"),
220
setOffset(orgTDir[TDIR_MAXP].offset);
221
if (maxp.read(this) < 0) {
225
if (getTableDirEntry(TAG_LOCA,&(orgTDir[TDIR_LOCA])) < 0) {
226
p2pError(-1,const_cast<char *>("loca table not found in font file %s"),
231
if (getTableDirEntry(TAG_GLYF,&(orgTDir[TDIR_GLYF])) < 0) {
232
p2pError(-1,const_cast<char *>("glyf table not found in font file %s"),
237
if (getTableDirEntry(TAG_HMTX,&(orgTDir[TDIR_HMTX])) < 0) {
238
p2pError(-1,const_cast<char *>("hmtx table not found in font file %s"),
243
if (getTableDirEntry(TAG_CVT,&(orgTDir[TDIR_CVT])) < 0) {
245
orgTDir[TDIR_CVT].tag = 0; /* null */
248
if (getTableDirEntry(TAG_PREP,&(orgTDir[TDIR_PREP])) < 0) {
250
orgTDir[TDIR_PREP].tag = 0; /* null */
253
if (getTableDirEntry(TAG_FPGM,&(orgTDir[TDIR_FPGM])) < 0) {
255
orgTDir[TDIR_FPGM].tag = 0; /* null */
260
void PDFFTrueTypeFont::outputWholeFile(P2POutputStream *str)
264
unsigned char *p = top;
272
outputLength = fileLength;
275
/* creating loca ,glyf and hmtx */
276
void PDFFTrueTypeFont::createLGHTable()
281
/* allocate new tables */
284
locaEntrySize = head.indexToLocFormat == 0 ? 2 : 4;
286
/* read the last longHorMetrics for default width */
287
read(orgTDir[TDIR_HHEA].offset+(hhea.numberOfHMetrics-1)*(sizeof(USHORT)
288
+sizeof(SHORT)),&defWidth);
290
/* NOTE: maxGID may be changed in this loop. */
291
for (i = 0;i <= maxGID;i++) {
294
SHORT numberOfContours;
295
unsigned long longHorMetricsLen
296
= hhea.numberOfHMetrics*(sizeof(USHORT)+sizeof(SHORT));
299
setOffset(orgTDir[TDIR_LOCA].offset+GIDMap[i]*locaEntrySize);
300
read(&start,locaEntrySize);
301
read(&end,locaEntrySize);
303
/* convert start to offset from the top of file */
304
start += orgTDir[TDIR_GLYF].offset;
306
/* copy glyf entry */
307
if (cGlyfIndex+len >= glyfSize) {
310
unsigned long newSize
311
= (cGlyfIndex+len+GLYF_INC-1)/GLYF_INC;
314
p = new unsigned char [newSize];
315
memcpy(p,glyf,cGlyfIndex);
320
read(start,&numberOfContours);
321
if (numberOfContours < 0) {
322
/* composite glyph */
323
//fprintf(stderr,"DEBUG: GID=%d is composite glyph\n",GIDMap[i]);
325
/* closure for copy */
331
_CopyGlyf(unsigned char *dstA, unsigned char *srcA) {
335
void copy(unsigned long n) {
340
void copy(unsigned char *p, unsigned long n) {
345
} copyGlyf(glyf+cGlyfIndex,top+start);
347
int haveInstructions = 0;
349
/* skip xMin,yMin,xMax,yMax */
350
advance(sizeof(SHORT)*4);
353
copyGlyf.copy(sizeof(SHORT)*5);
356
unsigned long oldMax;
361
haveInstructions |= (flags & CG_WE_HAVE_INSTRUCTIONS) != 0;
363
copyGlyf.copy(sizeof(flags));
366
//fprintf(stderr,"DEBUG: composite ref GID=%d, maxGID=%d\n",glyphIndex,maxGID);
368
mappedGID = mapGID(glyphIndex);
369
mappedGID = toBE(mappedGID); /* convert Big endian */
371
copyGlyf.copy(reinterpret_cast<unsigned char *>(&mappedGID),
374
if (maxGID != oldMax) {
375
/* new GID has been added */
376
//fprintf(stderr,"DEBUG: composite GID added\n");
380
if (flags & CG_ARG_1_AND_2_ARE_WORDS) {
381
/* copy argument1, argument2 */
382
advance(sizeof(SHORT)*2);
383
copyGlyf.copy(sizeof(SHORT)*2);
386
advance(sizeof(USHORT));
387
copyGlyf.copy(sizeof(USHORT));
389
if (flags & CG_WE_HAVE_A_SCALE) {
391
advance(sizeof(F2Dot14));
392
copyGlyf.copy(sizeof(F2Dot14));
393
} else if (flags & CG_WE_HAVE_AN_X_AND_Y_SCALE) {
394
/* copy xscale, yscale */
395
advance(sizeof(F2Dot14)*2);
396
copyGlyf.copy(sizeof(F2Dot14)*2);
397
} else if (flags & CG_WE_HAVE_A_TWO_BY_TWO) {
398
/* copy xscale, scale01, scale10, yscale */
399
advance(sizeof(F2Dot14)*4);
400
copyGlyf.copy(sizeof(F2Dot14)*4);
402
} while (flags & CG_MORE_COMPONENTS);
403
if (haveInstructions) {
407
/* copy instructions */
408
advance(sizeof(USHORT)+numInstr);
409
copyGlyf.copy(sizeof(USHORT)+numInstr);
413
memcpy(glyf+cGlyfIndex,top+start,len);
415
loca[i] = cGlyfIndex;
419
if (GIDMap[i] < hhea.numberOfHMetrics) {
421
setOffset(orgTDir[TDIR_HMTX].offset+GIDMap[i]*(sizeof(USHORT)
423
read(&(hmtx[i].advanceWidth));
424
read(&(hmtx[i].lsb));
426
/* lsb only version */
427
read(orgTDir[TDIR_HMTX].offset+longHorMetricsLen
428
+(GIDMap[i]-hhea.numberOfHMetrics)*sizeof(SHORT),&(hmtx[i].lsb));
429
hmtx[i].advanceWidth = defWidth;
432
loca[i] = cGlyfIndex; /* last entry */
435
unsigned long PDFFTrueTypeFont::locaCheckSum()
437
unsigned long sum = 0;
440
for (i = 0;i < maxGID+2;i++) {
446
unsigned long PDFFTrueTypeFont::glyfCheckSum()
448
unsigned long sum = 0;
449
unsigned long n = (cGlyfIndex+3)/4;
451
ULONG *p = reinterpret_cast<ULONG *>(glyf);
453
for (i = 0;i < n;i++) {
459
unsigned long PDFFTrueTypeFont::hmtxCheckSum()
461
unsigned long sum = 0;
464
for (i = 0;i < maxGID+1;i++) {
465
sum += hmtx[i].checkSum();
470
void PDFFTrueTypeFont::setupNewTableDirectory()
472
unsigned long toffset = OFFSET_TABLE_LEN+TABLE_DIR_ENTRY_LEN*TDIR_LEN;
474
tDir[TDIR_HEAD].tag = TAG_HEAD;
475
tDir[TDIR_HEAD].checkSum = head.checkSum();
476
tDir[TDIR_HEAD].offset = toffset;
477
tDir[TDIR_HEAD].length = HEAD_TABLE_LEN;
478
toffset += tDir[TDIR_HEAD].length;
480
tDir[TDIR_HHEA].tag = TAG_HHEA;
481
tDir[TDIR_HHEA].checkSum = hhea.checkSum();
482
tDir[TDIR_HHEA].offset = toffset;
483
tDir[TDIR_HHEA].length = HHEA_TABLE_LEN;
484
toffset += tDir[TDIR_HHEA].length;
486
tDir[TDIR_LOCA].tag = TAG_LOCA;
487
tDir[TDIR_LOCA].checkSum = locaCheckSum();
488
tDir[TDIR_LOCA].offset = toffset;
489
tDir[TDIR_LOCA].length = (maxGID+2)*sizeof(ULONG);
490
toffset += tDir[TDIR_LOCA].length;
492
tDir[TDIR_MAXP].tag = TAG_MAXP;
493
tDir[TDIR_MAXP].checkSum = maxp.checkSum();
494
tDir[TDIR_MAXP].offset = toffset;
495
tDir[TDIR_MAXP].length = MAXP_TABLE_LEN;
496
toffset += tDir[TDIR_MAXP].length;
498
/* copy cvt table, so checkSum and length are same as original */
499
tDir[TDIR_CVT].tag = TAG_CVT;
500
tDir[TDIR_CVT].offset = toffset;
501
if (orgTDir[TDIR_CVT].tag == 0) {
502
/* no cvt table in original font, output empty */
503
tDir[TDIR_CVT].checkSum = TAG_CVT + toffset;
504
tDir[TDIR_CVT].length = 0;
506
tDir[TDIR_CVT].checkSum = orgTDir[TDIR_CVT].checkSum;
507
tDir[TDIR_CVT].length = orgTDir[TDIR_CVT].length;
509
toffset += tDir[TDIR_CVT].length;
511
/* copy prep table, so checkSum and length are same as original */
512
tDir[TDIR_PREP].tag = TAG_PREP;
513
tDir[TDIR_PREP].offset = toffset;
514
if (orgTDir[TDIR_PREP].tag == 0) {
515
/* no prep table in original font, output empty */
516
tDir[TDIR_PREP].checkSum = TAG_PREP + toffset;
517
tDir[TDIR_PREP].length = 0;
519
tDir[TDIR_PREP].length = orgTDir[TDIR_PREP].length;
520
tDir[TDIR_PREP].checkSum = orgTDir[TDIR_PREP].checkSum;
522
toffset += tDir[TDIR_PREP].length;
524
tDir[TDIR_GLYF].tag = TAG_GLYF;
525
tDir[TDIR_GLYF].checkSum = glyfCheckSum();
526
tDir[TDIR_GLYF].offset = toffset;
527
tDir[TDIR_GLYF].length = cGlyfIndex;
528
toffset += tDir[TDIR_GLYF].length;
530
tDir[TDIR_HMTX].tag = TAG_HMTX;
531
tDir[TDIR_HMTX].checkSum = hmtxCheckSum();
532
tDir[TDIR_HMTX].offset = toffset;
533
tDir[TDIR_HMTX].length = (maxGID+1)*LONGHORMETRIC_LEN;
534
toffset += tDir[TDIR_HMTX].length;
536
/* copy fpgm table, so checkSum and length are same as original */
537
tDir[TDIR_FPGM].tag = TAG_FPGM;
538
tDir[TDIR_FPGM].offset = toffset;
539
if (orgTDir[TDIR_FPGM].tag == 0) {
540
/* no fpgm table in original font, output empty */
541
tDir[TDIR_FPGM].checkSum = TAG_FPGM + toffset;
542
tDir[TDIR_FPGM].length = 0;
544
tDir[TDIR_FPGM].length = orgTDir[TDIR_FPGM].length;
545
tDir[TDIR_FPGM].checkSum = orgTDir[TDIR_FPGM].checkSum;
547
toffset += tDir[TDIR_FPGM].length;
550
void PDFFTrueTypeFont::outputOffsetTable(P2POutputStream *str)
552
write(str,static_cast<Fixed>(0x0010000)); /* version 1.0 */
553
write(str,static_cast<USHORT>(TDIR_LEN)); /* numTable */
554
write(str,static_cast<USHORT>(SEARCH_RANGE)); /* searchRange */
555
write(str,static_cast<USHORT>(ENTRY_SELECTOR)); /* entrySelector */
556
write(str,static_cast<USHORT>(TDIR_LEN*16-SEARCH_RANGE)); /* rangeShift */
559
unsigned long PDFFTrueTypeFont::offsetTableCheckSum()
561
unsigned long sum = 0;
563
sum += 0x0010000; /* version 1.0 */
564
sum += TDIR_LEN << 16; /* numTable */
565
sum += SEARCH_RANGE & 0xffff; /* searchRange */
566
sum += ENTRY_SELECTOR << 16; /* entrySelector */
567
sum += (TDIR_LEN*16-SEARCH_RANGE) & 0xffff; /* rangeShift */
571
unsigned long PDFFTrueTypeFont::allCheckSum()
573
unsigned long sum = 0;
576
sum += offsetTableCheckSum();
577
sum += tableDirectoryCheckSum();
578
for (i = 0;i < TDIR_LEN;i++) {
579
sum += tDir[i].checkSum;
584
unsigned long PDFFTrueTypeFont::tableDirectoryCheckSum()
587
unsigned long sum = 0;
589
for (i = 0;i < TDIR_LEN;i++) {
590
sum += tDir[i].calcCheckSum();
595
void PDFFTrueTypeFont::outputOrgData(P2POutputStream *str,
596
unsigned long offset, unsigned long len)
598
str->write(top+offset,len);
601
void PDFFTrueTypeFont::outputCvt(P2POutputStream *str)
603
/* copy original data */
604
outputOrgData(str,orgTDir[TDIR_CVT].offset,tDir[TDIR_CVT].length);
607
void PDFFTrueTypeFont::outputPrep(P2POutputStream *str)
609
/* copy original data */
610
outputOrgData(str,orgTDir[TDIR_PREP].offset,tDir[TDIR_PREP].length);
613
void PDFFTrueTypeFont::outputFpgm(P2POutputStream *str)
615
/* copy original data */
616
outputOrgData(str,orgTDir[TDIR_FPGM].offset,tDir[TDIR_FPGM].length);
619
void PDFFTrueTypeFont::outputLoca(P2POutputStream *str)
623
for (i = 0;i < maxGID+2;i++) {
628
void PDFFTrueTypeFont::outputGlyf(P2POutputStream *str)
630
str->write(glyf,cGlyfIndex);
633
void PDFFTrueTypeFont::outputHmtx(P2POutputStream *str)
637
for (i = 0;i < maxGID+1;i++) {
638
hmtx[i].output(this,str);
642
void PDFFTrueTypeFont::outputTableDirectory(P2POutputStream *str)
646
for (i = 0;i < TDIR_LEN;i++) {
647
tDir[i].output(this,str);
651
void PDFFTrueTypeFont::output(P2POutputStream *str)
654
/* output whole file */
655
outputWholeFile(str);
659
/* read or setup original tables */
660
if (readOrgTables() < 0) {
665
/* creating loca ,glyf and hmtx */
668
/* change rest table values */
669
head.checkSumAdjustment = 0;
670
hhea.numberOfHMetrics = maxGID+1; /* all metrics are long format */
671
maxp.numGlyphs = maxGID+1;
672
maxp.maxContours = maxGID+1;
673
maxp.maxCompositeContours = maxGID+1;
675
setupNewTableDirectory();
677
/* calc Adjustment */
678
head.checkSumAdjustment = 0xB1B0AFBA-allCheckSum();
681
outputOffsetTable(str);
682
outputTableDirectory(str);
693
/* setup table directory */
697
void PDFFTrueTypeFont::freeNewTables()
715
int PDFFTrueTypeFont::Head::read(PDFFTrueTypeFont *font)
717
font->read(&version);
718
if ((version & 0x10000) != 0x10000) {
719
p2pError(-1,const_cast<char *>("Not supported head table version in file %s"),
723
font->read(&fontRevision);
724
font->read(&checkSumAdjustment);
725
font->read(&magicNumber);
727
font->read(&unitsPerEm);
728
font->read(&created);
729
font->read(&modified);
734
font->read(&macStyle);
735
font->read(&lowestRecPPEM);
736
font->read(&fontDirectionHint);
737
font->read(&indexToLocFormat);
738
font->read(&glyphDataFormat);
742
void PDFFTrueTypeFont::Head::output(PDFFTrueTypeFont *font, P2POutputStream *str)
744
font->write(str,version);
745
font->write(str,fontRevision);
746
font->write(str,checkSumAdjustment);
747
font->write(str,magicNumber);
748
font->write(str,flags);
749
font->write(str,unitsPerEm);
750
font->write(str,created);
751
font->write(str,modified);
752
font->write(str,xMin);
753
font->write(str,yMin);
754
font->write(str,xMax);
755
font->write(str,yMax);
756
font->write(str,macStyle);
757
font->write(str,lowestRecPPEM);
758
font->write(str,fontDirectionHint);
759
font->write(str,indexToLocFormat);
760
font->write(str,glyphDataFormat);
761
font->write(str,static_cast<USHORT>(0)); /* padding */
764
unsigned long PDFFTrueTypeFont::Head::checkSum()
766
unsigned long sum = 0;
772
sum += unitsPerEm & 0xffff;
773
sum += (created >> 32) & 0xffffffff;
774
sum += created & 0xffffffff;
775
sum += (modified >> 32) & 0xffffffff;
776
sum += modified & 0xffffffff;
778
sum += yMin & 0xffff;
780
sum += yMax & 0xffff;
781
sum += macStyle << 16;
782
sum += lowestRecPPEM & 0xffff;
783
sum += fontDirectionHint << 16;
784
sum += indexToLocFormat & 0xffff;
785
sum += glyphDataFormat << 16;
790
int PDFFTrueTypeFont::Hhea::read(PDFFTrueTypeFont *font)
792
font->read(&version);
793
if ((version & 0x10000) != 0x10000) {
794
p2pError(-1,const_cast<char *>("Not supported hhea table version in file %s"),
798
font->read(&Ascender);
799
font->read(&Descender);
800
font->read(&LineGap);
801
font->read(&advanceWidthMax);
802
font->read(&minLeftSideBearing);
803
font->read(&minRightSideBearing);
804
font->read(&xMacExtent);
805
font->read(&caretSlopeRise);
806
font->read(&caretSlopeRun);
807
font->read(&caretOffset);
813
font->read(&metricDataFormat);
814
font->read(&numberOfHMetrics);
818
void PDFFTrueTypeFont::Hhea::output(PDFFTrueTypeFont *font, P2POutputStream *str)
820
font->write(str,version);
821
font->write(str,Ascender);
822
font->write(str,Descender);
823
font->write(str,LineGap);
824
font->write(str,advanceWidthMax);
825
font->write(str,minLeftSideBearing);
826
font->write(str,minRightSideBearing);
827
font->write(str,xMacExtent);
828
font->write(str,caretSlopeRise);
829
font->write(str,caretSlopeRun);
830
font->write(str,caretOffset);
831
/* output reserved */
832
font->write(str,static_cast<SHORT>(0));
833
font->write(str,static_cast<SHORT>(0));
834
font->write(str,static_cast<SHORT>(0));
835
font->write(str,static_cast<SHORT>(0));
836
font->write(str,metricDataFormat);
837
font->write(str,numberOfHMetrics);
840
unsigned long PDFFTrueTypeFont::Hhea::checkSum()
842
unsigned long sum = 0;
845
sum += Ascender << 16;
846
sum += Descender & 0xffff;
847
sum += LineGap << 16;
848
sum += advanceWidthMax & 0xffff;
849
sum += minLeftSideBearing << 16;
850
sum += minRightSideBearing & 0xffff;
851
sum += xMacExtent << 16;
852
sum += caretSlopeRise & 0xffff;
853
sum += caretSlopeRun << 16;
854
sum += caretOffset & 0xffff;
855
sum += metricDataFormat << 16;
856
sum += numberOfHMetrics & 0xffff;
860
int PDFFTrueTypeFont::Maxp::read(PDFFTrueTypeFont *font)
862
font->read(&version);
863
if ((version & 0x10000) != 0x10000) {
864
p2pError(-1,const_cast<char *>("Not supported maxp table version in file %s"),
868
font->read(&numGlyphs);
869
font->read(&maxPoints);
870
font->read(&maxContours);
871
font->read(&maxCompositePoints);
872
font->read(&maxCompositeContours);
873
font->read(&maxZones);
874
font->read(&maxTwilightPoints);
875
font->read(&maxStorage);
876
font->read(&maxFunctionDefs);
877
font->read(&maxInstructionDefs);
878
font->read(&maxStackElements);
879
font->read(&maxSizeOfInstructions);
880
font->read(&maxComponentElements);
881
font->read(&maxComponentDepth);
885
void PDFFTrueTypeFont::Maxp::output(PDFFTrueTypeFont *font, P2POutputStream *str)
887
font->write(str,version);
888
font->write(str,numGlyphs);
889
font->write(str,maxPoints);
890
font->write(str,maxContours);
891
font->write(str,maxCompositePoints);
892
font->write(str,maxCompositeContours);
893
font->write(str,maxZones);
894
font->write(str,maxTwilightPoints);
895
font->write(str,maxStorage);
896
font->write(str,maxFunctionDefs);
897
font->write(str,maxInstructionDefs);
898
font->write(str,maxStackElements);
899
font->write(str,maxSizeOfInstructions);
900
font->write(str,maxComponentElements);
901
font->write(str,maxComponentDepth);
904
unsigned long PDFFTrueTypeFont::Maxp::checkSum()
906
unsigned long sum = 0;
909
sum += numGlyphs << 16;
910
sum += maxPoints & 0xffff;
911
sum += maxContours << 16;
912
sum += maxCompositePoints & 0xffff;
913
sum += maxCompositeContours << 16;
914
sum += maxZones & 0xffff;
915
sum += maxTwilightPoints << 16;
916
sum += maxStorage & 0xffff;
917
sum += maxFunctionDefs << 16;
918
sum += maxInstructionDefs & 0xffff;
919
sum += maxStackElements << 16;
920
sum += maxSizeOfInstructions & 0xffff;
921
sum += maxComponentElements << 16;
922
sum += maxComponentDepth & 0xffff;
926
void PDFFTrueTypeFont::TableDirectory::output(PDFFTrueTypeFont *font,
927
P2POutputStream *str)
929
font->write(str,tag);
930
font->write(str,checkSum);
931
font->write(str,offset);
932
font->write(str,length);
935
unsigned long PDFFTrueTypeFont::TableDirectory::calcCheckSum()
937
unsigned long sum = 0;
947
int PDFFTrueTypeFont::setupCmap()
953
unsigned int format4Offset = 0;
955
if (cmap != 0) return 0; /* already setup */
956
if (getTable(TAG_CMAP,&cmapTable) < 0) {
957
p2pError(-1,const_cast<char *>("cmap table not found in font file %s"),
961
setOffset(cmapTable);
962
skip<USHORT>(); // skip version
965
/* find unicode table */
966
/* NOTICE: only support, Microsoft Unicode or platformID == 0 */
967
for (i = 0;i < numCMTables;i++) {
968
USHORT platformID, encodingID;
974
if ((platformID == 3 /* Microsoft */ && encodingID == 1 /* Unicode */)
975
|| platformID == 0) {
976
unsigned long old = getOffset(); /* save current offset */
978
setOffset(subtable+cmapTable);
981
/* found , but continue searching for format 12 */
982
format4Offset = getOffset();
984
setOffset(old); /* restore old offset */
985
} else if ((platformID == 3 /* Microsoft */ && encodingID == 10 /* UCS-4 */)
986
|| platformID == 0) {
987
unsigned long old = getOffset(); /* save current offset */
989
setOffset(subtable+cmapTable);
996
/* found , but continue searching for format 12 */
997
format4Offset = getOffset();
999
setOffset(old); /* restore old offset */
1002
if (i >= numCMTables && format4Offset == 0) {
1004
p2pError(-1,const_cast<char *>("cmap table: Microsoft, Unicode, format 4 or 12 subtable not found in font file %s"),fileName);
1008
cmap = new CmapFormat12();
1012
setOffset(format4Offset);
1013
cmap = new CmapFormat4();
1021
unsigned long PDFFTrueTypeFont::getGID(unsigned long unicode, int wmode, int whole)
1023
unsigned long PDFFTrueTypeFont::getGID(unsigned long unicode, int wmode)
1028
if (cmap == 0) return 0;
1030
//fprintf(stderr,"DEBUG:getGID %d\n",code);
1031
gid = cmap->getGID(this, unicode);
1033
if (wmode && gid != 0) {
1034
gid = mapToVertGID(unicode,gid);
1038
if (!whole) gid = mapGID(gid);
1043
unsigned long PDFFTrueTypeFont::CmapFormat4::getGID(PDFFTrueTypeFont *font,
1044
unsigned long unicode)
1048
int b = segCount - 1;
1051
if (unicode > endCode[b]) {
1052
/* segment not found */
1053
/* illegal format */
1058
if (endCode[m] < unicode) {
1065
if (unicode >= startCode[b]) {
1066
if (idRangeOffset[b] != 0) {
1067
ULONG off = idRangeOffsetTop + b*2
1069
+ (unicode - startCode[b])*2;
1070
font->read(off,&gid);
1071
if (gid != 0) gid += idDelta[b];
1073
gid = unicode + idDelta[b];
1079
void PDFFTrueTypeFont::CmapFormat4::read(PDFFTrueTypeFont *font)
1084
font->read(&length);
1085
font->read(&language);
1086
font->read(&segCountX2);
1087
segCount = segCountX2/2;
1088
font->read(&searchRange);
1089
font->read(&entrySelector);
1090
font->read(&rangeShift);
1091
endCode = new USHORT[segCount];
1092
for (i = 0;i < segCount;i++) {
1093
font->read(&(endCode[i]));
1095
font->skip<USHORT>(); // skip reservedPad
1096
startCode = new USHORT[segCount];
1097
for (i = 0;i < segCount;i++) {
1098
font->read(&(startCode[i]));
1100
idDelta = new SHORT[segCount];
1101
for (i = 0;i < segCount;i++) {
1102
font->read(&(idDelta[i]));
1104
idRangeOffsetTop = font->getOffset();
1105
idRangeOffset = new USHORT[segCount];
1106
for (i = 0;i < segCount;i++) {
1107
font->read(&(idRangeOffset[i]));
1111
unsigned long PDFFTrueTypeFont::CmapFormat12::getGID(PDFFTrueTypeFont *font,
1112
unsigned long unicode)
1114
unsigned long gid = 0;
1116
int b = nGroups - 1;
1119
if (unicode > endCharCode[b]) {
1120
/* segment not found */
1121
/* illegal format */
1126
if (endCharCode[m] < unicode) {
1133
if (unicode >= startCharCode[b]) {
1134
gid = startGlyphID[b] + unicode - startCharCode[b];
1139
void PDFFTrueTypeFont::CmapFormat12::read(PDFFTrueTypeFont *font)
1144
font->skip<USHORT>(); // skip reservedPad
1145
font->read(&length);
1146
font->read(&language);
1147
font->read(&nGroups);
1149
startCharCode = new ULONG[nGroups];
1150
endCharCode = new ULONG[nGroups];
1151
startGlyphID = new ULONG[nGroups];
1152
for (i = 0;i < nGroups;i++) {
1153
font->read(&(startCharCode[i]));
1154
font->read(&(endCharCode[i]));
1155
font->read(&(startGlyphID[i]));
1159
int PDFFTrueTypeFont::setOffsetTable(unsigned int faceIndexA)
1164
/* check if file is TTC */
1165
if ((ext = strrchr(fileName,'.')) != 0 && strncasecmp(ext,".ttc",4) == 0) {
1167
/* set offsetTable */
1173
if (TTCTag != TAG_TTC) {
1174
p2pError(-1,const_cast<char *>("Illegal TTCTag:0x%08lx of TTC file:%s"),
1178
skip<ULONG>(); /* skip version */
1180
if (numFonts <= faceIndexA) {
1181
p2pError(-1,const_cast<char *>("Too large faceIndex:%d of TTC file:%s : faces=%ld"),
1182
faceIndexA,fileName,numFonts);
1185
advance(sizeof(ULONG)*faceIndexA); /* skip to the element */
1191
PDFFTrueTypeFont::PDFFTrueTypeFont()
1206
tDir = new TableDirectory [TDIR_LEN];
1207
orgTDir = new TableDirectory [TDIR_LEN];
1222
UGooString *PDFFTrueTypeFont::getFontName()
1226
USHORT stringOffset;
1229
if (fontName != 0) return fontName;
1230
if (getTable(TAG_NAME,&nameTable) < 0) {
1231
p2pError(-1,const_cast<char *>("name table not found in font file %s"),
1235
setOffset(nameTable);
1236
skip<USHORT>(); /* skip format */
1238
read(&stringOffset);
1239
for (i = 0;i < count;i++) {
1247
//advance(sizeof(USHORT)*3); /* skip to nameID */
1255
/* PostScript name */
1256
if (platformID == 0 /* Unicode */ || platformID == 3 /* Microsoft */) {
1258
Unicode *p = new Unicode[length/2];
1261
setOffset(nameTable+stringOffset+so);
1262
for (j = 0;j < length/2;j++) {
1267
fontName = new UGooString(p,length/2);
1271
Unicode *p = new Unicode[length];
1272
unsigned char *q = top+nameTable+stringOffset+so;
1274
for (j = 0;j < length;j++) {
1277
fontName = new UGooString(p,length);
1285
int PDFFTrueTypeFont::init(const char *fileNameA, unsigned int faceIndexA)
1291
fileName = new char [strlen(fileNameA)+1];
1292
strcpy(fileName,fileNameA);
1293
if ((fontFileFD = open(fileName,O_RDONLY)) < 0) {
1294
p2pError(-1,const_cast<char *>("Can't open font file %s"),fileName);
1297
if (fstat(fontFileFD,&sbuf) < 0) {
1298
p2pError(-1,const_cast<char *>("Can't get stat of font file %s"),fileName);
1301
fileLength = sbuf.st_size;
1302
if ((top = reinterpret_cast<unsigned char *>(
1303
mmap(0,fileLength,PROT_READ,MAP_PRIVATE,fontFileFD,0))) == 0) {
1304
p2pError(-1,const_cast<char *>("mmap font file %s failed"),fileName);
1307
if (setOffsetTable(faceIndexA) < 0) goto error_end2;
1308
setOffset(offsetTable);
1310
if (sfntVersion != 0x00010000) {
1311
p2pError(-1,const_cast<char *>("Illegal sfnt version in font file %s"),
1319
munmap((char *)top,fileLength);
1326
PDFFTrueTypeFont::~PDFFTrueTypeFont()
1329
if (cmap != 0) delete cmap;
1330
if (GIDMap != 0) delete[] GIDMap;
1331
if (tDir != 0) delete[] tDir;
1332
if (orgTDir != 0) delete[] orgTDir;
1337
munmap((char *)top,fileLength);
1339
if (fontFileFD >= 0) close(fontFileFD);
1340
if (fileName != 0) delete[] fileName;
1341
if (fontName != 0) delete fontName;
1344
unsigned long PDFFTrueTypeFont::charToTag(const char *tagName)
1346
int n = strlen(tagName);
1347
unsigned long tag = 0;
1351
for (i = 0;i < n;i++) {
1353
tag |= tagName[i] & 0xff;
1363
setup GSUB table data
1364
Only supporting vertical text substitution.
1366
int PDFFTrueTypeFont::setupGSUB(const char *tagName)
1370
USHORT scriptList, featureList;
1375
USHORT featureCount;
1376
USHORT featureIndex;
1386
ttag = charToTag(tagName);
1387
if (featureTable != 0 && ttag == scriptTag) {
1388
/* already setup GSUB */
1392
/* read GSUB Header */
1393
if (getTable(TAG_GSUB,&gsubTable) < 0) {
1394
return 0; /* GSUB table not found */
1396
setOffset(gsubTable);
1397
skip<Fixed>(); // skip version
1402
lookupList = llist+gsubTable; /* change to offset from top of file */
1403
/* read script list table */
1404
setOffset(gsubTable+scriptList);
1407
for (i = 0;i < scriptCount;i++) {
1410
if (tag == scriptTag) {
1415
if (i >= scriptCount) {
1420
/* read script table */
1421
/* use default language system */
1422
setOffset(gsubTable+scriptList+scriptTable);
1423
read(&langSys); /* default language system */
1425
/* read LangSys table */
1427
/* no ldefault LangSys */
1431
setOffset(gsubTable+scriptList+scriptTable+langSys);
1432
skip<USHORT>(); /* skip LookupOrder */
1433
read(&featureIndex); /* ReqFeatureIndex */
1434
if (featureIndex != 0xffff) {
1435
oldOffset = getOffset();
1436
/* read feature record */
1437
setOffset(gsubTable+featureList);
1439
read(&featureCount);
1440
setOffset(gsubTable+featureList+sizeof(USHORT)+
1441
featureIndex*(sizeof(TAG)+sizeof(USHORT)));
1443
if (tag == TAG_VRT2) {
1444
/* vrt2 is preferred, overwrite vert */
1446
/* convert to offset from file top */
1447
featureTable = ftable+gsubTable+featureList;
1449
} else if (tag == TAG_VERT) {
1452
setOffset(oldOffset); /* restore offset */
1454
read(&featureCount);
1455
/* find 'vrt2' or 'vert' feature */
1456
for (i = 0;i < featureCount;i++) {
1457
read(&featureIndex);
1458
oldOffset = getOffset();
1459
/* read feature record */
1460
setOffset(gsubTable+featureList+sizeof(USHORT)+
1461
featureIndex*(sizeof(TAG)+sizeof(USHORT)));
1463
if (tag == TAG_VRT2) {
1464
/* vrt2 is preferred, overwrite vert */
1467
} else if (ftable == 0 && tag == TAG_VERT) {
1470
setOffset(oldOffset); /* restore offset */
1473
/* vert nor vrt2 are not found */
1476
/* convert to offset from file top */
1477
featureTable = ftable+gsubTable+featureList;
1481
int PDFFTrueTypeFont::getTableDirEntry(TAG tableTag, TableDirectory *ent)
1485
/* set to the top of Table Directory entiries */
1486
setOffset(offsetTable+OFFSET_TABLE_LEN);
1487
for (i = 0;i < numTables;i++) {
1491
if (tag == tableTag) {
1494
read(&(ent->checkSum));
1495
read(&(ent->offset));
1496
read(&(ent->length));
1499
advance(sizeof(ULONG)*3); /* skip to next entry */
1501
return -1; /* not found */
1504
int PDFFTrueTypeFont::getTable(TAG tableTag, ULONG *tableOffset,
1509
if (getTableDirEntry(tableTag,&ent) < 0) {
1513
if (tableOffset != 0) {
1514
*tableOffset = ent.offset;
1516
if (tableLength != 0) {
1517
*tableLength = ent.length;
1522
unsigned long PDFFTrueTypeFont::doMapToVertGID(unsigned long orgGID)
1525
USHORT lookupListIndex;
1527
unsigned long gid = 0;
1529
setOffset(featureTable+sizeof(USHORT));
1531
for (i = 0;i < lookupCount;i++) {
1532
read(&lookupListIndex);
1533
if ((gid = scanLookupList(lookupListIndex,orgGID)) != 0) {
1540
unsigned long PDFFTrueTypeFont::mapToVertGID(unsigned long code,
1541
unsigned long orgGID)
1543
unsigned long mapped;
1546
if (featureTable == 0) return orgGID;
1547
if ((mapped = doMapToVertGID(orgGID)) != 0) {
1548
//fprintf(stderr,"DEBUG:GSUB map %d to %d\n",orgGID,mapped);
1554
unsigned long PDFFTrueTypeFont::scanLookupList(USHORT listIndex,
1555
unsigned long orgGID)
1558
USHORT subTableCount;
1561
unsigned long gid = 0;
1562
ULONG oldOffset = getOffset();
1564
if (lookupList == 0) return 0; /* no lookup list */
1565
setOffset(lookupList+sizeof(USHORT)+listIndex*sizeof(USHORT));
1567
/* read lookup table */
1568
setOffset(lookupList+lookupTable);
1569
skip<USHORT>(); /* skip LookupType */
1570
skip<USHORT>(); /* skip LookupFlag */
1571
read(&subTableCount);
1572
for (i = 0;i < subTableCount;i++) {
1574
if ((gid = scanLookupSubTable(lookupList+lookupTable+subTable,orgGID))
1577
setOffset(oldOffset); /* restore offset */
1581
unsigned long PDFFTrueTypeFont::scanLookupSubTable(ULONG subTable,
1582
unsigned long orgGID)
1589
unsigned long gid = 0;
1591
ULONG oldOffset = getOffset();
1593
setOffset(subTable);
1596
if ((coverageIndex =
1597
checkGIDInCoverage(subTable+coverage,orgGID)) >= 0) {
1607
if (glyphCount > coverageIndex) {
1608
advance(coverageIndex*sizeof(GlyphID));
1614
/* unknown format */
1618
setOffset(oldOffset); /* restore offset */
1622
int PDFFTrueTypeFont::checkGIDInCoverage(ULONG coverage, unsigned long orgGID)
1625
ULONG oldOffset = getOffset();
1630
setOffset(coverage);
1635
for (i = 0;i < count;i++) {
1639
if (gid == orgGID) {
1643
} else if (gid > orgGID) {
1651
for (i = 0;i < count;i++) {
1652
GlyphID startGID, endGID;
1658
if (startGID <= orgGID && orgGID <= endGID) {
1660
index = startIndex+orgGID-startGID;
1662
} else if (orgGID <= endGID) {
1671
setOffset(oldOffset); /* restore offset */