mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-23 12:09:51 +00:00
706 lines
17 KiB
Objective-C
706 lines
17 KiB
Objective-C
#import "O2TTFDecoder.h"
|
|
#import "O2DataProvider.h"
|
|
#import "O2Font.h"
|
|
#import "O2MutablePath.h"
|
|
#import <Foundation/NSMapTable.h>
|
|
|
|
@implementation O2TTFDecoder
|
|
|
|
typedef uint32_t Fixed32;
|
|
typedef uint16_t FWord16;
|
|
typedef int64_t longDateTime64;
|
|
|
|
O2TTFDecoderRef O2TTFDecoderCreate(O2DataProviderRef dataProvider) {
|
|
O2TTFDecoderRef self=NSAllocateObject([O2TTFDecoder class],0,NULL);
|
|
|
|
self->_dataProvider=O2DataProviderRetain(dataProvider);
|
|
self->_data=O2DataProviderCopyData(dataProvider);
|
|
self->_bytes=CFDataGetBytePtr(self->_data);
|
|
self->_length=CFDataGetLength(self->_data);
|
|
self->_position=0;
|
|
|
|
return self;
|
|
}
|
|
|
|
static void dump(O2TTFDecoderRef self,NSString *format,...){
|
|
if(self->_dump){
|
|
va_list arguments;
|
|
|
|
va_start(arguments,format);
|
|
NSLogv(format,arguments);
|
|
va_end(arguments);
|
|
}
|
|
}
|
|
|
|
static uint8_t decode_uint8(O2TTFDecoderRef self){
|
|
if(self->_position>=self->_length){
|
|
dump(self,@"overflow");
|
|
exit(0);
|
|
}
|
|
|
|
return self->_bytes[self->_position++];
|
|
}
|
|
|
|
static uint16_t decode_uint16(O2TTFDecoderRef self){
|
|
uint16_t result;
|
|
|
|
result=decode_uint8(self);
|
|
result<<=8;
|
|
result|=decode_uint8(self);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int16_t decode_int16(O2TTFDecoderRef self){
|
|
uint16_t result;
|
|
|
|
result=decode_uint8(self);
|
|
result<<=8;
|
|
result|=decode_uint8(self);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
static uint32_t decode_uint32(O2TTFDecoderRef self){
|
|
uint32_t result;
|
|
|
|
result=decode_uint8(self);
|
|
result<<=8;
|
|
result|=decode_uint8(self);
|
|
result<<=8;
|
|
result|=decode_uint8(self);
|
|
result<<=8;
|
|
result|=decode_uint8(self);
|
|
|
|
return result;
|
|
}
|
|
|
|
static longDateTime64 decode_longDateTime64(O2TTFDecoderRef self){
|
|
uint64_t result;
|
|
|
|
result=decode_uint32(self);
|
|
result<<=32;
|
|
result|=decode_uint32(self);
|
|
|
|
return result;
|
|
}
|
|
|
|
static Fixed32 decode_Fixed32(O2TTFDecoderRef self){
|
|
return decode_uint32(self);
|
|
}
|
|
|
|
static FWord16 decode_FWord16(O2TTFDecoderRef self){
|
|
return decode_uint16(self);
|
|
}
|
|
|
|
void decode_format_0(O2TTFDecoderRef self){
|
|
}
|
|
void decode_format_2(O2TTFDecoderRef self){
|
|
}
|
|
void decode_format_4(O2TTFDecoderRef self,O2Glyph **twoLevel){
|
|
struct segment {
|
|
uint16_t endCode;
|
|
uint16_t startCode;
|
|
uint16_t idDelta;
|
|
uint16_t idRangePosition;
|
|
} *segments;
|
|
|
|
uint16_t length=decode_uint16(self);
|
|
dump(self,@"length=%d",length);
|
|
uint16_t language=decode_uint16(self);
|
|
dump(self,@"language=%d",language);
|
|
uint16_t segCountX2=decode_uint16(self);
|
|
uint16_t segCount=segCountX2/2;
|
|
segments=__builtin_alloca(sizeof(struct segment)*segCount);
|
|
dump(self,@"segCountX2=%d",segCountX2);
|
|
uint16_t searchRange=decode_uint16(self);
|
|
dump(self,@"searchRange=%d",searchRange);
|
|
uint16_t entrySelector=decode_uint16(self);
|
|
dump(self,@"entrySelector=%d",entrySelector);
|
|
uint16_t rangeShift=decode_uint16(self);
|
|
dump(self,@"rangeShift=%d",rangeShift);
|
|
uint16_t i;
|
|
|
|
for(i=0;i<segCount;i++){
|
|
uint16_t endCode=decode_uint16(self);
|
|
dump(self,@"endCode[%d]=%x",i,endCode);
|
|
segments[i].endCode=endCode;
|
|
}
|
|
|
|
uint16_t reservedPad=decode_uint16(self);
|
|
dump(self,@"reservedPad=%d",reservedPad);
|
|
|
|
for(i=0;i<segCount;i++){
|
|
uint16_t startCode=decode_uint16(self);
|
|
dump(self,@"startCode[%d]=%x",i,startCode);
|
|
segments[i].startCode=startCode;
|
|
}
|
|
|
|
for(i=0;i<segCount;i++){
|
|
uint16_t idDelta=decode_uint16(self);
|
|
dump(self,@"idDelta[%d]=%x",i,idDelta);
|
|
|
|
segments[i].idDelta=idDelta;
|
|
}
|
|
|
|
for(i=0;i<segCount;i++){
|
|
uint16_t position=self->_position;
|
|
uint16_t idRangeOffset=decode_uint16(self);
|
|
|
|
if(idRangeOffset==0)
|
|
segments[i].idRangePosition=0;
|
|
else
|
|
segments[i].idRangePosition=position+idRangeOffset;
|
|
|
|
dump(self,@"idRangeOffset[%d]=%x",i,idRangeOffset);
|
|
}
|
|
|
|
for(i=0;i<segCount && segments[i].endCode!=0xFFFF;i++){
|
|
uint16_t code=segments[i].startCode;
|
|
|
|
if(segments[i].idRangePosition==0){
|
|
for(;code<=segments[i].endCode;code++){
|
|
uint16_t glyph=segments[i].idDelta+code;
|
|
uint8_t group=code>>8;
|
|
uint8_t index=code&0xFF;
|
|
|
|
if(twoLevel[group]==NULL)
|
|
twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
|
|
|
|
twoLevel[group][index]=glyph;
|
|
}
|
|
}
|
|
else {
|
|
self->_position=segments[i].idRangePosition;
|
|
|
|
for(;code<=segments[i].endCode;code++){
|
|
uint16_t glyph=decode_uint16(self);
|
|
uint8_t group=code>>8;
|
|
uint8_t index=code&0xFF;
|
|
|
|
if(twoLevel[group]==NULL)
|
|
twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
|
|
|
|
twoLevel[group][index]=glyph;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void decode_format_6(O2TTFDecoderRef self){
|
|
}
|
|
|
|
void decode_subtable(O2TTFDecoderRef self,O2Glyph **twoLevel){
|
|
uint16_t platformID=decode_uint16(self);
|
|
dump(self,@"platformID=%d",platformID);
|
|
uint16_t platformSpecificID=decode_uint16(self);
|
|
dump(self,@"platformSpecificID=%d",platformSpecificID);
|
|
uint32_t offset=decode_uint32(self);
|
|
dump(self,@"offset=%d",offset);
|
|
|
|
CFIndex save=self->_position;
|
|
self->_position=offset;
|
|
uint16_t format=decode_uint16(self);
|
|
dump(self,@"format=%d",format);
|
|
|
|
switch(format){
|
|
|
|
case 0:
|
|
decode_format_0(self);
|
|
break;
|
|
|
|
case 2:
|
|
decode_format_2(self);
|
|
break;
|
|
|
|
case 4:
|
|
decode_format_4(self,twoLevel);
|
|
break;
|
|
|
|
case 6:
|
|
decode_format_6(self);
|
|
break;
|
|
|
|
default:
|
|
dump(self,@"unknown format %d",format);
|
|
break;
|
|
|
|
}
|
|
|
|
self->_position=save;
|
|
}
|
|
|
|
O2Glyph **O2TTFecoderTwoLevelUnicode_cmap(O2TTFDecoderRef self){
|
|
O2Glyph **twoLevel=NSZoneCalloc(NULL,256,sizeof(O2Glyph *));
|
|
|
|
uint16_t version=decode_uint16(self);
|
|
dump(self,@"version=%d",version);
|
|
uint16_t i,subTableCount=decode_uint16(self);
|
|
dump(self,@"subTableCount=%d",subTableCount);
|
|
|
|
for(i=0;i<subTableCount;i++){
|
|
decode_subtable(self,twoLevel);
|
|
}
|
|
|
|
return twoLevel;
|
|
}
|
|
|
|
BOOL seekToTable(O2TTFDecoderRef self,uint32_t seekToTag){
|
|
self->_position=0;
|
|
uint32_t scaler=decode_uint32(self);
|
|
|
|
if(scaler!=0x00010000 && scaler!=0x74727565){
|
|
dump(self,@"invalid scaler=%08X",scaler);
|
|
return NO;
|
|
}
|
|
|
|
uint16_t numTables=decode_uint16(self);
|
|
uint16_t searchRange=decode_uint16(self);
|
|
uint16_t entrySelector=decode_uint16(self);
|
|
uint16_t rangeShift=decode_uint16(self);
|
|
int i;
|
|
|
|
for(i=0;i<numTables;i++){
|
|
uint32_t tag=decode_uint32(self);
|
|
uint32_t checkSum=decode_uint32(self);
|
|
uint32_t offset=decode_uint32(self);
|
|
uint32_t length=decode_uint32(self);
|
|
|
|
if(tag==seekToTag){
|
|
self->_position=offset;
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
dump(self,@"unable to find tag %c%c%c%c",seekToTag>>24,(seekToTag>>16)&0xFF,(seekToTag>>8)&0xFF,seekToTag&0xFF);
|
|
return NO;
|
|
}
|
|
static struct {
|
|
// FIXME: remove the glyph entry, pointless
|
|
O2Glyph glyph;
|
|
NSString *name;
|
|
} MacintoshNameMapping[258]={
|
|
{ 0,@".notdef" },
|
|
{ 1,@".null" },
|
|
{ 2,@"nonmarkingreturn" },
|
|
{ 3,@"space" },
|
|
{ 4,@"exclam" },
|
|
{ 5,@"quotedbl" },
|
|
{ 6,@"numbersign" },
|
|
{ 7,@"dollar" },
|
|
{ 8,@"percent" },
|
|
{ 9,@"ampersand" },
|
|
{ 10,@"quotesingle" },
|
|
{ 11,@"parenleft" },
|
|
{ 12,@"parenright" },
|
|
{ 13,@"asterisk" },
|
|
{ 14,@"plus" },
|
|
{ 15,@"comma" },
|
|
{ 16,@"hyphen" },
|
|
{ 17,@"period" },
|
|
{ 18,@"slash" },
|
|
{ 19,@"zero" },
|
|
{ 20,@"one" },
|
|
{ 21,@"two" },
|
|
{ 22,@"three" },
|
|
{ 23,@"four" },
|
|
{ 24,@"five" },
|
|
{ 25,@"six" },
|
|
{ 26,@"seven" },
|
|
{ 27,@"eight" },
|
|
{ 28,@"nine" },
|
|
{ 29,@"colon" },
|
|
{ 30,@"semicolon" },
|
|
{ 31,@"less" },
|
|
{ 32,@"equal" },
|
|
{ 33,@"greater" },
|
|
{ 34,@"question" },
|
|
{ 35,@"at" },
|
|
{ 36,@"A" },
|
|
{ 37,@"B" },
|
|
{ 38,@"C" },
|
|
{ 39,@"D" },
|
|
{ 40,@"E" },
|
|
{ 41,@"F" },
|
|
{ 42,@"G" },
|
|
{ 43,@"H" },
|
|
{ 44,@"I" },
|
|
{ 45,@"J" },
|
|
{ 46,@"K" },
|
|
{ 47,@"L" },
|
|
{ 48,@"M" },
|
|
{ 49,@"N" },
|
|
{ 50,@"O" },
|
|
{ 51,@"P" },
|
|
{ 52,@"Q" },
|
|
{ 53,@"R" },
|
|
{ 54,@"S" },
|
|
{ 55,@"T" },
|
|
{ 56,@"U" },
|
|
{ 57,@"V" },
|
|
{ 58,@"W" },
|
|
{ 59,@"X" },
|
|
{ 60,@"Y" },
|
|
{ 61,@"Z" },
|
|
{ 62,@"bracketleft" },
|
|
{ 63,@"backslash" },
|
|
{ 64,@"bracketright" },
|
|
{ 65,@"asciicircum" },
|
|
{ 66,@"underscore" },
|
|
{ 67,@"grave" },
|
|
{ 68,@"a" },
|
|
{ 69,@"b" },
|
|
{ 70,@"c" },
|
|
{ 71,@"d" },
|
|
{ 72,@"e" },
|
|
{ 73,@"f" },
|
|
{ 74,@"g" },
|
|
{ 75,@"h" },
|
|
{ 76,@"i" },
|
|
{ 77,@"j" },
|
|
{ 78,@"k" },
|
|
{ 79,@"l" },
|
|
{ 80,@"m" },
|
|
{ 81,@"n" },
|
|
{ 82,@"o" },
|
|
{ 83,@"p" },
|
|
{ 84,@"q" },
|
|
{ 85,@"r" },
|
|
{ 86,@"s" },
|
|
{ 87,@"t" },
|
|
{ 88,@"u" },
|
|
{ 89,@"v" },
|
|
{ 90,@"w" },
|
|
{ 91,@"x" },
|
|
{ 92,@"y" },
|
|
{ 93,@"z" },
|
|
{ 94,@"braceleft" },
|
|
{ 95,@"bar" },
|
|
{ 96,@"braceright" },
|
|
{ 97,@"asciitilde" },
|
|
{ 98,@"Adieresis" },
|
|
{ 99,@"Aring" },
|
|
{ 100,@"Ccedilla" },
|
|
{ 101,@"Eacute" },
|
|
{ 102,@"Ntilde" },
|
|
{ 103,@"Odieresis" },
|
|
{ 104,@"Udieresis" },
|
|
{ 105,@"aacute" },
|
|
{ 106,@"agrave" },
|
|
{ 107,@"acircumflex" },
|
|
{ 108,@"adieresis" },
|
|
{ 109,@"atilde" },
|
|
{ 110,@"aring" },
|
|
{ 111,@"ccedilla" },
|
|
{ 112,@"eacute" },
|
|
{ 113,@"egrave" },
|
|
{ 114,@"ecircumflex" },
|
|
{ 115,@"edieresis" },
|
|
{ 116,@"iacute" },
|
|
{ 117,@"igrave" },
|
|
{ 118,@"icircumflex" },
|
|
{ 119,@"idieresis" },
|
|
{ 120,@"ntilde" },
|
|
{ 121,@"oacute" },
|
|
{ 122,@"ograve" },
|
|
{ 123,@"ocircumflex" },
|
|
{ 124,@"odieresis" },
|
|
{ 125,@"otilde" },
|
|
{ 126,@"uacute" },
|
|
{ 127,@"ugrave" },
|
|
{ 128,@"ucircumflex" },
|
|
{ 129,@"udieresis" },
|
|
{ 130,@"dagger" },
|
|
{ 131,@"degree" },
|
|
{ 132,@"cent" },
|
|
{ 133,@"sterling" },
|
|
{ 134,@"section" },
|
|
{ 135,@"bullet" },
|
|
{ 136,@"paragraph" },
|
|
{ 137,@"germandbls" },
|
|
{ 138,@"registered" },
|
|
{ 139,@"copyright" },
|
|
{ 140,@"trademark" },
|
|
{ 141,@"acute" },
|
|
{ 142,@"dieresis" },
|
|
{ 143,@"notequal" },
|
|
{ 144,@"AE" },
|
|
{ 145,@"Oslash" },
|
|
{ 146,@"infinity" },
|
|
{ 147,@"plusminus" },
|
|
{ 148,@"lessequal" },
|
|
{ 149,@"greaterequal" },
|
|
{ 150,@"yen" },
|
|
{ 151,@"mu" },
|
|
{ 152,@"partialdiff" },
|
|
{ 153,@"summation" },
|
|
{ 154,@"product" },
|
|
{ 155,@"pi" },
|
|
{ 156,@"integral" },
|
|
{ 157,@"ordfeminine" },
|
|
{ 158,@"ordmasculine" },
|
|
{ 159,@"Omega" },
|
|
{ 160,@"ae" },
|
|
{ 161,@"oslash" },
|
|
{ 162,@"questiondown" },
|
|
{ 163,@"exclamdown" },
|
|
{ 164,@"logicalnot" },
|
|
{ 165,@"radical" },
|
|
{ 166,@"florin" },
|
|
{ 167,@"approxequal" },
|
|
{ 168,@"Delta" },
|
|
{ 169,@"guillemotleft" },
|
|
{ 170,@"guillemotright" },
|
|
{ 171,@"ellipsis" },
|
|
{ 172,@"nonbreakingspace" },
|
|
{ 173,@"Agrave" },
|
|
{ 174,@"Atilde" },
|
|
{ 175,@"Otilde" },
|
|
{ 176,@"OE" },
|
|
{ 177,@"oe" },
|
|
{ 178,@"endash" },
|
|
{ 179,@"emdash" },
|
|
{ 180,@"quotedblleft" },
|
|
{ 181,@"quotedblright" },
|
|
{ 182,@"quoteleft" },
|
|
{ 183,@"quoteright" },
|
|
{ 184,@"divide" },
|
|
{ 185,@"lozenge" },
|
|
{ 186,@"ydieresis" },
|
|
{ 187,@"Ydieresis" },
|
|
{ 188,@"fraction" },
|
|
{ 189,@"currency" },
|
|
{ 190,@"guilsinglleft" },
|
|
{ 191,@"guilsinglright" },
|
|
{ 192,@"fi" },
|
|
{ 193,@"fl" },
|
|
{ 194,@"daggerdbl" },
|
|
{ 195,@"periodcentered" },
|
|
{ 196,@"quotesinglbase" },
|
|
{ 197,@"quotedblbase" },
|
|
{ 198,@"perthousand" },
|
|
{ 199,@"Acircumflex" },
|
|
{ 200,@"Ecircumflex" },
|
|
{ 201,@"Aacute" },
|
|
{ 202,@"Edieresis" },
|
|
{ 203,@"Egrave" },
|
|
{ 204,@"Iacute" },
|
|
{ 205,@"Icircumflex" },
|
|
{ 206,@"Idieresis" },
|
|
{ 207,@"Igrave" },
|
|
{ 208,@"Oacute" },
|
|
{ 209,@"Ocircumflex" },
|
|
{ 210,@"apple" },
|
|
{ 211,@"Ograve" },
|
|
{ 212,@"Uacute" },
|
|
{ 213,@"Ucircumflex" },
|
|
{ 214,@"Ugrave" },
|
|
{ 215,@"dotlessi" },
|
|
{ 216,@"circumflex" },
|
|
{ 217,@"tilde" },
|
|
{ 218,@"macron" },
|
|
{ 219,@"breve" },
|
|
{ 220,@"dotaccent" },
|
|
{ 221,@"ring" },
|
|
{ 222,@"cedilla" },
|
|
{ 223,@"hungarumlaut" },
|
|
{ 224,@"ogonek" },
|
|
{ 225,@"caron" },
|
|
{ 226,@"Lslash" },
|
|
{ 227,@"lslash" },
|
|
{ 228,@"Scaron" },
|
|
{ 229,@"scaron" },
|
|
{ 230,@"Zcaron" },
|
|
{ 231,@"zcaron" },
|
|
{ 232,@"brokenbar" },
|
|
{ 233,@"Eth" },
|
|
{ 234,@"eth" },
|
|
{ 235,@"Yacute" },
|
|
{ 236,@"yacute" },
|
|
{ 237,@"Thorn" },
|
|
{ 238,@"thorn" },
|
|
{ 239,@"minus" },
|
|
{ 240,@"multiply" },
|
|
{ 241,@"onesuperior" },
|
|
{ 242,@"twosuperior" },
|
|
{ 243,@"threesuperior" },
|
|
{ 244,@"onehalf" },
|
|
{ 245,@"onequarter" },
|
|
{ 246,@"threequarters" },
|
|
{ 247,@"franc" },
|
|
{ 248,@"Gbreve" },
|
|
{ 249,@"gbreve" },
|
|
{ 250,@"Idotaccent" },
|
|
{ 251,@"Scedilla" },
|
|
{ 252,@"scedilla" },
|
|
{ 253,@"Cacute" },
|
|
{ 254,@"cacute" },
|
|
{ 255,@"Ccaron" },
|
|
{ 256,@"ccaron" },
|
|
{ 257,@"dcroat" },
|
|
};
|
|
|
|
static void loadMacintoshNameMapping(NSMapTable *table){
|
|
NSInteger i;
|
|
|
|
for(i=0;i<258;i++)
|
|
NSMapInsert(table,MacintoshNameMapping[i].name,(void *)i);
|
|
}
|
|
|
|
NSMapTable *O2TTFDecoderGetPostScriptNameMapTable(O2TTFDecoderRef self,int *numberOfGlyphs){
|
|
NSMapTable *result=NSCreateMapTable(NSObjectMapKeyCallBacks,NSIntegerMapValueCallBacks,258);
|
|
|
|
if(!seekToTable(self,'post'))
|
|
return NULL;
|
|
|
|
Fixed32 format=decode_Fixed32(self);
|
|
Fixed32 italicAngle=decode_Fixed32(self);
|
|
FWord16 underlinePosition=decode_FWord16(self);
|
|
FWord16 underlineThickness=decode_FWord16(self);
|
|
uint32_t isFixedPitch=decode_uint32(self);
|
|
uint32_t minMemType42=decode_uint32(self);
|
|
uint32_t maxMemType42=decode_uint32(self);
|
|
uint32_t minMemType1=decode_uint32(self);
|
|
uint32_t maxMemType1=decode_uint32(self);
|
|
|
|
switch(format){
|
|
|
|
default:
|
|
NSLog(@"unimplemented 'post' format %08X",format);
|
|
return NULL;
|
|
|
|
case 0x00010000:;
|
|
loadMacintoshNameMapping(result);
|
|
break;
|
|
|
|
case 0x00020000:;
|
|
uint16_t numberOfGlyphs=decode_uint16(self);
|
|
int i;
|
|
uint16_t maxIndex=0;
|
|
uint16_t glyphNameIndex[numberOfGlyphs];
|
|
|
|
for(i=0;i<numberOfGlyphs;i++){
|
|
glyphNameIndex[i]=decode_uint16(self);
|
|
|
|
maxIndex=MAX(maxIndex,glyphNameIndex[i]);
|
|
}
|
|
maxIndex-=258;
|
|
maxIndex++;
|
|
NSString *names[maxIndex];
|
|
|
|
for(i=0;i<maxIndex;i++){
|
|
uint8_t length=decode_uint8(self);
|
|
uint8_t buffer[length];
|
|
int count=0;
|
|
|
|
for(count=0;count<length;count++)
|
|
buffer[count]=decode_uint8(self);
|
|
|
|
names[i]=[[NSString alloc] initWithBytes:buffer length:count encoding:NSASCIIStringEncoding];
|
|
}
|
|
|
|
for(i=0;i<numberOfGlyphs;i++){
|
|
uint16_t nameIndex=glyphNameIndex[i];
|
|
|
|
if(nameIndex<=257)
|
|
NSMapInsert(result,MacintoshNameMapping[nameIndex].name,(void *)i);
|
|
else {
|
|
nameIndex-=258;
|
|
NSMapInsert(result,names[nameIndex],(void *)i);
|
|
}
|
|
}
|
|
|
|
for(i=0;i<maxIndex;i++)
|
|
[names[i] release];
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int O2TTFDecoderGetOffsetsAreLong(O2TTFDecoderRef self) {
|
|
if(!seekToTable(self,'head'))
|
|
return NULL;
|
|
|
|
Fixed32 version=decode_Fixed32(self);
|
|
Fixed32 fontRevision=decode_Fixed32(self);
|
|
uint32_t checkSumAdjustment=decode_uint32(self);
|
|
uint32_t magicNumber=decode_uint32(self);
|
|
uint16_t flags=decode_uint16(self);
|
|
uint16_t unitsPerEm=decode_uint16(self);
|
|
longDateTime64 created=decode_longDateTime64(self);
|
|
longDateTime64 modified=decode_longDateTime64(self);
|
|
FWord16 xMin=decode_FWord16(self);
|
|
FWord16 yMin=decode_FWord16(self);
|
|
FWord16 xMax=decode_FWord16(self);
|
|
FWord16 yMax=decode_FWord16(self);
|
|
uint16_t macStyle=decode_uint16(self);
|
|
uint16_t lowestRecPPEM=decode_uint16(self);
|
|
int16_t fontDirectionHint=decode_int16(self);
|
|
int16_t indexToLocFormat=decode_int16(self);
|
|
int16_t glyphDataFormat=decode_int16(self);
|
|
|
|
return indexToLocFormat;
|
|
}
|
|
|
|
int *O2TTFDecoderGetGlyphLocations(O2TTFDecoderRef self,int numberOfGlyphs) {
|
|
int *result=NSZoneMalloc(NULL,sizeof(int)*numberOfGlyphs);
|
|
|
|
if(O2TTFDecoderGetOffsetsAreLong(self)){
|
|
if(!seekToTable(self,'loca'))
|
|
return NULL;
|
|
|
|
int i;
|
|
for(i=0;i<numberOfGlyphs;i++)
|
|
result[i]=decode_uint32(self);
|
|
|
|
}
|
|
else {
|
|
if(!seekToTable(self,'loca'))
|
|
return NULL;
|
|
|
|
int i;
|
|
for(i=0;i<numberOfGlyphs;i++)
|
|
result[i]=decode_uint16(self);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
O2PathRef O2TTFDecoderGetGlyphOutline(O2TTFDecoderRef self,int glyphLocation) {
|
|
O2PathRef result=O2PathCreateMutable();
|
|
|
|
if(!seekToTable(self,'glyf'))
|
|
return NULL;
|
|
|
|
self->_position+=glyphLocation;
|
|
|
|
int16_t numberOfContours=decode_int16(self);
|
|
|
|
if(numberOfContours>=0){
|
|
uint16_t endPtsOfContours[numberOfContours];
|
|
int i;
|
|
|
|
for(i=0;i<numberOfContours;i++)
|
|
endPtsOfContours[i]=decode_uint16(self);
|
|
|
|
uint16_t instructionLength=decode_uint16(self);
|
|
uint8_t instructions[instructionLength];
|
|
|
|
for(i=0;i<instructionLength;i++)
|
|
instructions[i]=decode_uint8(self);
|
|
|
|
|
|
}
|
|
else if(numberOfContours==-1){
|
|
}
|
|
else {
|
|
NSLog(@"invalid numberOfContours=%d",numberOfContours);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
@end
|