From 0a7531cb33c465e53532be4af039af24e5a37106 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 29 Jun 2011 21:29:33 +0200 Subject: [PATCH 01/15] Calculate correct checksum for the field header --- fonts.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fonts.js b/fonts.js index e25b2ae2d..e4dfd3541 100644 --- a/fonts.js +++ b/fonts.js @@ -247,12 +247,9 @@ var Font = (function () { var length = data.length; // checksum - var checksum = tag.charCodeAt(0) + - tag.charCodeAt(1) + - tag.charCodeAt(2) + - tag.charCodeAt(3) + - offset + - length; + var checksum = 0; + for (var i = 0; i < length; i+=4) + checksum += FontsUtils.bytesToInteger([data[i], data[i+1], data[i+2], data[i+3]]); var tableEntry = tag + string32(checksum) + string32(offset) + string32(length); tableEntry = stringToArray(tableEntry); From a7c3ebcac372c87e082c77e634640502a9bfd600 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 29 Jun 2011 21:30:25 +0200 Subject: [PATCH 02/15] Do not include the padding size in the length declared in the table header --- fonts.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fonts.js b/fonts.js index e4dfd3541..191652c1d 100644 --- a/fonts.js +++ b/fonts.js @@ -236,6 +236,9 @@ var Font = (function () { // offset var offset = offsets.virtualOffset; + // length + var length = data.length; + // Per spec tables must be 4-bytes align so add padding as needed while (data.length & 3) data.push(0x00); @@ -243,9 +246,6 @@ var Font = (function () { while (offsets.virtualOffset & 3) offsets.virtualOffset++; - // length - var length = data.length; - // checksum var checksum = 0; for (var i = 0; i < length; i+=4) From 4c6c20fc29c5ee080c4219ea8cb0093fd47cd7f7 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 29 Jun 2011 21:53:22 +0200 Subject: [PATCH 03/15] Fix a few headers fields --- fonts.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/fonts.js b/fonts.js index 191652c1d..d09e2ad83 100644 --- a/fonts.js +++ b/fonts.js @@ -360,21 +360,21 @@ var Font = (function () { "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 64-95) "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 96-127) "\x2A\x32\x31\x2A" + // achVendID - "\x00\x20" + // fsSelection + "\x00\x00" + // fsSelection "\x00\x2D" + // usFirstCharIndex "\x00\x7A" + // usLastCharIndex - "\x00\x03" + // sTypoAscender - "\x00\x20" + // sTypeDescender - "\x00\x38" + // sTypoLineGap + "\x00\x20" + // sTypoAscender + "\x00\x00" + // sTypeDescender + "\x00\x00" + // sTypoLineGap string16(properties.ascent) + // usWinAscent string16(properties.descent) + // usWinDescent - "\x00\xCE\x00\x00" + // ulCodePageRange1 (Bits 0-31) - "\x00\x01\x00\x00" + // ulCodePageRange2 (Bits 32-63) + "\x00\x00\x00\x00" + // ulCodePageRange1 (Bits 0-31) + "\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight string16(properties.capHeight) + // sCapHeight "\x00\x01" + // usDefaultChar "\x00\xCD" + // usBreakChar - "\x00\x02"; // usMaxContext + "\x00\x00"; // usMaxContext }; function createPostTable(properties) { @@ -700,14 +700,14 @@ var Font = (function () { "\x5F\x0F\x3C\xF5" + // magicNumber "\x00\x00" + // Flags "\x03\xE8" + // unitsPerEM (defaulting to 1000) - "\x00\x00\x00\x00\x00\x00\x00\x00" + // creation date - "\x00\x00\x00\x00\x00\x00\x00\x00" + // modifification date + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // creation date + "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // modifification date "\x00\x00" + // xMin "\x00\x00" + // yMin "\x00\x00" + // xMax "\x00\x00" + // yMax "\x00\x00" + // macStyle - "\x00\x00" + // lowestRecPPEM + "\x00\x11" + // lowestRecPPEM "\x00\x00" + // fontDirectionHint "\x00\x00" + // indexToLocFormat "\x00\x00" // glyphDataFormat @@ -717,8 +717,8 @@ var Font = (function () { /** HHEA */ hhea = stringToArray( "\x00\x01\x00\x00" + // Version number - "\x00\x00" + // Typographic Ascent - "\x00\x00" + // Typographic Descent + string16(properties.ascent) + // Typographic Ascent + string16(properties.descent) + // Typographic Descent "\x00\x00" + // Line Gap "\xFF\xFF" + // advanceWidthMax "\x00\x00" + // minLeftSidebearing @@ -797,7 +797,7 @@ var Font = (function () { // seems it's loaded once Gecko notices it's used. Therefore, // add a div on the page using the loaded font. var div = document.createElement("div"); - var style = 'font-family:"' + name + + var style = 'font-family:"' + name + '";position: absolute;top:-99999;left:-99999;z-index:-99999'; div.setAttribute("style", style); document.body.appendChild(div); @@ -828,7 +828,7 @@ var Font = (function () { warn("Is " + fontName + " loaded?"); } } - + window.clearInterval(interval); Fonts[fontName].loading = false; this.start = 0; From 1c611d4e32698714b9e8c9b1edc67c03cb79c50f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 01:18:11 +0200 Subject: [PATCH 04/15] Improve a bit the createNameTable code --- fonts.js | 82 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/fonts.js b/fonts.js index d09e2ad83..7d9a96236 100644 --- a/fonts.js +++ b/fonts.js @@ -616,43 +616,65 @@ var Font = (function () { var otf = new Uint8Array(kMaxFontFileSize); function createNameTable(name) { - var names = [ - "See original licence", // Copyright - fontName, // Font family - "undefined", // Font subfamily (font weight) - "uniqueID", // Unique ID - fontName, // Full font name - "0.1", // Version - "undefined", // Postscript name - "undefined", // Trademark - "undefined", // Manufacturer - "undefined" // Designer + // All the strings of the name table should be an odd number of bytes + if (name.length % 2) + name = name.slice(0, name.length - 1); + + var strings = [ + "Original licence",// 0.Copyright + name, // 1.Font family + "Unknown", // 2.Font subfamily (font weight) + "uniqueID", // 3.Unique ID + name, // 4.Full font name + "Version 0.11", // 5.Version + "Unknown", // 6.Postscript name + "Unknown", // 7.Trademark + "Unknown", // 8.Manufacturer + "Unknown" // 9.Designer ]; + var platforms = ["\x00\x01", "\x00\x03"]; + var encodings = ["\x00\x00", "\x00\x01"]; + var languages = ["\x00\x00", "\x04\x09"]; + + // Mac want 1-byte per character strings while Windows want + // 2-bytes per character, so duplicate the names table + var stringsUnicode = []; + var names = [strings, stringsUnicode]; + for (var i = 0; i < strings.length; i++) { + var str = strings[i]; + + var strUnicode = ""; + for (var j = 0; j < str.length; j++) + strUnicode += string16(str.charCodeAt(j)); + stringsUnicode.push(strUnicode); + } + + var namesRecordCount = platforms.length * names.length; var nameTable = - "\x00\x00" + // format - "\x00\x0A" + // Number of names Record - "\x00\x7E"; // Storage + "\x00\x00" + // format + string16(namesRecordCount) + // Number of names Record + string16(namesRecordCount * 12 + 6); // Storage // Build the name records field var strOffset = 0; - for (var i = 0; i < names.length; i++) { - var str = names[i]; - - var nameRecord = - "\x00\x01" + // platform ID - "\x00\x00" + // encoding ID - "\x00\x00" + // language ID - "\x00\x00" + // name ID - string16(str.length) + - string16(strOffset); - nameTable += nameRecord; - - strOffset += str.length; + for (var i = 0; i < platforms.length; i++) { + var names = strings[i]; + for (var j = 0; j < names.length; j++) { + var str = names[j]; + var nameRecord = + platforms[i] + // platform ID + encodings[i] + // encoding ID + languages[i] + // language ID + string16(i) + // name ID + string16(str.length) + + string16(strOffset); + nameTable += nameRecord; + strOffset += str.length; + } } - nameTable += names.join(""); - return nameTable; + return nameTable + strings.join("") + stringsUnicode.join(""); } // Required Tables @@ -758,7 +780,7 @@ var Font = (function () { createTableEntry(otf, offsets, "maxp", maxp); /** NAME */ - name = stringToArray(createNameTable(name)); + name = stringToArray(createNameTable(fontName)); createTableEntry(otf, offsets, "name", name); /** POST */ From e448dce42b0a58830b83b05e16c7ab5f27b9dcd0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 02:52:47 +0200 Subject: [PATCH 05/15] Add better informations for the OS/2 table --- fonts.js | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 168 insertions(+), 8 deletions(-) diff --git a/fonts.js b/fonts.js index 7d9a96236..444980042 100644 --- a/fonts.js +++ b/fonts.js @@ -123,6 +123,140 @@ var FontLoader = { } }; +var UnicodeRanges = [ + { "begin": 0x0000, "end": 0x007F }, // Basic Latin + { "begin": 0x0080, "end": 0x00FF }, // Latin-1 Supplement + { "begin": 0x0100, "end": 0x017F }, // Latin Extended-A + { "begin": 0x0180, "end": 0x024F }, // Latin Extended-B + { "begin": 0x0250, "end": 0x02AF }, // IPA Extensions + { "begin": 0x02B0, "end": 0x02FF }, // Spacing Modifier Letters + { "begin": 0x0300, "end": 0x036F }, // Combining Diacritical Marks + { "begin": 0x0370, "end": 0x03FF }, // Greek and Coptic + { "begin": 0x2C80, "end": 0x2CFF }, // Coptic + { "begin": 0x0400, "end": 0x04FF }, // Cyrillic + { "begin": 0x0530, "end": 0x058F }, // Armenian + { "begin": 0x0590, "end": 0x05FF }, // Hebrew + { "begin": 0xA500, "end": 0xA63F }, // Vai + { "begin": 0x0600, "end": 0x06FF }, // Arabic + { "begin": 0x07C0, "end": 0x07FF }, // NKo + { "begin": 0x0900, "end": 0x097F }, // Devanagari + { "begin": 0x0980, "end": 0x09FF }, // Bengali + { "begin": 0x0A00, "end": 0x0A7F }, // Gurmukhi + { "begin": 0x0A80, "end": 0x0AFF }, // Gujarati + { "begin": 0x0B00, "end": 0x0B7F }, // Oriya + { "begin": 0x0B80, "end": 0x0BFF }, // Tamil + { "begin": 0x0C00, "end": 0x0C7F }, // Telugu + { "begin": 0x0C80, "end": 0x0CFF }, // Kannada + { "begin": 0x0D00, "end": 0x0D7F }, // Malayalam + { "begin": 0x0E00, "end": 0x0E7F }, // Thai + { "begin": 0x0E80, "end": 0x0EFF }, // Lao + { "begin": 0x10A0, "end": 0x10FF }, // Georgian + { "begin": 0x1B00, "end": 0x1B7F }, // Balinese + { "begin": 0x1100, "end": 0x11FF }, // Hangul Jamo + { "begin": 0x1E00, "end": 0x1EFF }, // Latin Extended Additional + { "begin": 0x1F00, "end": 0x1FFF }, // Greek Extended + { "begin": 0x2000, "end": 0x206F }, // General Punctuation + { "begin": 0x2070, "end": 0x209F }, // Superscripts And Subscripts + { "begin": 0x20A0, "end": 0x20CF }, // Currency Symbol + { "begin": 0x20D0, "end": 0x20FF }, // Combining Diacritical Marks For Symbols + { "begin": 0x2100, "end": 0x214F }, // Letterlike Symbols + { "begin": 0x2150, "end": 0x218F }, // Number Forms + { "begin": 0x2190, "end": 0x21FF }, // Arrows + { "begin": 0x2200, "end": 0x22FF }, // Mathematical Operators + { "begin": 0x2300, "end": 0x23FF }, // Miscellaneous Technical + { "begin": 0x2400, "end": 0x243F }, // Control Pictures + { "begin": 0x2440, "end": 0x245F }, // Optical Character Recognition + { "begin": 0x2460, "end": 0x24FF }, // Enclosed Alphanumerics + { "begin": 0x2500, "end": 0x257F }, // Box Drawing + { "begin": 0x2580, "end": 0x259F }, // Block Elements + { "begin": 0x25A0, "end": 0x25FF }, // Geometric Shapes + { "begin": 0x2600, "end": 0x26FF }, // Miscellaneous Symbols + { "begin": 0x2700, "end": 0x27BF }, // Dingbats + { "begin": 0x3000, "end": 0x303F }, // CJK Symbols And Punctuation + { "begin": 0x3040, "end": 0x309F }, // Hiragana + { "begin": 0x30A0, "end": 0x30FF }, // Katakana + { "begin": 0x3100, "end": 0x312F }, // Bopomofo + { "begin": 0x3130, "end": 0x318F }, // Hangul Compatibility Jamo + { "begin": 0xA840, "end": 0xA87F }, // Phags-pa + { "begin": 0x3200, "end": 0x32FF }, // Enclosed CJK Letters And Months + { "begin": 0x3300, "end": 0x33FF }, // CJK Compatibility + { "begin": 0xAC00, "end": 0xD7AF }, // Hangul Syllables + { "begin": 0xD800, "end": 0xDFFF }, // Non-Plane 0 * + { "begin": 0x10900, "end": 0x1091F }, // Phoenicia + { "begin": 0x4E00, "end": 0x9FFF }, // CJK Unified Ideographs + { "begin": 0xE000, "end": 0xF8FF }, // Private Use Area (plane 0) + { "begin": 0x31C0, "end": 0x31EF }, // CJK Strokes + { "begin": 0xFB00, "end": 0xFB4F }, // Alphabetic Presentation Forms + { "begin": 0xFB50, "end": 0xFDFF }, // Arabic Presentation Forms-A + { "begin": 0xFE20, "end": 0xFE2F }, // Combining Half Marks + { "begin": 0xFE10, "end": 0xFE1F }, // Vertical Forms + { "begin": 0xFE50, "end": 0xFE6F }, // Small Form Variants + { "begin": 0xFE70, "end": 0xFEFF }, // Arabic Presentation Forms-B + { "begin": 0xFF00, "end": 0xFFEF }, // Halfwidth And Fullwidth Forms + { "begin": 0xFFF0, "end": 0xFFFF }, // Specials + { "begin": 0x0F00, "end": 0x0FFF }, // Tibetan + { "begin": 0x0700, "end": 0x074F }, // Syriac + { "begin": 0x0780, "end": 0x07BF }, // Thaana + { "begin": 0x0D80, "end": 0x0DFF }, // Sinhala + { "begin": 0x1000, "end": 0x109F }, // Myanmar + { "begin": 0x1200, "end": 0x137F }, // Ethiopic + { "begin": 0x13A0, "end": 0x13FF }, // Cherokee + { "begin": 0x1400, "end": 0x167F }, // Unified Canadian Aboriginal Syllabics + { "begin": 0x1680, "end": 0x169F }, // Ogham + { "begin": 0x16A0, "end": 0x16FF }, // Runic + { "begin": 0x1780, "end": 0x17FF }, // Khmer + { "begin": 0x1800, "end": 0x18AF }, // Mongolian + { "begin": 0x2800, "end": 0x28FF }, // Braille Patterns + { "begin": 0xA000, "end": 0xA48F }, // Yi Syllables + { "begin": 0x1700, "end": 0x171F }, // Tagalog + { "begin": 0x10300, "end": 0x1032F }, // Old Italic + { "begin": 0x10330, "end": 0x1034F }, // Gothic + { "begin": 0x10400, "end": 0x1044F }, // Deseret + { "begin": 0x1D000, "end": 0x1D0FF }, // Byzantine Musical Symbols + { "begin": 0x1D400, "end": 0x1D7FF }, // Mathematical Alphanumeric Symbols + { "begin": 0xFF000, "end": 0xFFFFD }, // Private Use (plane 15) + { "begin": 0xFE00, "end": 0xFE0F }, // Variation Selectors + { "begin": 0xE0000, "end": 0xE007F }, // Tags + { "begin": 0x1900, "end": 0x194F }, // Limbu + { "begin": 0x1950, "end": 0x197F }, // Tai Le + { "begin": 0x1980, "end": 0x19DF }, // New Tai Lue + { "begin": 0x1A00, "end": 0x1A1F }, // Buginese + { "begin": 0x2C00, "end": 0x2C5F }, // Glagolitic + { "begin": 0x2D30, "end": 0x2D7F }, // Tifinagh + { "begin": 0x4DC0, "end": 0x4DFF }, // Yijing Hexagram Symbols + { "begin": 0xA800, "end": 0xA82F }, // Syloti Nagri + { "begin": 0x10000, "end": 0x1007F }, // Linear B Syllabary + { "begin": 0x10140, "end": 0x1018F }, // Ancient Greek Numbers + { "begin": 0x10380, "end": 0x1039F }, // Ugaritic + { "begin": 0x103A0, "end": 0x103DF }, // Old Persian + { "begin": 0x10450, "end": 0x1047F }, // Shavian + { "begin": 0x10480, "end": 0x104AF }, // Osmanya + { "begin": 0x10800, "end": 0x1083F }, // Cypriot Syllabary + { "begin": 0x10A00, "end": 0x10A5F }, // Kharoshthi + { "begin": 0x1D300, "end": 0x1D35F }, // Tai Xuan Jing Symbols + { "begin": 0x12000, "end": 0x123FF }, // Cuneiform + { "begin": 0x1D360, "end": 0x1D37F }, // Counting Rod Numerals + { "begin": 0x1B80, "end": 0x1BBF }, // Sundanese + { "begin": 0x1C00, "end": 0x1C4F }, // Lepcha + { "begin": 0x1C50, "end": 0x1C7F }, // Ol Chiki + { "begin": 0xA880, "end": 0xA8DF }, // Saurashtra + { "begin": 0xA900, "end": 0xA92F }, // Kayah Li + { "begin": 0xA930, "end": 0xA95F }, // Rejang + { "begin": 0xAA00, "end": 0xAA5F }, // Cham + { "begin": 0x10190, "end": 0x101CF }, // Ancient Symbols + { "begin": 0x101D0, "end": 0x101FF }, // Phaistos Disc + { "begin": 0x102A0, "end": 0x102DF }, // Carian + { "begin": 0x1F030, "end": 0x1F09F } // Domino Tiles +]; + +function getUnicodeRangeFor(value) { + for (var i = 0; i < UnicodeRanges.length; i++) { + var range = UnicodeRanges[i]; + if (value >= range.begin && value < range.end) + return i; + } + return -1; +}; /** * 'Font' is the class the outside world should use, it encapsulate all the font @@ -338,6 +472,30 @@ var Font = (function () { }; function createOS2Table(properties) { + var ulUnicodeRange1 = 0; + var ulUnicodeRange2 = 0; + var ulUnicodeRange3 = 0; + var ulUnicodeRange4 = 0; + + var charset = properties.charset; + if (charset && charset.length) { + // XXX why is the first character equal to ''? + for (var i = 1; i < charset.length; i++) { + var position = getUnicodeRangeFor(GlyphsUnicode[charset[i]]); + if (position < 32) { + ulUnicodeRange1 |= 1 << position; + } else if (position < 64) { + ulUnicodeRange2 |= 1 << position - 32; + } else if (position < 96) { + ulUnicodeRange3 |= 1 << position - 64; + } else if (position < 123) { + ulUnicodeRange4 |= 1 << position - 96; + } else { + error("Unicode ranges Bits > 123 are reserved for internal usage"); + } + } + } + return "\x00\x03" + // version "\x02\x24" + // xAvgCharWidth "\x01\xF4" + // usWeightClass @@ -355,14 +513,14 @@ var Font = (function () { "\x01\x02" + // yStrikeOutPosition "\x00\x00" + // sFamilyClass "\x02\x00\x06\x03\x00\x00\x00\x00\x00\x00" + // Panose - "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 0-31) - "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 32-63) - "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 64-95) - "\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 96-127) + string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31) + string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63) + string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95) + string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127) "\x2A\x32\x31\x2A" + // achVendID "\x00\x00" + // fsSelection - "\x00\x2D" + // usFirstCharIndex - "\x00\x7A" + // usLastCharIndex + string16(properties.firstChar) + // usFirstCharIndex + string16(properties.lastChar) + // usLastCharIndex "\x00\x20" + // sTypoAscender "\x00\x00" + // sTypeDescender "\x00\x00" + // sTypoLineGap @@ -372,8 +530,10 @@ var Font = (function () { "\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight string16(properties.capHeight) + // sCapHeight - "\x00\x01" + // usDefaultChar - "\x00\xCD" + // usBreakChar + // XXX mapping .notdef in the cmap table will allow us to use it + // here instead, especially because these field are limit to 0xFFFF + string16(properties.firstChar) + // usDefaultChar + string16(properties.firstChar) + // usBreakChar "\x00\x00"; // usMaxContext }; From 2e71f798655837992b6bff4c12c3818829110390 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 02:58:40 +0200 Subject: [PATCH 06/15] Remove the first empty character of charset --- fonts.js | 2 +- pdf.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 444980042..f023419bb 100644 --- a/fonts.js +++ b/fonts.js @@ -479,7 +479,7 @@ var Font = (function () { var charset = properties.charset; if (charset && charset.length) { - // XXX why is the first character equal to ''? + log(charset); for (var i = 1; i < charset.length; i++) { var position = getUnicodeRangeFor(GlyphsUnicode[charset[i]]); if (position < 32) { diff --git a/pdf.js b/pdf.js index 33a21e38c..e1c48b4d9 100644 --- a/pdf.js +++ b/pdf.js @@ -3440,6 +3440,7 @@ var CanvasGraphics = (function() { if (charset) { assertWellFormed(IsString(charset), "invalid charset"); charset = charset.split("/"); + charset.shift(); } } else if (IsName(encoding)) { var encoding = Encodings[encoding.name]; @@ -3534,6 +3535,8 @@ var CanvasGraphics = (function() { type: subType.name, encoding: encodingMap, charset: charset, + firstChar: fontDict.get("FirstChar"), + lastChar: fontDict.get("LastChar"), bbox: descriptor.get("FontBBox"), ascent: descriptor.get("Ascent"), descent: descriptor.get("Descent"), From a2974b2f581301871f4793606f29e848de6e5a6a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 03:01:46 +0200 Subject: [PATCH 07/15] Map .notdef in order to attach the [missing|break]Char to it --- fonts.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fonts.js b/fonts.js index f023419bb..1aee442c6 100644 --- a/fonts.js +++ b/fonts.js @@ -417,6 +417,7 @@ var Font = (function () { }; function createCMapTable(glyphs) { + glyphs.push({ unicode: 0x0000 }); var ranges = getRanges(glyphs); var headerSize = (12 * 2 + (ranges.length * 4 * 2)); @@ -450,7 +451,7 @@ var Font = (function () { var range = ranges[i]; var start = range[0]; var end = range[1]; - var delta = (((start - 1) - bias) ^ 0xffff) + 1; + var delta = (((start - 1) - bias) ^ 0xffff); bias += (end - start + 1); startCount += string16(start); @@ -479,7 +480,6 @@ var Font = (function () { var charset = properties.charset; if (charset && charset.length) { - log(charset); for (var i = 1; i < charset.length; i++) { var position = getUnicodeRangeFor(GlyphsUnicode[charset[i]]); if (position < 32) { @@ -530,10 +530,8 @@ var Font = (function () { "\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight string16(properties.capHeight) + // sCapHeight - // XXX mapping .notdef in the cmap table will allow us to use it - // here instead, especially because these field are limit to 0xFFFF - string16(properties.firstChar) + // usDefaultChar - string16(properties.firstChar) + // usBreakChar + string16(0) + // usDefaultChar + string16(0) + // usBreakChar "\x00\x00"; // usMaxContext }; From 9921288f44292ce6a9bf1c5be6f39c6f4f489176 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 03:24:07 +0200 Subject: [PATCH 08/15] Set a default font size identical for .notdef --- fonts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 1aee442c6..a3f270c94 100644 --- a/fonts.js +++ b/fonts.js @@ -299,6 +299,7 @@ var Font = (function () { // Wrap the CFF data inside an OTF font file data = this.convert(name, cff, properties); + writeToFile(data, "/tmp/file." + fontName + "-" + fontCount + ".otf"); break; case "TrueType": @@ -922,7 +923,7 @@ var Font = (function () { * while Windows use this data. So be careful if you hack on Linux and * have to touch the 'hmtx' table */ - hmtx = "\x00\x00\x00\x00"; // Fake .notdef + hmtx = "\x00\x8B\x00\x00"; // Fake .notdef var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i]; @@ -1635,7 +1636,7 @@ CFF.prototype = { charset.push(bytes[1]); } - var charstringsIndex = this.createCFFIndexHeader([[0x40, 0x0E]].concat(glyphs), true); + var charstringsIndex = this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true); //Top Dict Index var topDictIndex = [ From 233439949855ac14182c0371552dbe6f027b1805 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 03:27:22 +0200 Subject: [PATCH 09/15] Add more information about the italic angle --- fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index a3f270c94..a7a2ed147 100644 --- a/fonts.js +++ b/fonts.js @@ -887,7 +887,7 @@ var Font = (function () { "\x00\x00" + // yMin "\x00\x00" + // xMax "\x00\x00" + // yMax - "\x00\x00" + // macStyle + string16(properties.italicAngle ? 1 : 0) + // macStyle "\x00\x11" + // lowestRecPPEM "\x00\x00" + // fontDirectionHint "\x00\x00" + // indexToLocFormat @@ -906,7 +906,7 @@ var Font = (function () { "\x00\x00" + // minRightSidebearing "\x00\x00" + // xMaxExtent "\x00\x00" + // caretSlopeRise - "\x00\x00" + // caretSlopeRun + string16(properties.italicAngle) + // caretSlopeRun "\x00\x00" + // caretOffset "\x00\x00" + // -reserved- "\x00\x00" + // -reserved- From 64f8e79bf80d5740a9a2e430a3dff133f2c42df1 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 05:38:10 +0200 Subject: [PATCH 10/15] Make windows table header more compatible with windows --- fonts.js | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/fonts.js b/fonts.js index a7a2ed147..d6812590e 100644 --- a/fonts.js +++ b/fonts.js @@ -299,7 +299,6 @@ var Font = (function () { // Wrap the CFF data inside an OTF font file data = this.convert(name, cff, properties); - writeToFile(data, "/tmp/file." + fontName + "-" + fontCount + ".otf"); break; case "TrueType": @@ -373,7 +372,7 @@ var Font = (function () { // length var length = data.length; - + // Per spec tables must be 4-bytes align so add padding as needed while (data.length & 3) data.push(0x00); @@ -435,7 +434,7 @@ var Font = (function () { "\x00\x00\x00\x0C" + // start of the table record "\x00\x04" + // format string16(headerSize) + // length - "\x00\x00" + // languages + "\x04\x09" + // languages string16(segCount2) + string16(searchRange) + string16(searchEntry) + @@ -458,7 +457,7 @@ var Font = (function () { startCount += string16(start); endCount += string16(end); idDeltas += string16(delta); - idRangeOffsets += string16(0); + idRangeOffsets += string16(0); for (var j = 0; j < range.length; j++) glyphsIds += String.fromCharCode(range[j]); @@ -479,10 +478,19 @@ var Font = (function () { var ulUnicodeRange3 = 0; var ulUnicodeRange4 = 0; - var charset = properties.charset; + var charset = properties.charset; if (charset && charset.length) { + var firstCharIndex = null; + var lastCharIndex = 0; + for (var i = 1; i < charset.length; i++) { - var position = getUnicodeRangeFor(GlyphsUnicode[charset[i]]); + var code = GlyphsUnicode[charset[i]]; + if (code < firstCharIndex || !firstCharIndex) + firstCharIndex = code; + if (code > lastCharIndex) + lastCharIndex = code; + + var position = getUnicodeRangeFor(code); if (position < 32) { ulUnicodeRange1 |= 1 << position; } else if (position < 64) { @@ -520,8 +528,8 @@ var Font = (function () { string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127) "\x2A\x32\x31\x2A" + // achVendID "\x00\x00" + // fsSelection - string16(properties.firstChar) + // usFirstCharIndex - string16(properties.lastChar) + // usLastCharIndex + string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex + string16(lastCharIndex || properties.lastChar) + // usLastCharIndex "\x00\x20" + // sTypoAscender "\x00\x00" + // sTypeDescender "\x00\x00" + // sTypoLineGap @@ -532,7 +540,7 @@ var Font = (function () { string16(properties.xHeight) + // sxHeight string16(properties.capHeight) + // sCapHeight string16(0) + // usDefaultChar - string16(0) + // usBreakChar + string16(firstCharIndex || properties.firstChar) + // usBreakChar "\x00\x00"; // usMaxContext }; @@ -780,7 +788,7 @@ var Font = (function () { name = name.slice(0, name.length - 1); var strings = [ - "Original licence",// 0.Copyright + "Original licence", // 0.Copyright name, // 1.Font family "Unknown", // 2.Font subfamily (font weight) "uniqueID", // 3.Unique ID @@ -792,14 +800,9 @@ var Font = (function () { "Unknown" // 9.Designer ]; - var platforms = ["\x00\x01", "\x00\x03"]; - var encodings = ["\x00\x00", "\x00\x01"]; - var languages = ["\x00\x00", "\x04\x09"]; - // Mac want 1-byte per character strings while Windows want // 2-bytes per character, so duplicate the names table var stringsUnicode = []; - var names = [strings, stringsUnicode]; for (var i = 0; i < strings.length; i++) { var str = strings[i]; @@ -809,7 +812,12 @@ var Font = (function () { stringsUnicode.push(strUnicode); } - var namesRecordCount = platforms.length * names.length; + var names = [strings, stringsUnicode]; + var platforms = ["\x00\x01", "\x00\x03"]; + var encodings = ["\x00\x00", "\x00\x01"]; + var languages = ["\x00\x00", "\x04\x09"]; + + var namesRecordCount = strings.length * platforms.length; var nameTable = "\x00\x00" + // format string16(namesRecordCount) + // Number of names Record @@ -818,9 +826,9 @@ var Font = (function () { // Build the name records field var strOffset = 0; for (var i = 0; i < platforms.length; i++) { - var names = strings[i]; - for (var j = 0; j < names.length; j++) { - var str = names[j]; + var strs = names[i]; + for (var j = 0; j < strs.length; j++) { + var str = strs[j]; var nameRecord = platforms[i] + // platform ID encodings[i] + // encoding ID @@ -833,7 +841,8 @@ var Font = (function () { } } - return nameTable + strings.join("") + stringsUnicode.join(""); + nameTable += strings.join("") + stringsUnicode.join(""); + return nameTable; } // Required Tables @@ -870,13 +879,13 @@ var Font = (function () { /** CMAP */ var charstrings = font.charstrings; - cmap = createCMapTable(charstrings); + cmap = createCMapTable(charstrings.slice()); createTableEntry(otf, offsets, "cmap", cmap); /** HEAD */ head = stringToArray( "\x00\x01\x00\x00" + // Version number - "\x00\x00\x50\x00" + // fontRevision + "\x00\x00\x10\x00" + // fontRevision "\x00\x00\x00\x00" + // checksumAdjustement "\x5F\x0F\x3C\xF5" + // magicNumber "\x00\x00" + // Flags @@ -923,7 +932,7 @@ var Font = (function () { * while Windows use this data. So be careful if you hack on Linux and * have to touch the 'hmtx' table */ - hmtx = "\x00\x8B\x00\x00"; // Fake .notdef + hmtx = "\x00\x00\x00\x00"; // Fake .notdef var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i]; From 7ff6f5166cb89aea60e6d4a91af8970ba438cfdb Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 09:25:57 +0200 Subject: [PATCH 11/15] Fix languages bustage --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index d6812590e..3a95b2da2 100644 --- a/fonts.js +++ b/fonts.js @@ -434,7 +434,7 @@ var Font = (function () { "\x00\x00\x00\x0C" + // start of the table record "\x00\x04" + // format string16(headerSize) + // length - "\x04\x09" + // languages + "\x00\x00" + // languages string16(segCount2) + string16(searchRange) + string16(searchEntry) + From 1c78d8fdb40216ab4cefe2a0b857f9b9363d35ba Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 11:48:43 +0200 Subject: [PATCH 12/15] Fix more headers tables --- fonts.js | 72 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/fonts.js b/fonts.js index 3a95b2da2..91fdfd3e5 100644 --- a/fonts.js +++ b/fonts.js @@ -299,6 +299,7 @@ var Font = (function () { // Wrap the CFF data inside an OTF font file data = this.convert(name, cff, properties); + writeToFile(data, "/tmp/file." + fontName + "-" + fontCount + ".otf"); break; case "TrueType": @@ -485,9 +486,9 @@ var Font = (function () { for (var i = 1; i < charset.length; i++) { var code = GlyphsUnicode[charset[i]]; - if (code < firstCharIndex || !firstCharIndex) + if (firstCharIndex > code || !firstCharIndex) firstCharIndex = code; - if (code > lastCharIndex) + if (lastCharIndex < code) lastCharIndex = code; var position = getUnicodeRangeFor(code); @@ -509,7 +510,7 @@ var Font = (function () { "\x02\x24" + // xAvgCharWidth "\x01\xF4" + // usWeightClass "\x00\x05" + // usWidthClass - "\x00\x00" + // fstype + "\x00\x02" + // fstype "\x02\x8A" + // ySubscriptXSize "\x02\xBB" + // ySubscriptYSize "\x00\x00" + // ySubscriptXOffset @@ -521,41 +522,41 @@ var Font = (function () { "\x00\x31" + // yStrikeOutSize "\x01\x02" + // yStrikeOutPosition "\x00\x00" + // sFamilyClass - "\x02\x00\x06\x03\x00\x00\x00\x00\x00\x00" + // Panose + "\x00\x00\x06" + String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) + + "\x00\x00\x00\x00\x00\x00" + // Panose string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31) string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63) string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95) string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127) "\x2A\x32\x31\x2A" + // achVendID - "\x00\x00" + // fsSelection + string16(properties.italicAngle ? 1 : 0) + // fsSelection string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex string16(lastCharIndex || properties.lastChar) + // usLastCharIndex - "\x00\x20" + // sTypoAscender - "\x00\x00" + // sTypeDescender - "\x00\x00" + // sTypoLineGap + string16(properties.ascent) + // sTypoAscender + string16(properties.descent) + // sTypoDescender + "\x00\x64" + // sTypoLineGap (7%-10% of the unitsPerEM value) string16(properties.ascent) + // usWinAscent - string16(properties.descent) + // usWinDescent + string16(-properties.descent) + // usWinDescent "\x00\x00\x00\x00" + // ulCodePageRange1 (Bits 0-31) "\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight string16(properties.capHeight) + // sCapHeight string16(0) + // usDefaultChar string16(firstCharIndex || properties.firstChar) + // usBreakChar - "\x00\x00"; // usMaxContext + "\x00\x03"; // usMaxContext }; function createPostTable(properties) { - TODO("Fill with real values from the font dict"); - - return "\x00\x03\x00\x00" + // Version number - string32(properties.italicAngle) + // italicAngle - "\x00\x00" + // underlinePosition - "\x00\x00" + // underlineThickness - "\x00\x00\x00\x00" + // isFixedPitch - "\x00\x00\x00\x00" + // minMemType42 - "\x00\x00\x00\x00" + // maxMemType42 - "\x00\x00\x00\x00" + // minMemType1 - "\x00\x00\x00\x00"; // maxMemType1 + var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16))); + return "\x00\x03\x00\x00" + // Version number + string32(angle) + // italicAngle + "\x00\x00" + // underlinePosition + "\x00\x00" + // underlineThickness + string32(properties.fixedPitch) + // isFixedPitch + "\x00\x00\x00\x00" + // minMemType42 + "\x00\x00\x00\x00" + // maxMemType42 + "\x00\x00\x00\x00" + // minMemType1 + "\x00\x00\x00\x00"; // maxMemType1 }; constructor.prototype = { @@ -844,6 +845,14 @@ var Font = (function () { nameTable += strings.join("") + stringsUnicode.join(""); return nameTable; } + + function isFixedPitch(glyphs) { + for (var i = 0; i < glyphs.length - 1; i++) { + if (glyphs[i] != glyphs[i+1]) + return false; + } + return true; + }; // Required Tables var CFF = @@ -874,11 +883,12 @@ var Font = (function () { createTableEntry(otf, offsets, "CFF ", CFF); /** OS/2 */ + var charstrings = font.charstrings; + properties.fixedPitch = isFixedPitch(charstrings); OS2 = stringToArray(createOS2Table(properties)); createTableEntry(otf, offsets, "OS/2", OS2); /** CMAP */ - var charstrings = font.charstrings; cmap = createCMapTable(charstrings.slice()); createTableEntry(otf, offsets, "cmap", cmap); @@ -893,10 +903,10 @@ var Font = (function () { "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // creation date "\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // modifification date "\x00\x00" + // xMin - "\x00\x00" + // yMin - "\x00\x00" + // xMax - "\x00\x00" + // yMax - string16(properties.italicAngle ? 1 : 0) + // macStyle + string16(properties.descent) + // yMin + "\x0F\xFF" + // xMax + string16(properties.ascent) + // yMax + string16(properties.italicAngle ? 2 : 0) + // macStyle "\x00\x11" + // lowestRecPPEM "\x00\x00" + // fontDirectionHint "\x00\x00" + // indexToLocFormat @@ -910,12 +920,12 @@ var Font = (function () { string16(properties.ascent) + // Typographic Ascent string16(properties.descent) + // Typographic Descent "\x00\x00" + // Line Gap - "\xFF\xFF" + // advanceWidthMax + "\x00\xFF" + // advanceWidthMax "\x00\x00" + // minLeftSidebearing "\x00\x00" + // minRightSidebearing "\x00\x00" + // xMaxExtent - "\x00\x00" + // caretSlopeRise - string16(properties.italicAngle) + // caretSlopeRun + string16(properties.capHeight) + // caretSlopeRise + string16(Math.tan(properties.italicAngle) * properties.xHeight) + // caretSlopeRun "\x00\x00" + // caretOffset "\x00\x00" + // -reserved- "\x00\x00" + // -reserved- @@ -933,10 +943,8 @@ var Font = (function () { * have to touch the 'hmtx' table */ hmtx = "\x00\x00\x00\x00"; // Fake .notdef - var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { - var charstring = charstrings[i]; - hmtx += string16(charstring.width) + string16(0); + hmtx += string16(charstrings[i].width) + string16(0); } hmtx = stringToArray(hmtx); createTableEntry(otf, offsets, "hmtx", hmtx); From 9b67a1e6b539eaee3600bfdb788f1c7edf4cdcc9 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 11:50:47 +0200 Subject: [PATCH 13/15] Forgot to add pdf.js to the last commit --- fonts.js | 1 - pdf.js | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 91fdfd3e5..df1795177 100644 --- a/fonts.js +++ b/fonts.js @@ -299,7 +299,6 @@ var Font = (function () { // Wrap the CFF data inside an OTF font file data = this.convert(name, cff, properties); - writeToFile(data, "/tmp/file." + fontName + "-" + fontCount + ".otf"); break; case "TrueType": diff --git a/pdf.js b/pdf.js index e1c48b4d9..8e0ab552a 100644 --- a/pdf.js +++ b/pdf.js @@ -3543,7 +3543,8 @@ var CanvasGraphics = (function() { xHeight: descriptor.get("XHeight"), capHeight: descriptor.get("CapHeight"), flags: descriptor.get("Flags"), - italicAngle: descriptor.get("ItalicAngle") + italicAngle: descriptor.get("ItalicAngle"), + fixedPitch: false }; return { From 9418ef60b0943c8962c76fe9099710de4997e8b2 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 30 Jun 2011 03:21:39 -0700 Subject: [PATCH 14/15] bump up default zoom to 150%. <3 HTML --- multi_page_viewer.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_page_viewer.html b/multi_page_viewer.html index e90606a23..df71d6690 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -27,9 +27,9 @@ Zoom From 2e7df014592624b62b1aec74345c016713e52afa Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 30 Jun 2011 12:40:21 +0200 Subject: [PATCH 15/15] Fix windows mispotionning issue --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 5a7a41c0f..fdc5949a5 100644 --- a/fonts.js +++ b/fonts.js @@ -932,7 +932,7 @@ var Font = (function () { string16(properties.ascent) + // Typographic Ascent string16(properties.descent) + // Typographic Descent "\x00\x00" + // Line Gap - "\x00\xFF" + // advanceWidthMax + "\xFF\xFF" + // advanceWidthMax "\x00\x00" + // minLeftSidebearing "\x00\x00" + // minRightSidebearing "\x00\x00" + // xMaxExtent