From: Andreas Gal Date: Fri, 17 Jun 2011 23:07:09 +0000 (-0700) Subject: move cffStandardStrings into utils/ along with font_utils.js X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=735bfa5972546e49065e4ba2fc0334e98ad18830;p=pdf.js.git move cffStandardStrings into utils/ along with font_utils.js --- diff --git a/cffStandardStrings.js b/cffStandardStrings.js deleted file mode 100644 index 8977cd8..0000000 --- a/cffStandardStrings.js +++ /dev/null @@ -1,689 +0,0 @@ -var CFFStrings = [ - ".notdef", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "onesuperior", - "logicalnot", - "mu", - "trademark", - "Eth", - "onehalf", - "plusminus", - "Thorn", - "onequarter", - "divide", - "brokenbar", - "degree", - "thorn", - "threequarters", - "twosuperior", - "registered", - "minus", - "eth", - "multiply", - "threesuperior", - "copyright", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "Zcaron", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "ccedilla", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "otilde", - "scaron", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "zcaron", - "exclamsmall", - "Hungarumlautsmall", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "266 ff", - "onedotenleader", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - "isuperior", - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - "rsuperior", - "ssuperior", - "tsuperior", - "ff", - "ffi", - "ffl", - "parenleftinferior", - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - "Dotaccentsmall", - "Macronsmall", - "figuredash", - "hypheninferior", - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - "zerosuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall", - "001.000", - "001.001", - "001.002", - "001.003", - "Black", - "Bold", - "Book", - "Light", - "Medium", - "Regular", - "Roman", - "Semibold" -]; - -var CFFEncodingMap = { - "0": "-reserved-", - "1": "hstem", - "2": "-reserved-", - "3": "vstem", - "4": "vmoveto", - "5": "rlineto", - "6": "hlineto", - "7": "vlineto", - "8": "rrcurveto", - "9": "-reserved-", - "10": "callsubr", - "11": "return", - "12": { - "3": "and", - "4": "or", - "5": "not", - "9": "abs", - "10": "add", - "11": "div", - "12": "sub", - "14": "neg", - "15": "eq", - "18": "drop", - "20": "put", - "21": "get", - "22": "ifelse", - "23": "random", - "24": "mul", - "26": "sqrt", - "27": "dup", - "28": "exch", - "29": "index", - "30": "roll", - "34": "hflex", - "35": "flex", - "36": "hflex1", - "37": "flex1" - }, - "13": "-reserved-", - "14": "endchar", - "15": "-reserved-", - "16": "-reserved-", - "17": "-reserved-", - "18": "hstemhm", - "19": "hintmask", - "20": "cntrmask", - "21": "rmoveto", - "22": "hmoveto", - "23": "vstemhm", - "24": "rcurveline", - "25": "rlivecurve", - "26": "vvcurveto", - "27": "hhcurveto", - "29": "callgsubr", - "30": "vhcurveto", - "31": "hvcurveto" -}; - -var CFFDictDataMap = { - "0": { - name: "version", - operand: "SID" - }, - "1": { - name: "Notice", - operand: "SID" - }, - "2": { - name: "FullName", - operand: "SID" - }, - "3": { - name: "FamilyName", - operand: "SID" - }, - "4": { - name: "Weight", - operand: "SID" - }, - "5": { - name: "FontBBox", - operand: [0, 0, 0, 0] - }, - "6": { - name: "BlueValues" - }, - "7": { - name: "OtherBlues" - }, - "8": { - name: "FamilyBlues" - }, - "9": { - name: "FamilyOtherBlues" - }, - "10": { - name: "StdHW" - }, - "11": { - name: "StdVW" - }, - "12": { - "0": { - name: "Copyright", - operand: "SID" - }, - "1": { - name: "IsFixedPitch", - operand: false - }, - "2": { - name: "ItalicAngle", - operand: 0 - }, - "3": { - name: "UnderlinePosition", - operand: -100 - }, - "4": { - name: "UnderlineThickness", - operand: 50 - }, - "5": { - name: "PaintType", - operand: 0 - }, - "6": { - name: "CharstringType", - operand: 2 - }, - "7": { - name: "FontMatrix", - operand: [0.001, 0, 0, 0.001, 0 ,0] - }, - "8": { - name: "StrokeWidth", - operand: 0 - }, - "9": { - name: "BlueScale" - }, - "10": { - name: "BlueShift" - }, - "11": { - name: "BlueFuzz" - }, - "12": { - name: "StemSnapH" - }, - "13": { - name: "StemSnapV" - }, - "14": { - name: "ForceBold" - }, - "17": { - name: "LanguageGroup" - }, - "18": { - name: "ExpansionFactor" - }, - "9": { - name: "initialRandomSeed" - }, - "20": { - name: "SyntheticBase", - operand: null - }, - "21": { - name: "PostScript", - operand: "SID" - }, - "22": { - name: "BaseFontName", - operand: "SID" - }, - "23": { - name: "BaseFontBlend", - operand: "delta" - } - }, - "13": { - name: "UniqueID", - operand: null - }, - "14": { - name: "XUID", - operand: [] - }, - "15": { - name: "charset", - operand: 0 - }, - "16": { - name: "Encoding", - operand: 0 - }, - "17": { - name: "CharStrings", - operand: null - }, - "18": { - name: "Private", - operand: "number number" - }, - "19": { - name: "Subrs" - }, - "20": { - name: "defaultWidthX" - }, - "21": { - name: "nominalWidthX" - } -}; - -var CFFDictPrivateDataMap = { - "6": { - name: "BluesValues", - operand: "delta" - }, - "7": { - name: "OtherBlues", - operand: "delta" - }, - "8": { - name: "FamilyBlues", - operand: "delta" - }, - "9": { - name: "FamilyOtherBlues", - operand: "delta" - }, - "10": { - name: "StdHW", - operand: null - }, - "11": { - name: "StdVW", - operand: null - }, - "12": { - "9": { - name: "BlueScale", - operand: 0.039625 - }, - "10": { - name: "BlueShift", - operand: 7 - }, - "11": { - name: "BlueFuzz", - operand: 1 - }, - "12": { - name: "StemSnapH", - operand: "delta" - }, - "13": { - name: "StemSnapV", - operand: "delta" - }, - "14": { - name: "ForceBold", - operand: "boolean" - }, - "17": { - name: "LanguageGroup", - operand: 0 - }, - "18": { - name: "ExpansionFactor", - operand: 0.06 - }, - "19": { - name: "initialRandomSeed", - operand: 0 - } - }, - "19": { - name: "Subrs", - operand: null - }, - "20": { - name: "defaultWidthX", - operand: 0 - }, - "21": { - name: "nominalWidthX", - operand: 0 - } -}; - diff --git a/fonts.js b/fonts.js index b9ef5b3..be4007d 100644 --- a/fonts.js +++ b/fonts.js @@ -1076,6 +1076,64 @@ var Type1Parser = function() { } }; +const CFFStrings = [ + ".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand", + "quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period", + "slash","zero","one","two","three","four","five","six","seven","eight","nine", + "colon","semicolon","less","equal","greater","question","at","A","B","C","D","E", + "F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y", + "Z","bracketleft","backslash","bracketright","asciicircum","underscore", + "quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q", + "r","s","t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde", + "exclamdown","cent","sterling","fraction","yen","florin","section","currency", + "quotesingle","quotedblleft","guillemotleft","guilsinglleft","guilsinglright", + "fi","fl","endash","dagger","daggerdbl","periodcentered","paragraph","bullet", + "quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis", + "perthousand","questiondown","grave","acute","circumflex","tilde","macron", + "breve","dotaccent","dieresis","ring","cedilla","hungarumlaut","ogonek","caron", + "emdash","AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae","dotlessi", + "lslash","oslash","oe","germandbls","onesuperior","logicalnot","mu","trademark", + "Eth","onehalf","plusminus","Thorn","onequarter","divide","brokenbar","degree", + "thorn","threequarters","twosuperior","registered","minus","eth","multiply", + "threesuperior","copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring", + "Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave","Iacute", + "Icircumflex","Idieresis","Igrave","Ntilde","Oacute","Ocircumflex","Odieresis", + "Ograve","Otilde","Scaron","Uacute","Ucircumflex","Udieresis","Ugrave","Yacute", + "Ydieresis","Zcaron","aacute","acircumflex","adieresis","agrave","aring","atilde", + "ccedilla","eacute","ecircumflex","edieresis","egrave","iacute","icircumflex", + "idieresis","igrave","ntilde","oacute","ocircumflex","odieresis","ograve", + "otilde","scaron","uacute","ucircumflex","udieresis","ugrave","yacute", + "ydieresis","zcaron","exclamsmall","Hungarumlautsmall","dollaroldstyle", + "dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior", + "parenrightsuperior","266 ff","onedotenleader","zerooldstyle","oneoldstyle", + "twooldstyle","threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle", + "sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior", + "threequartersemdash","periodsuperior","questionsmall","asuperior","bsuperior", + "centsuperior","dsuperior","esuperior","isuperior","lsuperior","msuperior", + "nsuperior","osuperior","rsuperior","ssuperior","tsuperior","ff","ffi","ffl", + "parenleftinferior","parenrightinferior","Circumflexsmall","hyphensuperior", + "Gravesmall","Asmall","Bsmall","Csmall","Dsmall","Esmall","Fsmall","Gsmall", + "Hsmall","Ismall","Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall", + "Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall","Xsmall","Ysmall", + "Zsmall","colonmonetary","onefitted","rupiah","Tildesmall","exclamdownsmall", + "centoldstyle","Lslashsmall","Scaronsmall","Zcaronsmall","Dieresissmall", + "Brevesmall","Caronsmall","Dotaccentsmall","Macronsmall","figuredash", + "hypheninferior","Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall", + "oneeighth","threeeighths","fiveeighths","seveneighths","onethird","twothirds", + "zerosuperior","foursuperior","fivesuperior","sixsuperior","sevensuperior", + "eightsuperior","ninesuperior","zeroinferior","oneinferior","twoinferior", + "threeinferior","fourinferior","fiveinferior","sixinferior","seveninferior", + "eightinferior","nineinferior","centinferior","dollarinferior","periodinferior", + "commainferior","Agravesmall","Aacutesmall","Acircumflexsmall","Atildesmall", + "Adieresissmall","Aringsmall","AEsmall","Ccedillasmall","Egravesmall", + "Eacutesmall","Ecircumflexsmall","Edieresissmall","Igravesmall","Iacutesmall", + "Icircumflexsmall","Idieresissmall","Ethsmall","Ntildesmall","Ogravesmall", + "Oacutesmall","Ocircumflexsmall","Otildesmall","Odieresissmall","OEsmall", + "Oslashsmall","Ugravesmall","Uacutesmall","Ucircumflexsmall","Udieresissmall", + "Yacutesmall","Thornsmall","Ydieresissmall","001.000","001.001","001.002", + "001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold" +]; + /** * Take a Type1 file as input and wrap it into a Compact Font Format (CFF) * wrapping Type2 charstrings. diff --git a/fonts_utils.js b/fonts_utils.js deleted file mode 100644 index 086648f..0000000 --- a/fonts_utils.js +++ /dev/null @@ -1,391 +0,0 @@ -/** - * The Type2 reader code below is only used for debugging purpose since Type2 - * is only a CharString format and is never used directly as a Font file. - * - * So the code here is useful for dumping the data content of a .cff file in - * order to investigate the similarity between a Type1 CharString and a Type2 - * CharString or to understand the structure of the CFF format. - */ - - -/** - * Build a charset by assigning the glyph name and the human readable form - * of the glyph data. - */ -function readCharset(aStream, aCharstrings) { - var charset = {}; - - var format = aStream.getByte(); - if (format == 0) { - charset[".notdef"] = readCharstringEncoding(aCharstrings[0]); - - var count = aCharstrings.length - 1; - for (var i = 1; i < count + 1; i++) { - var sid = aStream.getByte() << 8 | aStream.getByte(); - charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[i]); - //log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]); - } - } else if (format == 1) { - error("Charset Range are not supported"); - } else { - error("Invalid charset format"); - } - - return charset; -}; - -/** - * Take a Type2 binary charstring as input and transform it to a human - * readable representation as specified by the 'The Type 2 Charstring Format', - * chapter 3.1. - */ -function readCharstringEncoding(aString) { - var charstringTokens = []; - - var count = aString.length; - for (var i = 0; i < count; ) { - var value = aString[i++]; - var token = null; - - if (value < 0) { - continue; - } else if (value <= 11) { - token = CFFEncodingMap[value]; - } else if (value == 12) { - token = CFFEncodingMap[value][aString[i++]]; - } else if (value <= 18) { - token = CFFEncodingMap[value]; - } else if (value <= 20) { - var mask = aString[i++]; - token = CFFEncodingMap[value]; - } else if (value <= 27) { - token = CFFEncodingMap[value]; - } else if (value == 28) { - token = aString[i++] << 8 | aString[i++]; - } else if (value <= 31) { - token = CFFEncodingMap[value]; - } else if (value < 247) { - token = parseInt(value) - 139; - } else if (value < 251) { - token = ((value - 247) * 256) + aString[i++] + 108; - } else if (value < 255) { - token = -((value - 251) * 256) - aString[i++] - 108; - } else {// value == 255 - token = aString[i++] << 24 | aString[i++] << 16 | - aString[i++] << 8 | aString[i]; - } - - charstringTokens.push(token); - } - - return charstringTokens; -}; - - -/** - * Take a binary DICT Data as input and transform it into a human readable - * form as specified by 'The Compact Font Format Specification', chapter 5. - */ -function readFontDictData(aString, aMap) { - var fontDictDataTokens = []; - - var count = aString.length; - for (var i = 0; i < count; i) { - var value = aString[i++]; - var token = null; - - if (value == 12) { - token = aMap[value][aString[i++]]; - } else if (value == 28) { - token = aString[i++] << 8 | aString[i++]; - } else if (value == 29) { - token = aString[i++] << 24 | - aString[i++] << 16 | - aString[i++] << 8 | - aString[i++]; - } else if (value == 30) { - token = ""; - var parsed = false; - while (!parsed) { - var byte = aString[i++]; - - var nibbles = [parseInt(byte / 16), parseInt(byte % 16)]; - for (var j = 0; j < nibbles.length; j++) { - var nibble = nibbles[j]; - switch (nibble) { - case 0xA: - token += "."; - break; - case 0xB: - token += "E"; - break; - case 0xC: - token += "E-"; - break; - case 0xD: - break; - case 0xE: - token += "-"; - break; - case 0xF: - parsed = true; - break; - default: - token += nibble; - break; - } - } - }; - token = parseFloat(token); - } else if (value <= 31) { - token = aMap[value]; - } else if (value <= 246) { - token = parseInt(value) - 139; - } else if (value <= 250) { - token = ((value - 247) * 256) + aString[i++] + 108; - } else if (value <= 254) { - token = -((value - 251) * 256) - aString[i++] - 108; - } else if (value == 255) { - error("255 is not a valid DICT command"); - } - - fontDictDataTokens.push(token); - } - - return fontDictDataTokens; -}; - - -/** - * Take a stream as input and return an array of objects. - * In CFF an INDEX is a structure with the following format: - * { - * count: 2 bytes (Number of objects stored in INDEX), - * offsize: 1 byte (Offset array element size), - * offset: [count + 1] bytes (Offsets array), - * data: - (Objects data) - * } - * - * More explanation are given in the 'CFF Font Format Specification', - * chapter 5. - */ -function readFontIndexData(aStream, aIsByte) { - var count = aStream.getByte() << 8 | aStream.getByte(); - var offsize = aStream.getByte(); - - function getNextOffset() { - switch (offsize) { - case 0: - return 0; - case 1: - return aStream.getByte(); - case 2: - return aStream.getByte() << 8 | aStream.getByte(); - case 3: - return aStream.getByte() << 16 | aStream.getByte() << 8 | - aStream.getByte(); - case 4: - return aStream.getByte() << 24 | aStream.getByte() << 16 | - aStream.getByte() << 8 | aStream.getByte(); - } - }; - - var offsets = []; - for (var i = 0; i < count + 1; i++) - offsets.push(getNextOffset()); - - log("Found " + count + " objects at offsets :" + offsets + " (offsize: " + offsize + ")"); - - // Now extract the objects - var relativeOffset = aStream.pos; - var objects = []; - for (var i = 0; i < count; i++) { - var offset = offsets[i]; - aStream.pos = relativeOffset + offset - 1; - - var data = []; - var length = offsets[i + 1] - 1; - for (var j = offset - 1; j < length; j++) - data.push(aIsByte ? aStream.getByte() : aStream.getChar()); - objects.push(data); - } - - return objects; -}; - -var Type2Parser = function(aFilePath) { - var font = new Dict(); - - var xhr = new XMLHttpRequest(); - xhr.open("GET", aFilePath, false); - xhr.mozResponseType = xhr.responseType = "arraybuffer"; - xhr.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; - xhr.send(null); - this.data = new Stream(xhr.mozResponseArrayBuffer || xhr.mozResponse || - xhr.responseArrayBuffer || xhr.response); - - // Turn on this flag for additional debugging logs - var debug = false; - - function dump(aStr) { - if (debug) - log(aStr); - }; - - function parseAsToken(aString, aMap) { - var decoded = readFontDictData(aString, aMap); - - var stack = []; - var count = decoded.length; - for (var i = 0; i < count; i++) { - var token = decoded[i]; - if (IsNum(token)) { - stack.push(token); - } else { - switch (token.operand) { - case "SID": - font.set(token.name, CFFStrings[stack.pop()]); - break; - case "number number": - font.set(token.name, { - offset: stack.pop(), - size: stack.pop() - }); - break; - case "boolean": - font.set(token.name, stack.pop()); - break; - case "delta": - font.set(token.name, stack.pop()); - break; - default: - if (token.operand && token.operand.length) { - var array = []; - for (var j = 0; j < token.operand.length; j++) - array.push(stack.pop()); - font.set(token.name, array); - } else { - font.set(token.name, stack.pop()); - } - break; - } - } - } - }; - - this.parse = function(aStream) { - font.set("major", aStream.getByte()); - font.set("minor", aStream.getByte()); - font.set("hdrSize", aStream.getByte()); - font.set("offsize", aStream.getByte()); - - // Move the cursor after the header - aStream.skip(font.get("hdrSize") - aStream.pos); - - // Read the NAME Index - dump("Reading Index: Names"); - font.set("Names", readFontIndexData(aStream)); - log("Names: " + font.get("Names")); - - // Read the Top Dict Index - dump("Reading Index: TopDict"); - var topDict = readFontIndexData(aStream, true); - log("TopDict: " + topDict); - - // Read the String Index - dump("Reading Index: Strings"); - var strings = readFontIndexData(aStream); - log("strings: " + strings); - - // Fill up the Strings dictionary with the new unique strings - for (var i = 0; i < strings.length; i++) - CFFStrings.push(strings[i].join("")); - - // Parse the TopDict operator - var objects = []; - var count = topDict.length; - for (var i = 0; i < count; i++) - parseAsToken(topDict[i], CFFDictDataMap); - - // Read the Global Subr Index that comes just after the Strings Index - // (cf. "The Compact Font Format Specification" Chapter 16) - dump("Reading Global Subr Index"); - var subrs = readFontIndexData(aStream, true); - dump(subrs); - - // Reading Private Dict - var private = font.get("Private"); - log("Reading Private Dict (offset: " + private.offset + " size: " + private.size + ")"); - aStream.pos = private.offset; - - var privateDict = []; - for (var i = 0; i < private.size; i++) - privateDict.push(aStream.getByte()); - dump("private:" + privateDict); - parseAsToken(privateDict, CFFDictPrivateDataMap); - - for (var p in font.map) - dump(p + "::" + font.get(p)); - - // Read CharStrings Index - var charStringsOffset = font.get("CharStrings"); - dump("Read CharStrings Index (offset: " + charStringsOffset + ")"); - aStream.pos = charStringsOffset; - var charStrings = readFontIndexData(aStream, true); - - // Read Charset - dump("Read Charset for " + charStrings.length + " glyphs"); - var charsetEntry = font.get("charset"); - if (charsetEntry == 0) { - error("Need to support CFFISOAdobeCharset"); - } else if (charsetEntry == 1) { - error("Need to support CFFExpert"); - } else if (charsetEntry == 2) { - error("Need to support CFFExpertSubsetCharset"); - } else { - aStream.pos = charsetEntry; - var charset = readCharset(aStream, charStrings); - } - } -}; - -/* - * To try the Type2 decoder on a local file in the current directory: - * - * var cff = new Type2Parser("file.cff"); - * cff.parse(this.data); - * - * To try the Type2 decoder on a custom built CFF array: - * - * var file = new Uint8Array(cffFileArray, 0, cffFileSize); - * var parser = new Type2Parser(); - * parser.parse(new Stream(file)); - * - */ - - -/** - * Write to a file to the disk (works only on Firefox in privilege mode) - * but this is useful for dumping a font file to the disk and check with - * fontforge or the ots program what's wrong with the file. - * - * writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff"); - */ -function writeToFile(aBytes, aFilePath) { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var Cc = Components.classes, - Ci = Components.interfaces; - var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile); - file.initWithPath(aFilePath); - - var stream = Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(Ci.nsIFileOutputStream); - stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0); - - var bos = Cc["@mozilla.org/binaryoutputstream;1"] - .createInstance(Ci.nsIBinaryOutputStream); - bos.setOutputStream(stream); - bos.writeByteArray(aBytes, aBytes.length); - stream.close(); -}; - diff --git a/test.html b/test.html index dfe422e..600ff3c 100644 --- a/test.html +++ b/test.html @@ -6,7 +6,6 @@ - diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js new file mode 100644 index 0000000..8977cd8 --- /dev/null +++ b/utils/cffStandardStrings.js @@ -0,0 +1,689 @@ +var CFFStrings = [ + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "266 ff", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold" +]; + +var CFFEncodingMap = { + "0": "-reserved-", + "1": "hstem", + "2": "-reserved-", + "3": "vstem", + "4": "vmoveto", + "5": "rlineto", + "6": "hlineto", + "7": "vlineto", + "8": "rrcurveto", + "9": "-reserved-", + "10": "callsubr", + "11": "return", + "12": { + "3": "and", + "4": "or", + "5": "not", + "9": "abs", + "10": "add", + "11": "div", + "12": "sub", + "14": "neg", + "15": "eq", + "18": "drop", + "20": "put", + "21": "get", + "22": "ifelse", + "23": "random", + "24": "mul", + "26": "sqrt", + "27": "dup", + "28": "exch", + "29": "index", + "30": "roll", + "34": "hflex", + "35": "flex", + "36": "hflex1", + "37": "flex1" + }, + "13": "-reserved-", + "14": "endchar", + "15": "-reserved-", + "16": "-reserved-", + "17": "-reserved-", + "18": "hstemhm", + "19": "hintmask", + "20": "cntrmask", + "21": "rmoveto", + "22": "hmoveto", + "23": "vstemhm", + "24": "rcurveline", + "25": "rlivecurve", + "26": "vvcurveto", + "27": "hhcurveto", + "29": "callgsubr", + "30": "vhcurveto", + "31": "hvcurveto" +}; + +var CFFDictDataMap = { + "0": { + name: "version", + operand: "SID" + }, + "1": { + name: "Notice", + operand: "SID" + }, + "2": { + name: "FullName", + operand: "SID" + }, + "3": { + name: "FamilyName", + operand: "SID" + }, + "4": { + name: "Weight", + operand: "SID" + }, + "5": { + name: "FontBBox", + operand: [0, 0, 0, 0] + }, + "6": { + name: "BlueValues" + }, + "7": { + name: "OtherBlues" + }, + "8": { + name: "FamilyBlues" + }, + "9": { + name: "FamilyOtherBlues" + }, + "10": { + name: "StdHW" + }, + "11": { + name: "StdVW" + }, + "12": { + "0": { + name: "Copyright", + operand: "SID" + }, + "1": { + name: "IsFixedPitch", + operand: false + }, + "2": { + name: "ItalicAngle", + operand: 0 + }, + "3": { + name: "UnderlinePosition", + operand: -100 + }, + "4": { + name: "UnderlineThickness", + operand: 50 + }, + "5": { + name: "PaintType", + operand: 0 + }, + "6": { + name: "CharstringType", + operand: 2 + }, + "7": { + name: "FontMatrix", + operand: [0.001, 0, 0, 0.001, 0 ,0] + }, + "8": { + name: "StrokeWidth", + operand: 0 + }, + "9": { + name: "BlueScale" + }, + "10": { + name: "BlueShift" + }, + "11": { + name: "BlueFuzz" + }, + "12": { + name: "StemSnapH" + }, + "13": { + name: "StemSnapV" + }, + "14": { + name: "ForceBold" + }, + "17": { + name: "LanguageGroup" + }, + "18": { + name: "ExpansionFactor" + }, + "9": { + name: "initialRandomSeed" + }, + "20": { + name: "SyntheticBase", + operand: null + }, + "21": { + name: "PostScript", + operand: "SID" + }, + "22": { + name: "BaseFontName", + operand: "SID" + }, + "23": { + name: "BaseFontBlend", + operand: "delta" + } + }, + "13": { + name: "UniqueID", + operand: null + }, + "14": { + name: "XUID", + operand: [] + }, + "15": { + name: "charset", + operand: 0 + }, + "16": { + name: "Encoding", + operand: 0 + }, + "17": { + name: "CharStrings", + operand: null + }, + "18": { + name: "Private", + operand: "number number" + }, + "19": { + name: "Subrs" + }, + "20": { + name: "defaultWidthX" + }, + "21": { + name: "nominalWidthX" + } +}; + +var CFFDictPrivateDataMap = { + "6": { + name: "BluesValues", + operand: "delta" + }, + "7": { + name: "OtherBlues", + operand: "delta" + }, + "8": { + name: "FamilyBlues", + operand: "delta" + }, + "9": { + name: "FamilyOtherBlues", + operand: "delta" + }, + "10": { + name: "StdHW", + operand: null + }, + "11": { + name: "StdVW", + operand: null + }, + "12": { + "9": { + name: "BlueScale", + operand: 0.039625 + }, + "10": { + name: "BlueShift", + operand: 7 + }, + "11": { + name: "BlueFuzz", + operand: 1 + }, + "12": { + name: "StemSnapH", + operand: "delta" + }, + "13": { + name: "StemSnapV", + operand: "delta" + }, + "14": { + name: "ForceBold", + operand: "boolean" + }, + "17": { + name: "LanguageGroup", + operand: 0 + }, + "18": { + name: "ExpansionFactor", + operand: 0.06 + }, + "19": { + name: "initialRandomSeed", + operand: 0 + } + }, + "19": { + name: "Subrs", + operand: null + }, + "20": { + name: "defaultWidthX", + operand: 0 + }, + "21": { + name: "nominalWidthX", + operand: 0 + } +}; + diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js new file mode 100644 index 0000000..086648f --- /dev/null +++ b/utils/fonts_utils.js @@ -0,0 +1,391 @@ +/** + * The Type2 reader code below is only used for debugging purpose since Type2 + * is only a CharString format and is never used directly as a Font file. + * + * So the code here is useful for dumping the data content of a .cff file in + * order to investigate the similarity between a Type1 CharString and a Type2 + * CharString or to understand the structure of the CFF format. + */ + + +/** + * Build a charset by assigning the glyph name and the human readable form + * of the glyph data. + */ +function readCharset(aStream, aCharstrings) { + var charset = {}; + + var format = aStream.getByte(); + if (format == 0) { + charset[".notdef"] = readCharstringEncoding(aCharstrings[0]); + + var count = aCharstrings.length - 1; + for (var i = 1; i < count + 1; i++) { + var sid = aStream.getByte() << 8 | aStream.getByte(); + charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[i]); + //log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]); + } + } else if (format == 1) { + error("Charset Range are not supported"); + } else { + error("Invalid charset format"); + } + + return charset; +}; + +/** + * Take a Type2 binary charstring as input and transform it to a human + * readable representation as specified by the 'The Type 2 Charstring Format', + * chapter 3.1. + */ +function readCharstringEncoding(aString) { + var charstringTokens = []; + + var count = aString.length; + for (var i = 0; i < count; ) { + var value = aString[i++]; + var token = null; + + if (value < 0) { + continue; + } else if (value <= 11) { + token = CFFEncodingMap[value]; + } else if (value == 12) { + token = CFFEncodingMap[value][aString[i++]]; + } else if (value <= 18) { + token = CFFEncodingMap[value]; + } else if (value <= 20) { + var mask = aString[i++]; + token = CFFEncodingMap[value]; + } else if (value <= 27) { + token = CFFEncodingMap[value]; + } else if (value == 28) { + token = aString[i++] << 8 | aString[i++]; + } else if (value <= 31) { + token = CFFEncodingMap[value]; + } else if (value < 247) { + token = parseInt(value) - 139; + } else if (value < 251) { + token = ((value - 247) * 256) + aString[i++] + 108; + } else if (value < 255) { + token = -((value - 251) * 256) - aString[i++] - 108; + } else {// value == 255 + token = aString[i++] << 24 | aString[i++] << 16 | + aString[i++] << 8 | aString[i]; + } + + charstringTokens.push(token); + } + + return charstringTokens; +}; + + +/** + * Take a binary DICT Data as input and transform it into a human readable + * form as specified by 'The Compact Font Format Specification', chapter 5. + */ +function readFontDictData(aString, aMap) { + var fontDictDataTokens = []; + + var count = aString.length; + for (var i = 0; i < count; i) { + var value = aString[i++]; + var token = null; + + if (value == 12) { + token = aMap[value][aString[i++]]; + } else if (value == 28) { + token = aString[i++] << 8 | aString[i++]; + } else if (value == 29) { + token = aString[i++] << 24 | + aString[i++] << 16 | + aString[i++] << 8 | + aString[i++]; + } else if (value == 30) { + token = ""; + var parsed = false; + while (!parsed) { + var byte = aString[i++]; + + var nibbles = [parseInt(byte / 16), parseInt(byte % 16)]; + for (var j = 0; j < nibbles.length; j++) { + var nibble = nibbles[j]; + switch (nibble) { + case 0xA: + token += "."; + break; + case 0xB: + token += "E"; + break; + case 0xC: + token += "E-"; + break; + case 0xD: + break; + case 0xE: + token += "-"; + break; + case 0xF: + parsed = true; + break; + default: + token += nibble; + break; + } + } + }; + token = parseFloat(token); + } else if (value <= 31) { + token = aMap[value]; + } else if (value <= 246) { + token = parseInt(value) - 139; + } else if (value <= 250) { + token = ((value - 247) * 256) + aString[i++] + 108; + } else if (value <= 254) { + token = -((value - 251) * 256) - aString[i++] - 108; + } else if (value == 255) { + error("255 is not a valid DICT command"); + } + + fontDictDataTokens.push(token); + } + + return fontDictDataTokens; +}; + + +/** + * Take a stream as input and return an array of objects. + * In CFF an INDEX is a structure with the following format: + * { + * count: 2 bytes (Number of objects stored in INDEX), + * offsize: 1 byte (Offset array element size), + * offset: [count + 1] bytes (Offsets array), + * data: - (Objects data) + * } + * + * More explanation are given in the 'CFF Font Format Specification', + * chapter 5. + */ +function readFontIndexData(aStream, aIsByte) { + var count = aStream.getByte() << 8 | aStream.getByte(); + var offsize = aStream.getByte(); + + function getNextOffset() { + switch (offsize) { + case 0: + return 0; + case 1: + return aStream.getByte(); + case 2: + return aStream.getByte() << 8 | aStream.getByte(); + case 3: + return aStream.getByte() << 16 | aStream.getByte() << 8 | + aStream.getByte(); + case 4: + return aStream.getByte() << 24 | aStream.getByte() << 16 | + aStream.getByte() << 8 | aStream.getByte(); + } + }; + + var offsets = []; + for (var i = 0; i < count + 1; i++) + offsets.push(getNextOffset()); + + log("Found " + count + " objects at offsets :" + offsets + " (offsize: " + offsize + ")"); + + // Now extract the objects + var relativeOffset = aStream.pos; + var objects = []; + for (var i = 0; i < count; i++) { + var offset = offsets[i]; + aStream.pos = relativeOffset + offset - 1; + + var data = []; + var length = offsets[i + 1] - 1; + for (var j = offset - 1; j < length; j++) + data.push(aIsByte ? aStream.getByte() : aStream.getChar()); + objects.push(data); + } + + return objects; +}; + +var Type2Parser = function(aFilePath) { + var font = new Dict(); + + var xhr = new XMLHttpRequest(); + xhr.open("GET", aFilePath, false); + xhr.mozResponseType = xhr.responseType = "arraybuffer"; + xhr.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; + xhr.send(null); + this.data = new Stream(xhr.mozResponseArrayBuffer || xhr.mozResponse || + xhr.responseArrayBuffer || xhr.response); + + // Turn on this flag for additional debugging logs + var debug = false; + + function dump(aStr) { + if (debug) + log(aStr); + }; + + function parseAsToken(aString, aMap) { + var decoded = readFontDictData(aString, aMap); + + var stack = []; + var count = decoded.length; + for (var i = 0; i < count; i++) { + var token = decoded[i]; + if (IsNum(token)) { + stack.push(token); + } else { + switch (token.operand) { + case "SID": + font.set(token.name, CFFStrings[stack.pop()]); + break; + case "number number": + font.set(token.name, { + offset: stack.pop(), + size: stack.pop() + }); + break; + case "boolean": + font.set(token.name, stack.pop()); + break; + case "delta": + font.set(token.name, stack.pop()); + break; + default: + if (token.operand && token.operand.length) { + var array = []; + for (var j = 0; j < token.operand.length; j++) + array.push(stack.pop()); + font.set(token.name, array); + } else { + font.set(token.name, stack.pop()); + } + break; + } + } + } + }; + + this.parse = function(aStream) { + font.set("major", aStream.getByte()); + font.set("minor", aStream.getByte()); + font.set("hdrSize", aStream.getByte()); + font.set("offsize", aStream.getByte()); + + // Move the cursor after the header + aStream.skip(font.get("hdrSize") - aStream.pos); + + // Read the NAME Index + dump("Reading Index: Names"); + font.set("Names", readFontIndexData(aStream)); + log("Names: " + font.get("Names")); + + // Read the Top Dict Index + dump("Reading Index: TopDict"); + var topDict = readFontIndexData(aStream, true); + log("TopDict: " + topDict); + + // Read the String Index + dump("Reading Index: Strings"); + var strings = readFontIndexData(aStream); + log("strings: " + strings); + + // Fill up the Strings dictionary with the new unique strings + for (var i = 0; i < strings.length; i++) + CFFStrings.push(strings[i].join("")); + + // Parse the TopDict operator + var objects = []; + var count = topDict.length; + for (var i = 0; i < count; i++) + parseAsToken(topDict[i], CFFDictDataMap); + + // Read the Global Subr Index that comes just after the Strings Index + // (cf. "The Compact Font Format Specification" Chapter 16) + dump("Reading Global Subr Index"); + var subrs = readFontIndexData(aStream, true); + dump(subrs); + + // Reading Private Dict + var private = font.get("Private"); + log("Reading Private Dict (offset: " + private.offset + " size: " + private.size + ")"); + aStream.pos = private.offset; + + var privateDict = []; + for (var i = 0; i < private.size; i++) + privateDict.push(aStream.getByte()); + dump("private:" + privateDict); + parseAsToken(privateDict, CFFDictPrivateDataMap); + + for (var p in font.map) + dump(p + "::" + font.get(p)); + + // Read CharStrings Index + var charStringsOffset = font.get("CharStrings"); + dump("Read CharStrings Index (offset: " + charStringsOffset + ")"); + aStream.pos = charStringsOffset; + var charStrings = readFontIndexData(aStream, true); + + // Read Charset + dump("Read Charset for " + charStrings.length + " glyphs"); + var charsetEntry = font.get("charset"); + if (charsetEntry == 0) { + error("Need to support CFFISOAdobeCharset"); + } else if (charsetEntry == 1) { + error("Need to support CFFExpert"); + } else if (charsetEntry == 2) { + error("Need to support CFFExpertSubsetCharset"); + } else { + aStream.pos = charsetEntry; + var charset = readCharset(aStream, charStrings); + } + } +}; + +/* + * To try the Type2 decoder on a local file in the current directory: + * + * var cff = new Type2Parser("file.cff"); + * cff.parse(this.data); + * + * To try the Type2 decoder on a custom built CFF array: + * + * var file = new Uint8Array(cffFileArray, 0, cffFileSize); + * var parser = new Type2Parser(); + * parser.parse(new Stream(file)); + * + */ + + +/** + * Write to a file to the disk (works only on Firefox in privilege mode) + * but this is useful for dumping a font file to the disk and check with + * fontforge or the ots program what's wrong with the file. + * + * writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff"); + */ +function writeToFile(aBytes, aFilePath) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var Cc = Components.classes, + Ci = Components.interfaces; + var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile); + file.initWithPath(aFilePath); + + var stream = Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream); + stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0); + + var bos = Cc["@mozilla.org/binaryoutputstream;1"] + .createInstance(Ci.nsIBinaryOutputStream); + bos.setOutputStream(stream); + bos.writeByteArray(aBytes, aBytes.length); + stream.close(); +}; +