]> git.parisson.com Git - pdf.js.git/commitdiff
move cffStandardStrings into utils/ along with font_utils.js
authorAndreas Gal <andreas.gal@gmail.com>
Fri, 17 Jun 2011 23:07:09 +0000 (16:07 -0700)
committerAndreas Gal <andreas.gal@gmail.com>
Fri, 17 Jun 2011 23:07:09 +0000 (16:07 -0700)
cffStandardStrings.js [deleted file]
fonts.js
fonts_utils.js [deleted file]
test.html
utils/cffStandardStrings.js [new file with mode: 0644]
utils/fonts_utils.js [new file with mode: 0644]

diff --git a/cffStandardStrings.js b/cffStandardStrings.js
deleted file mode 100644 (file)
index 8977cd8..0000000
+++ /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
-  }
-};
-
index b9ef5b330974979a76d9a3f0416b12e6ab34a2c9..be4007d2482141a26c24208167458db9cf7d08a8 100644 (file)
--- 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 (file)
index 086648f..0000000
+++ /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();
-};
-
index dfe422e64ebc71e02e32fa1ebfbc35fd392ed60d..600ff3c57153ae84c34349d42c585c4df7b848ef 100644 (file)
--- a/test.html
+++ b/test.html
@@ -6,7 +6,6 @@
         <script type="text/javascript" src="test.js"></script>
         <script type="text/javascript" src="pdf.js"></script>
         <script type="text/javascript" src="fonts.js"></script>
-        <script type="text/javascript" src="cffStandardStrings.js"></script>
         <script type="text/javascript" src="glyphlist.js"></script>
   </head>
 
diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js
new file mode 100644 (file)
index 0000000..8977cd8
--- /dev/null
@@ -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 (file)
index 0000000..086648f
--- /dev/null
@@ -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();
+};
+