1 #import <Onyx2D/O2TTFDecoder.h>
2 #import <Onyx2D/O2DataProvider.h>
3 #import <Onyx2D/O2Font.h>
4 #import <Onyx2D/O2MutablePath.h>
5 #import <Foundation/NSMapTable.h>
7 @implementation O2TTFDecoder
9 typedef uint32_t Fixed32;
10 typedef uint16_t FWord16;
11 typedef int64_t longDateTime64;
13 O2TTFDecoderRef O2TTFDecoderCreate(O2DataProviderRef dataProvider) {
14 O2TTFDecoderRef self=NSAllocateObject([O2TTFDecoder class],0,NULL);
17 self->_dataProvider=O2DataProviderRetain(dataProvider);
18 self->_data=O2DataProviderCopyData(dataProvider);
19 self->_bytes=CFDataGetBytePtr(self->_data);
20 self->_length=CFDataGetLength(self->_data);
27 O2TTFDecoderRef O2TTFDecoderRetain(O2TTFDecoderRef self) {
31 void O2TTFDecoderRelease(O2TTFDecoderRef self) {
35 static void dump(O2TTFDecoderRef self,NSString *format,...){
39 va_start(arguments,format);
40 NSLogv(format,arguments);
46 static CFIndex currentPosition(O2TTFDecoderRef self){
47 return self->_position;
50 static void seekToPosition(O2TTFDecoderRef self,CFIndex value){
51 self->_position=value;
55 static uint8_t decode_uint8(O2TTFDecoderRef self){
56 if(self->_position>=self->_length){
57 dump(self,@"overflow");
61 return self->_bytes[self->_position++];
64 static uint16_t decode_uint16(O2TTFDecoderRef self){
67 result=decode_uint8(self);
69 result|=decode_uint8(self);
74 static int16_t decode_int16(O2TTFDecoderRef self){
77 result=decode_uint8(self);
79 result|=decode_uint8(self);
85 static uint32_t decode_uint32(O2TTFDecoderRef self){
88 result=decode_uint8(self);
90 result|=decode_uint8(self);
92 result|=decode_uint8(self);
94 result|=decode_uint8(self);
99 static longDateTime64 decode_longDateTime64(O2TTFDecoderRef self){
102 result=decode_uint32(self);
104 result|=decode_uint32(self);
109 static Fixed32 decode_Fixed32(O2TTFDecoderRef self){
110 return decode_uint32(self);
113 static FWord16 decode_FWord16(O2TTFDecoderRef self){
114 return decode_uint16(self);
117 void decode_format_0(O2TTFDecoderRef self){
119 void decode_format_2(O2TTFDecoderRef self){
121 void decode_format_4(O2TTFDecoderRef self,O2Glyph **twoLevel){
126 uint16_t idRangePosition;
129 uint16_t length=decode_uint16(self);
130 dump(self,@"length=%d",length);
131 uint16_t language=decode_uint16(self);
132 dump(self,@"language=%d",language);
133 uint16_t segCountX2=decode_uint16(self);
134 uint16_t segCount=segCountX2/2;
135 segments=__builtin_alloca(sizeof(struct segment)*segCount);
136 dump(self,@"segCountX2=%d",segCountX2);
137 uint16_t searchRange=decode_uint16(self);
138 dump(self,@"searchRange=%d",searchRange);
139 uint16_t entrySelector=decode_uint16(self);
140 dump(self,@"entrySelector=%d",entrySelector);
141 uint16_t rangeShift=decode_uint16(self);
142 dump(self,@"rangeShift=%d",rangeShift);
145 for(i=0;i<segCount;i++){
146 uint16_t endCode=decode_uint16(self);
147 dump(self,@"endCode[%d]=%x",i,endCode);
148 segments[i].endCode=endCode;
151 uint16_t reservedPad=decode_uint16(self);
152 dump(self,@"reservedPad=%d",reservedPad);
154 for(i=0;i<segCount;i++){
155 uint16_t startCode=decode_uint16(self);
156 dump(self,@"startCode[%d]=%x",i,startCode);
157 segments[i].startCode=startCode;
160 for(i=0;i<segCount;i++){
161 uint16_t idDelta=decode_uint16(self);
162 dump(self,@"idDelta[%d]=%x",i,idDelta);
164 segments[i].idDelta=idDelta;
167 for(i=0;i<segCount;i++){
168 uint16_t position=self->_position;
169 uint16_t idRangeOffset=decode_uint16(self);
172 segments[i].idRangePosition=0;
174 segments[i].idRangePosition=position+idRangeOffset;
176 dump(self,@"idRangeOffset[%d]=%x",i,idRangeOffset);
179 for(i=0;i<segCount && segments[i].endCode!=0xFFFF;i++){
180 uint16_t code=segments[i].startCode;
182 if(segments[i].idRangePosition==0){
183 for(;code<=segments[i].endCode;code++){
184 uint16_t glyph=segments[i].idDelta+code;
185 uint8_t group=code>>8;
186 uint8_t index=code&0xFF;
188 if(twoLevel[group]==NULL)
189 twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
191 twoLevel[group][index]=glyph;
195 self->_position=segments[i].idRangePosition;
197 for(;code<=segments[i].endCode;code++){
198 uint16_t glyph=decode_uint16(self);
199 uint8_t group=code>>8;
200 uint8_t index=code&0xFF;
202 if(twoLevel[group]==NULL)
203 twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
205 twoLevel[group][index]=glyph;
210 void decode_format_6(O2TTFDecoderRef self){
213 void decode_subtable(O2TTFDecoderRef self,O2Glyph **twoLevel){
214 uint16_t platformID=decode_uint16(self);
215 dump(self,@"platformID=%d",platformID);
216 uint16_t platformSpecificID=decode_uint16(self);
217 dump(self,@"platformSpecificID=%d",platformSpecificID);
218 uint32_t offset=decode_uint32(self);
219 dump(self,@"offset=%d",offset);
221 CFIndex save=self->_position;
222 self->_position=offset;
223 uint16_t format=decode_uint16(self);
224 dump(self,@"format=%d",format);
229 decode_format_0(self);
233 decode_format_2(self);
237 decode_format_4(self,twoLevel);
241 decode_format_6(self);
245 dump(self,@"unknown format %d",format);
250 self->_position=save;
253 O2Glyph **O2TTFecoderTwoLevelUnicode_cmap(O2TTFDecoderRef self){
254 O2Glyph **twoLevel=NSZoneCalloc(NULL,256,sizeof(O2Glyph *));
256 uint16_t version=decode_uint16(self);
257 dump(self,@"version=%d",version);
258 uint16_t i,subTableCount=decode_uint16(self);
259 dump(self,@"subTableCount=%d",subTableCount);
261 for(i=0;i<subTableCount;i++){
262 decode_subtable(self,twoLevel);
268 BOOL seekToTable(O2TTFDecoderRef self,uint32_t seekToTag){
270 uint32_t scaler=decode_uint32(self);
272 if(scaler!=0x00010000 && scaler!=0x74727565){
273 dump(self,@"invalid scaler=%08X",scaler);
277 uint16_t numTables=decode_uint16(self);
278 uint16_t searchRange=decode_uint16(self);
279 uint16_t entrySelector=decode_uint16(self);
280 uint16_t rangeShift=decode_uint16(self);
283 for(i=0;i<numTables;i++){
284 uint32_t tag=decode_uint32(self);
285 uint32_t checkSum=decode_uint32(self);
286 uint32_t offset=decode_uint32(self);
287 uint32_t length=decode_uint32(self);
290 self->_position=offset;
295 dump(self,@"unable to find tag %c%c%c%c",seekToTag>>24,(seekToTag>>16)&0xFF,(seekToTag>>8)&0xFF,seekToTag&0xFF);
299 // FIXME: remove the glyph entry, pointless
302 } MacintoshNameMapping[258]={
305 { 2,@"nonmarkingreturn" },
313 { 10,@"quotesingle" },
315 { 12,@"parenright" },
365 { 62,@"bracketleft" },
367 { 64,@"bracketright" },
368 { 65,@"asciicircum" },
369 { 66,@"underscore" },
399 { 96,@"braceright" },
400 { 97,@"asciitilde" },
406 { 103,@"Odieresis" },
407 { 104,@"Udieresis" },
410 { 107,@"acircumflex" },
411 { 108,@"adieresis" },
417 { 114,@"ecircumflex" },
418 { 115,@"edieresis" },
421 { 118,@"icircumflex" },
422 { 119,@"idieresis" },
426 { 123,@"ocircumflex" },
427 { 124,@"odieresis" },
431 { 128,@"ucircumflex" },
432 { 129,@"udieresis" },
439 { 136,@"paragraph" },
440 { 137,@"germandbls" },
441 { 138,@"registered" },
442 { 139,@"copyright" },
443 { 140,@"trademark" },
450 { 147,@"plusminus" },
451 { 148,@"lessequal" },
452 { 149,@"greaterequal" },
455 { 152,@"partialdiff" },
456 { 153,@"summation" },
460 { 157,@"ordfeminine" },
461 { 158,@"ordmasculine" },
465 { 162,@"questiondown" },
466 { 163,@"exclamdown" },
467 { 164,@"logicalnot" },
470 { 167,@"approxequal" },
472 { 169,@"guillemotleft" },
473 { 170,@"guillemotright" },
475 { 172,@"nonbreakingspace" },
483 { 180,@"quotedblleft" },
484 { 181,@"quotedblright" },
485 { 182,@"quoteleft" },
486 { 183,@"quoteright" },
489 { 186,@"ydieresis" },
490 { 187,@"Ydieresis" },
493 { 190,@"guilsinglleft" },
494 { 191,@"guilsinglright" },
497 { 194,@"daggerdbl" },
498 { 195,@"periodcentered" },
499 { 196,@"quotesinglbase" },
500 { 197,@"quotedblbase" },
501 { 198,@"perthousand" },
502 { 199,@"Acircumflex" },
503 { 200,@"Ecircumflex" },
505 { 202,@"Edieresis" },
508 { 205,@"Icircumflex" },
509 { 206,@"Idieresis" },
512 { 209,@"Ocircumflex" },
516 { 213,@"Ucircumflex" },
519 { 216,@"circumflex" },
523 { 220,@"dotaccent" },
526 { 223,@"hungarumlaut" },
535 { 232,@"brokenbar" },
544 { 241,@"onesuperior" },
545 { 242,@"twosuperior" },
546 { 243,@"threesuperior" },
548 { 245,@"onequarter" },
549 { 246,@"threequarters" },
553 { 250,@"Idotaccent" },
563 static void loadMacintoshNameMapping(NSMapTable *table){
567 NSMapInsert(table,MacintoshNameMapping[i].name,(void *)i);
570 NSMapTable *O2TTFDecoderGetPostScriptNameMapTable(O2TTFDecoderRef self,int *numberOfGlyphs){
571 NSMapTable *result=NSCreateMapTable(NSObjectMapKeyCallBacks,NSIntegerMapValueCallBacks,258);
573 if(!seekToTable(self,'post'))
576 Fixed32 format=decode_Fixed32(self);
577 Fixed32 italicAngle=decode_Fixed32(self);
578 FWord16 underlinePosition=decode_FWord16(self);
579 FWord16 underlineThickness=decode_FWord16(self);
580 uint32_t isFixedPitch=decode_uint32(self);
581 uint32_t minMemType42=decode_uint32(self);
582 uint32_t maxMemType42=decode_uint32(self);
583 uint32_t minMemType1=decode_uint32(self);
584 uint32_t maxMemType1=decode_uint32(self);
589 NSLog(@"unimplemented 'post' format %08X",format);
593 loadMacintoshNameMapping(result);
597 uint16_t numberOfGlyphs=decode_uint16(self);
600 uint16_t glyphNameIndex[numberOfGlyphs];
602 for(i=0;i<numberOfGlyphs;i++){
603 glyphNameIndex[i]=decode_uint16(self);
605 maxIndex=MAX(maxIndex,glyphNameIndex[i]);
609 NSString *names[maxIndex];
611 for(i=0;i<maxIndex;i++){
612 uint8_t length=decode_uint8(self);
613 uint8_t buffer[length];
616 for(count=0;count<length;count++)
617 buffer[count]=decode_uint8(self);
619 names[i]=[[NSString alloc] initWithBytes:buffer length:count encoding:NSASCIIStringEncoding];
622 for(i=0;i<numberOfGlyphs;i++){
623 uint16_t nameIndex=glyphNameIndex[i];
626 NSMapInsert(result,MacintoshNameMapping[nameIndex].name,(void *)i);
629 NSMapInsert(result,names[nameIndex],(void *)i);
633 for(i=0;i<maxIndex;i++)
642 int O2TTFDecoderGetOffsetsAreLong(O2TTFDecoderRef self) {
643 if(!seekToTable(self,'head'))
646 Fixed32 version=decode_Fixed32(self);
647 Fixed32 fontRevision=decode_Fixed32(self);
648 uint32_t checkSumAdjustment=decode_uint32(self);
649 uint32_t magicNumber=decode_uint32(self);
650 uint16_t flags=decode_uint16(self);
651 uint16_t unitsPerEm=decode_uint16(self);
652 longDateTime64 created=decode_longDateTime64(self);
653 longDateTime64 modified=decode_longDateTime64(self);
654 FWord16 xMin=decode_FWord16(self);
655 FWord16 yMin=decode_FWord16(self);
656 FWord16 xMax=decode_FWord16(self);
657 FWord16 yMax=decode_FWord16(self);
658 uint16_t macStyle=decode_uint16(self);
659 uint16_t lowestRecPPEM=decode_uint16(self);
660 int16_t fontDirectionHint=decode_int16(self);
661 int16_t indexToLocFormat=decode_int16(self);
662 int16_t glyphDataFormat=decode_int16(self);
664 return indexToLocFormat;
667 int *O2TTFDecoderGetGlyphLocations(O2TTFDecoderRef self,int numberOfGlyphs) {
668 int *result=NSZoneMalloc(NULL,sizeof(int)*numberOfGlyphs);
670 if(O2TTFDecoderGetOffsetsAreLong(self)){
671 if(!seekToTable(self,'loca'))
675 for(i=0;i<numberOfGlyphs;i++)
676 result[i]=decode_uint32(self);
680 if(!seekToTable(self,'loca'))
684 for(i=0;i<numberOfGlyphs;i++)
685 result[i]=decode_uint16(self);
690 O2PathRef O2TTFDecoderGetGlyphOutline(O2TTFDecoderRef self,int glyphLocation) {
691 O2PathRef result=O2PathCreateMutable();
693 if(!seekToTable(self,'glyf'))
696 self->_position+=glyphLocation;
698 int16_t numberOfContours=decode_int16(self);
700 if(numberOfContours>=0){
701 uint16_t endPtsOfContours[numberOfContours];
704 for(i=0;i<numberOfContours;i++)
705 endPtsOfContours[i]=decode_uint16(self);
707 uint16_t instructionLength=decode_uint16(self);
708 uint8_t instructions[instructionLength];
710 for(i=0;i<instructionLength;i++)
711 instructions[i]=decode_uint8(self);
715 else if(numberOfContours==-1){
718 NSLog(@"invalid numberOfContours=%d",numberOfContours);
724 void O2TTFDecoderGetNameTable(O2TTFDecoderRef self) {
725 if(!seekToTable(self,'name')){
726 NSLog(@"TrueType error: No name table");
730 int stringTable=self->_position;
732 uint16_t format=decode_uint16(self);
733 uint16_t i,count=decode_uint16(self);
734 uint16_t stringOffset=decode_uint16(self);
736 stringTable+=stringOffset;
738 for(i=0;i<count;i++){
739 uint16_t platformID=decode_uint16(self);
740 /*uint16_t platformSpecificID=*/decode_uint16(self);
741 uint16_t languageID=decode_uint16(self);
742 uint16_t nameID=decode_uint16(self);
743 uint16_t length=decode_uint16(self);
744 uint16_t offset=decode_uint16(self);
746 CFIndex location=stringTable+offset;
748 NSLog(@"platformID=%d,languageId=%d,nameID=%d",platformID,languageID,nameID);
750 NSLog(@"position=%ld,stringOffset=%d,offset=%d",self->_position,stringOffset,offset);
752 NSString *string=[NSString stringWithCString:(const char *)self->_bytes+location length:length];
754 NSLog(@"platformID=%d,languageID=%d,string=%@",platformID,languageID,string);