From bf2c5257880410637b113c1e29bf8bee50e8e479 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sat, 11 Jun 2011 23:49:17 -0700 Subject: [PATCH 001/439] remove debug code --- pdf.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index 0816dc069..418db2462 100644 --- a/pdf.js +++ b/pdf.js @@ -1971,14 +1971,7 @@ var CanvasGraphics = (function() { var fn = sh.get("Function"); fn = this.xref.fetchIfRef(fn); -/* - console.log("x0: "+ x0, "y0: "+ y0, "x1: "+ x1, "y1: "+ y1); - console.log("size: "+ fn.dict.get("Size")); - console.log("BPS: "+ fn.dict.get("BitsPerSample")); - console.log(fn.dict.get("Encode")); - console.log(fn.dict.get("Range")); - console.log(fn.dict.get("Decode")); -*/ + var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); gradient.addColorStop(0, 'rgb(0,0,255)'); From b7449f3bccdbeb5b062b93c414d85daeccc0febb Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 13 Jun 2011 23:23:13 +0200 Subject: [PATCH 002/439] Do not use makeSubStream in the CFF constructor --- PDFFont.js | 6 +++--- pdf.js | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 9318fd3a1..34fb28fc4 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -1142,9 +1142,9 @@ var CFF = function(aFontName, aFontFile) { var length1 = aFontFile.dict.get("Length1"); var length2 = aFontFile.dict.get("Length2"); - var pos = aFontFile.pos; - var ASCIIStream = aFontFile.makeSubStream(pos, length1, aFontFile.dict); - var binaryStream = aFontFile.makeSubStream(pos + length1, length2, aFontFile.dict); + + var ASCIIStream = new Stream(aFontFile.getBytes(length1)); + var binaryStream = new Stream(aFontFile.getBytes(length2)); this.parser = new Type1Parser(ASCIIStream, binaryStream); var fontName = this.parser.parse(); diff --git a/pdf.js b/pdf.js index a9c9bf020..8b06f5582 100644 --- a/pdf.js +++ b/pdf.js @@ -1848,7 +1848,6 @@ var CanvasGraphics = (function() { } this.current.fontSize = size; - TODO("using hard-coded font for testing"); this.ctx.font = this.current.fontSize +'px "' + fontName + '"'; }, moveText: function (x, y) { From 375b38392082f014e7a099888cb60dfc3001bbf2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 04:35:46 +0200 Subject: [PATCH 003/439] Make the fonts decoding code works with asynchronous data url --- PDFFont.js | 104 +++++++++++++++++++++++++++++++++++++++++++++++++---- pdf.js | 15 +++++++- test.js | 61 ++++++++++++++++++++++++------- 3 files changed, 161 insertions(+), 19 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 34fb28fc4..4e81187b9 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -11,6 +11,16 @@ var kMaxFontFileSize = 40000; */ var kMaxGlyphsCount = 1024; +/** + * Maximum time to wait for a font to be loaded by @font-face + */ +var kMaxWaitForFontFace = 2000; + + /* + * Useful for debugging when you want to certains operations depending on how + * many fonts are loaded. + */ +var fontCount = 0; /** * Hold a map of decoded fonts and of the standard fourteen Type1 fonts and @@ -36,9 +46,10 @@ var Font = function(aFontName, aFontFile, aFontType) { // If the font has already been decoded simply return if (Fonts[aFontName]) { - this.font = Fonts[aFontName]; + this.font = Fonts[aFontName].data; return; } + fontCount++; var start = Date.now(); switch (aFontType) { @@ -62,10 +73,13 @@ var Font = function(aFontName, aFontFile, aFontType) { } var end = Date.now(); + Fonts[aFontName] = { + data: this.font, + loading: true + } + // Attach the font to the document this.bind(); - - Fonts[aFontName] = this.font; }; Font.prototype = { @@ -84,10 +98,90 @@ Font.prototype = { : String.fromCharCode(data[i])); var dataBase64 = window.btoa(str.join("")); + var fontName = this.name; + + /** Hack begin */ + + // Actually there is not event when a font has finished downloading so + // the following tons of code are a dirty hack to 'guess' when a font is + // ready + var debug = false; + + var canvas = document.createElement("canvas"); + var style = "position:absolute; left: " + + (debug ? (100 * fontCount) : "-200") + "px; top: -200px;"; + canvas.setAttribute("style", style); + canvas.setAttribute("width", 100); + canvas.setAttribute("heigth", 100); + document.body.appendChild(canvas); + + // Get the first character of the font + var page = pdfDocument.getPage(pageNum); + var xref = page.xref; + var resources = xref.fetchIfRef(page.resources); + var fontResource = resources.get("Font"); + var charset = ""; + for (var id in fontResource.map) { + var res = xref.fetch(fontResource.get(id)); + var descriptor = xref.fetch(res.get("FontDescriptor")); + var name = descriptor.get("FontName").toString(); + var font = Fonts[name.replace("+", "_")]; + if (font && font.loading && name == fontName.replace("_", "+")) { + charset = descriptor.get("CharSet").split("/"); + break; + } + } + + // Warn if the charset is not found, this is likely a bug! + var testCharset = charset; + if (!charset) { + warn("No charset found for: " + fontName); + } else { + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && testCharset.length <= 30) + testCharset = testCharset.concat(charset.slice()); + } + + // Get the font size canvas think it will be + var ctx = canvas.getContext("2d"); + var testString = ""; + for (var i = 0; i < testCharset.length; i++) { + var unicode = new Number("0x" + GlyphsUnicode[testCharset[i]]); + if (!unicode) + error("Unicode for " + testCharset[i] + " is has not been found in the glyphs list"); + testString += String.fromCharCode(unicode); + } + ctx.font = "20px " + fontName + ", Symbol"; + var textWidth = ctx.mozMeasureText(testString); + + if (debug) + ctx.fillText(testString, 20, 20); + + var start = Date.now(); + var interval = window.setInterval(function(self) { + ctx.font = "20px " + fontName + ", Symbol"; + + // For some reasons the font has not loaded, so mark it loaded for the + // page to proceed but cry + if ((Date.now() - start) >= kMaxWaitForFontFace) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + warn("Is " + fontName + " for charset: " + charset + " loaded?"); + } else if (textWidth != ctx.mozMeasureText(testString)) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + } + + if (debug) + ctx.fillText(testString, 20, 60); + }, 150, this); + + /** Hack end */ // Add the @font-face rule to the document var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");"; - var rule = "@font-face { font-family:'" + this.name + "';src:" + url + "}"; + var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); }, @@ -473,7 +567,6 @@ var TrueType = function(aFontName, aFontFile) { */ var PSFonts = new Dict(); - var Stack = function(aStackSize) { var innerStack = new Array(aStackSize || 0); @@ -1136,7 +1229,6 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { } }; - var CFF = function(aFontName, aFontFile) { var start = Date.now(); diff --git a/pdf.js b/pdf.js index 8b06f5582..697e6c3ad 100644 --- a/pdf.js +++ b/pdf.js @@ -1399,6 +1399,19 @@ var Page = (function() { ? obj : null)); }, + get fonts() { + var xref = this.xref; + var fonts = []; + + var resources = xref.fetchIfRef(this.resources); + var fontResource = resources.get("Font"); + for (var id in fontResource.map) { + var res = xref.fetch(fontResource.get(id)); + var descriptor = xref.fetch(res.get("FontDescriptor")); + fonts.push(descriptor.get("FontName").toString()); + } + return shadow(this, "fonts", fonts); + }, display: function(gfx) { var xref = this.xref; var contents = xref.fetchIfRef(this.contents); @@ -1843,7 +1856,7 @@ var CanvasGraphics = (function() { var fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile")); if (!fontFile) fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile2")); - fontName = fontDescriptor.get("FontName").name.replace("+", " "); + fontName = fontDescriptor.get("FontName").name.replace("+", "_"); new Font(fontName, fontFile, subtype); } diff --git a/test.js b/test.js index ec784ea62..bd6c812e8 100644 --- a/test.js +++ b/test.js @@ -21,7 +21,6 @@ function queryParams() { return params; } - function open(url) { document.title = url; req = new XMLHttpRequest(); @@ -54,21 +53,59 @@ function displayPage(num) { var page = pdfDocument.getPage(pageNum = num); - var t1 = Date.now(); + function display() { + var t1 = Date.now(); + var ctx = canvas.getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); - var ctx = canvas.getContext("2d"); - ctx.save(); - ctx.fillStyle = "rgb(255, 255, 255)"; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); + var gfx = new CanvasGraphics(ctx); + page.display(gfx); - var gfx = new CanvasGraphics(ctx); - page.display(gfx); + var t2 = Date.now(); + var infoDisplay = document.getElementById("info"); + infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms"; + } - var t2 = Date.now(); + // Loading a font via data uri is asynchronous, so wait for all font + // of the page to be fully loaded before loading the page + var fontsReady = true; + var fonts = page.fonts; + for (var i = 0; i < fonts.length; i++) { + var fontName = fonts[i].replace("+", "_"); + var font = Fonts[fontName]; + if (!font) { + // load the new font + var xref = page.xref; + var resources = xref.fetchIfRef(page.resources); + var fontResource = resources.get("Font"); + for (var id in fontResource.map) { + var res = xref.fetch(fontResource.get(id)); + var descriptor = xref.fetch(res.get("FontDescriptor")); + var name = descriptor.get("FontName").toString(); + if (name == fontName.replace("_", "+")) { + var subtype = res.get("Subtype").name; + var fontFile = page.xref.fetchIfRef(descriptor.get("FontFile")); + if (!fontFile) + fontFile = page.xref.fetchIfRef(descriptor.get("FontFile2")); + new Font(fontName, fontFile, subtype); + fontsReady = false; + break; + } + } + } else if (font.loading) { + fontsReady = false; + break; + } + } - var infoDisplay = document.getElementById("info"); - infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms"; + // If everything is ready do not delayed the page loading any more + if (fontsReady) + display(); + else + setTimeout(displayPage, 150, num); } function nextPage() { From f802ad05b2d9f1cd8dd81a9167eb9b87f48dba2d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 04:52:21 +0200 Subject: [PATCH 004/439] Fix an issue with the setTimeout method used for waiting for fonts to load --- test.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index bd6c812e8..8c561e8a6 100644 --- a/test.js +++ b/test.js @@ -1,7 +1,7 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ -var pdfDocument, canvas, pageDisplay, pageNum; +var pdfDocument, canvas, pageDisplay, pageNum, pageTimeout; function load() { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; @@ -47,6 +47,9 @@ function gotoPage(num) { } function displayPage(num) { + if (pageNum != num) + window.clearTimeout(pageTimeout); + document.getElementById("pageNumber").value = num; var t0 = Date.now(); @@ -104,8 +107,11 @@ function displayPage(num) { // If everything is ready do not delayed the page loading any more if (fontsReady) display(); - else - setTimeout(displayPage, 150, num); + else { + // FIXME Relying on an event seems much more cleaner here instead + // of a setTimeout... + pageTimeout = window.setTimeout(displayPage, 150, num); + } } function nextPage() { From 4cae2df1e59fe7312a93be04144bc09e0407c9f2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 11:08:08 +0200 Subject: [PATCH 005/439] Add support for ligatures, asterisks, etc. --- PDFFont.js | 69 ++++++++++++++++++++++++++++++++++-------------------- pdf.js | 8 +++---- test.html | 1 - test.js | 16 ++++++++++++- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 4e81187b9..509d714fe 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -9,7 +9,7 @@ var kMaxFontFileSize = 40000; /** * Maximum number of glyphs per font. */ -var kMaxGlyphsCount = 1024; +var kMaxGlyphsCount = 65526; /** * Maximum time to wait for a font to be loaded by @font-face @@ -28,33 +28,48 @@ var fontCount = 0; * TODO Add the standard fourteen Type1 fonts list by default * http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65 */ -var Fonts = {}; +var Fonts = { + _active: null, + get active() { + return this._active; + }, + + set active(aFontName) { + this._active = this[aFontName]; + }, + + getUnicodeFor: function fonts_getUnicodeFor(aCode) { + var glyph = this._active.encoding[aCode]; + var unicode = "0x" + GlyphsUnicode[glyph]; + return unicode || aCode; + } +}; /** * 'Font' is the class the outside world should use, it encapsulate all the font * decoding logics whatever type it is (assuming the font type is supported). * * For example to read a Type1 font and to attach it to the document: - * var type1Font = new Font("MyFontName", binaryData, "Type1"); + * var type1Font = new Font("MyFontName", binaryData, aFontEncoding, "Type1"); * type1Font.bind(); * * As an improvment the last parameter can be replaced by an automatic guess * of the font type based on the first byte of the file. */ -var Font = function(aFontName, aFontFile, aFontType) { - this.name = aFontName; +var Font = function(aName, aFile, aEncoding, aType) { + this.name = aName; // If the font has already been decoded simply return - if (Fonts[aFontName]) { - this.font = Fonts[aFontName].data; + if (Fonts[aName]) { + this.font = Fonts[aName].data; return; } fontCount++; var start = Date.now(); - switch (aFontType) { + switch (aType) { case "Type1": - var cff = new CFF(aFontName, aFontFile); + var cff = new CFF(aFile); this.mimetype = "font/otf"; // Wrap the CFF data inside an OTF font file @@ -63,18 +78,19 @@ var Font = function(aFontName, aFontFile, aFontType) { case "TrueType": this.mimetype = "font/ttf"; - var ttf = new TrueType(aFontName, aFontFile); + var ttf = new TrueType(aFile); this.font = ttf.data; break; default: - warn("Font " + aFontType + " is not supported"); + warn("Font " + aType + " is not supported"); break; } var end = Date.now(); - Fonts[aFontName] = { + Fonts[aName] = { data: this.font, + encoding: aEncoding, loading: true } @@ -108,11 +124,11 @@ Font.prototype = { var debug = false; var canvas = document.createElement("canvas"); - var style = "position:absolute; left: " + - (debug ? (100 * fontCount) : "-200") + "px; top: -200px;"; + var style = "position:absolute; top: " + + (debug ? (80 * fontCount) : "-200") + "px; left: 100px;"; canvas.setAttribute("style", style); canvas.setAttribute("width", 100); - canvas.setAttribute("heigth", 100); + canvas.setAttribute("heigth", 70); document.body.appendChild(canvas); // Get the first character of the font @@ -125,7 +141,7 @@ Font.prototype = { var res = xref.fetch(fontResource.get(id)); var descriptor = xref.fetch(res.get("FontDescriptor")); var name = descriptor.get("FontName").toString(); - var font = Fonts[name.replace("+", "_")]; + var font = Fonts[name.replace("+", "_")]; if (font && font.loading && name == fontName.replace("_", "+")) { charset = descriptor.get("CharSet").split("/"); break; @@ -174,7 +190,7 @@ Font.prototype = { } if (debug) - ctx.fillText(testString, 20, 60); + ctx.fillText(testString, 20, 50); }, 150, this); /** Hack end */ @@ -246,8 +262,9 @@ Font.prototype = { _createCMAPTable: function font_createCMAPTable(aGlyphs) { var characters = new Array(kMaxGlyphsCount); - for (var i = 0; i < aGlyphs.length; i++) + for (var i = 0; i < aGlyphs.length; i++) { characters[aGlyphs[i].unicode] = i + 1; + } // Separate the glyphs into continuous range of codes, aka segment. var ranges = []; @@ -377,10 +394,10 @@ Font.prototype = { 0x01, 0x02, // yStrikeOutPosition 0x00, 0x00, // sFamilyClass 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose - 0x00, 0x00, 0x00, 0x01, // ulUnicodeRange1 (Bits 0-31) - 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange2 (Bits 32-63) - 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange3 (Bits 64-95) - 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange4 (Bits 96-127) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) 0x2A, 0x32, 0x31, 0x2A, // achVendID 0x00, 0x20, // fsSelection 0x00, 0x2D, // usFirstCharIndex @@ -558,8 +575,8 @@ var FontsUtils = { * (near?) future this class will rewrite the font to ensure it is well formed * and valid in the point of view of the sanitizer. */ -var TrueType = function(aFontName, aFontFile) { - this.data = aFontFile; +var TrueType = function(aFile) { + this.data = aFile; }; /** @@ -1229,7 +1246,7 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { } }; -var CFF = function(aFontName, aFontFile) { +var CFF = function(aFontFile) { var start = Date.now(); var length1 = aFontFile.dict.get("Length1"); @@ -1405,7 +1422,7 @@ CFF.prototype = { var familyName = fontInfo.get("FamilyName"); var weight = fontInfo.get("Weight"); var strings = [version, notice, fullName, - familyName, weight, "asteriskmath"]; + familyName, weight]; var stringsIndex = this.createCFFIndexHeader(strings); var stringsDataLength = stringsIndex.length; diff --git a/pdf.js b/pdf.js index 697e6c3ad..1f42bd6d6 100644 --- a/pdf.js +++ b/pdf.js @@ -798,6 +798,8 @@ var Lexer = (function() { x = (x << 3) + (ch - '0'); } } + + x = Fonts.getUnicodeFor(x); str += String.fromCharCode(x); break; case '\r': @@ -1849,15 +1851,11 @@ var CanvasGraphics = (function() { return; var fontName = ""; - var subtype = font.get("Subtype").name; var fontDescriptor = font.get("FontDescriptor"); if (fontDescriptor.num) { var fontDescriptor = this.xref.fetchIfRef(fontDescriptor); - var fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile")); - if (!fontFile) - fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile2")); fontName = fontDescriptor.get("FontName").name.replace("+", "_"); - new Font(fontName, fontFile, subtype); + Fonts.active = fontName; } this.current.fontSize = size; diff --git a/test.html b/test.html index 73ba7d2db..8d649a149 100644 --- a/test.html +++ b/test.html @@ -1,5 +1,4 @@ -<<<<<<< HEAD Simple pdf.js page viewer diff --git a/test.js b/test.js index 8c561e8a6..f2fdcfdf7 100644 --- a/test.js +++ b/test.js @@ -93,7 +93,21 @@ function displayPage(num) { var fontFile = page.xref.fetchIfRef(descriptor.get("FontFile")); if (!fontFile) fontFile = page.xref.fetchIfRef(descriptor.get("FontFile2")); - new Font(fontName, fontFile, subtype); + + // Generate the custom cmap of the font + var encoding = xref.fetch(res.get("Encoding")); + var differences = encoding.get("Differences"); + var encodingMap = {}; + var index = 0; + for (var j = 0; j < differences.length; j++) { + var data = differences[j]; + if (IsNum(data)) + index = data; + else + encodingMap[index++] = data; + } + + new Font(fontName, fontFile, encodingMap, subtype); fontsReady = false; break; } From 6a6753fd5e1068684488f95d9a16e98cc3c9ee80 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 11:59:10 +0200 Subject: [PATCH 006/439] Add support for brackets around the header emails --- PDFFont.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 509d714fe..9c6c620bb 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -38,10 +38,14 @@ var Fonts = { this._active = this[aFontName]; }, - getUnicodeFor: function fonts_getUnicodeFor(aCode) { - var glyph = this._active.encoding[aCode]; - var unicode = "0x" + GlyphsUnicode[glyph]; - return unicode || aCode; + unicodeFromCode: function fonts_unicodeFromCode(aCode) { + var active = this._active; + if (!active) + return aCode; + + var difference = active.encoding[aCode]; + var unicode = GlyphsUnicode[difference]; + return unicode ? "0x" + unicode : aCode; } }; From 6364e7fad5a12ecaa280807d1f793f0118d2ec6d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 19:40:36 +0200 Subject: [PATCH 007/439] Forgot to push function calls changes to get the unicode char from a random code --- pdf.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 1f42bd6d6..bbfa7186a 100644 --- a/pdf.js +++ b/pdf.js @@ -799,7 +799,7 @@ var Lexer = (function() { } } - x = Fonts.getUnicodeFor(x); + x = Fonts.unicodeFromCode(x); str += String.fromCharCode(x); break; case '\r': @@ -815,7 +815,8 @@ var Lexer = (function() { } break; default: - str += ch; + var unicode = Fonts.unicodeFromCode(ch.charCodeAt(0)); + str += String.fromCharCode(unicode); break; } } while (!done); From 9fc97d94e84ca7eb67dfab24bd108cd275a00349 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 14 Jun 2011 11:55:27 -0700 Subject: [PATCH 008/439] Implemented type 2 shading for the pdf (aka gradients) --- pdf.js | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 194 insertions(+), 15 deletions(-) diff --git a/pdf.js b/pdf.js index 418db2462..87335317a 100644 --- a/pdf.js +++ b/pdf.js @@ -1911,14 +1911,19 @@ var CanvasGraphics = (function() { // Shading shadingFill: function(entryRef) { + if (!this.current.bbox) + TODO("bbox"); + var shadingRes = this.res.get("Shading"); if (!shadingRes) return; - shadingRes = this.xref.fetchIfRef(shadingRes); + + var xref = this.xref; + shadingRes = xref.fetchIfRef(shadingRes); var shading = shadingRes.get(entryRef.name); if (!shading) return; - shading = this.xref.fetchIfRef(shading); + shading = xref.fetchIfRef(shading); if (!shading) return; @@ -1931,8 +1936,13 @@ var CanvasGraphics = (function() { this.endPath(); } + var cs = shading.get2("ColorSpace", "CS"); TODO("shading-fill color space"); + var background = shading.get("Background"); + if (background) + TODO("handle background colors"); + var type = shading.get("ShadingType"); switch (type) { case 1: @@ -1952,10 +1962,10 @@ var CanvasGraphics = (function() { this.restore(); }, + fillAxialShading: function(sh) { - var coordsArr = sh.get("Coords"); - var x0 = coordsArr[0], y0 = coordsArr[1], - x1 = coordsArr[2], y1 = coordsArr[3]; + var cds = sh.get("Coords"); + var t0 = 0.0, t1 = 1.0; if (sh.has("Domain")) { @@ -1967,19 +1977,29 @@ var CanvasGraphics = (function() { if (sh.has("Extend")) { var extendArr = sh.get("Extend"); extendStart = extendArr[0], extendEnd = extendArr[1]; + TODO("Support extend"); + } + var fnObj = sh.get("Function"); + fnObj = this.xref.fetchIfRef(fnObj); + if (!IsFunction(fnObj)) + error("invalid function"); + fn = new Function(this.xref, fnObj); + + var gradient = this.ctx.createLinearGradient(cds[0], cds[1], cds[2], cds[3]); + var step = (t1 - t0) / 10; + + for (var i = t0; i <= t1; i += step) { + var c = fn.func([i]); + var clength = c.length; + for (var j = 0; j < clength; ++j) + c[j] = Math.round(c[j] * 255); + gradient.addColorStop(i, "rgb("+c[0] + "," + c[1] + "," + c[2] + ")"); } - var fn = sh.get("Function"); - fn = this.xref.fetchIfRef(fn); - - var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); - - gradient.addColorStop(0, 'rgb(0,0,255)'); - gradient.addColorStop(1, 'rgb(0,255,0)'); - this.ctx.fillStyle = gradient; - this.ctx.fill(); - this.consumePath(); + + // HACK to draw the gradient onto an infinite rectangle + this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); }, // XObjects @@ -2292,3 +2312,162 @@ var ColorSpace = (function() { return constructor; })(); + +var Function = (function() { + function constructor(xref, fn) { + var dict = fn.dict; + if (!dict) + dict = fn; + + var type = dict.get("FunctionType"); + + switch(type) { + case 0: + this.constructSampled(fn, dict); + break; + case 2: + this.constructInterpolated(); + break; + case 3: + this.constructStiched(); + break; + case 4: + this.constructPostScript(); + break; + default: + error("Unknown type of function"); + } + }; + + constructor.prototype = { + constructSampled: function(str, dict) { + var domain = dict.get("Domain"); + var range = dict.get("Range"); + + if (!domain || !range) + error("No domain or range"); + + var inputSize = domain.length / 2; + var outputSize = range.length / 2; + + if (inputSize != 1) + error("No support for multi-variable inputs to functions"); + + var size = dict.get("Size"); + var bps = dict.get("BitsPerSample"); + var order = dict.get("Order"); + if (!order) + order = 1; + if (order !== 1) + error ("No support for cubic spline interpolation"); + + var encode = dict.get("Encode"); + if (!encode) { + encode = []; + for (var i = 0; i < inputSize; ++i) { + encode.push(0); + encode.push(size[i] - 1); + } + } + var decode = dict.get("Decode"); + if (!decode) + decode = range; + + var samples = this.getSampleArray(size, outputSize, bps, str); + + this.func = function(args) { + var clip = function(v, min, max) { + if (v > max) + v = max; + else if (v < min) + v = min + return v; + } + + if (inputSize != args.length) + error("Incorrect number of arguments"); + + for (var i = 0; i < inputSize; i++) { + var i2 = i * 2; + + // clip to the domain + var v = clip(args[i], domain[i2], domain[i2 + 1]); + + // encode + v = encode[i2] + ((v - domain[i2]) * + (encode[i2 + 1] - encode[i2]) / + (domain[i2 + 1] - domain[i2])); + + // clip to the size + args[i] = clip(v, 0, size[i] - 1); + } + + // interpolate to table + TODO("Multi-dimensional interpolation"); + var floor = Math.floor(args[0]); + var ceil = Math.ceil(args[0]); + var scale = args[0] - floor; + + floor *= outputSize; + ceil *= outputSize; + + var output = []; + for (var i = 0; i < outputSize; ++i) { + if (ceil == floor) { + var v = samples[ceil + i]; + } else { + var low = samples[floor + i]; + var high = samples[ceil + i]; + var v = low * scale + high * (1 - scale); + } + + var i2 = i * 2; + // decode + v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) / + ((1 << bps) - 1)); + + // clip to the domain + output.push(clip(v, range[i2], range[i2 + 1])); + } + + return output; + } + }, + getSampleArray: function(size, outputSize, bps, str) { + var length = 1; + for (var i = 0; i < size.length; i++) + length *= size[i]; + length *= outputSize; + + var array = []; + var codeSize = 0; + var codeBuf = 0; + + var strBytes = str.getBytes((length * bps + 7) / 8); + var strIdx = 0; + for (var i = 0; i < length; i++) { + var b; + while (codeSize < bps) { + codeBuf <<= 8; + codeBuf |= strBytes[strIdx++]; + codeSize += 8; + } + codeSize -= bps + array.push(codeBuf >> codeSize); + codeBuf &= (1 << codeSize) - 1; + } + return array; + }, + constructInterpolated: function() { + error("unhandled type of function"); + }, + constructStiched: function() { + error("unhandled type of function"); + }, + constructPostScript: function() { + error("unhandled type of function"); + } + }; + + return constructor; +})(); From aa6d9f75a38996651f499362f67ce07110da80b5 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 14 Jun 2011 12:19:35 -0700 Subject: [PATCH 009/439] cleaned up code --- pdf.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index 87335317a..1910a216a 100644 --- a/pdf.js +++ b/pdf.js @@ -1911,9 +1911,6 @@ var CanvasGraphics = (function() { // Shading shadingFill: function(entryRef) { - if (!this.current.bbox) - TODO("bbox"); - var shadingRes = this.res.get("Shading"); if (!shadingRes) return; @@ -1965,8 +1962,7 @@ var CanvasGraphics = (function() { fillAxialShading: function(sh) { var cds = sh.get("Coords"); - - + var t0 = 0.0, t1 = 1.0; if (sh.has("Domain")) { var domainArr = sh.get("Domain"); @@ -1981,8 +1977,10 @@ var CanvasGraphics = (function() { } var fnObj = sh.get("Function"); fnObj = this.xref.fetchIfRef(fnObj); - if (!IsFunction(fnObj)) - error("invalid function"); + if (IsArray(fnObj)) + error("No support for array of functions"); + else if (!IsFunction(fnObj)) + error("Invalid function"); fn = new Function(this.xref, fnObj); var gradient = this.ctx.createLinearGradient(cds[0], cds[1], cds[2], cds[3]); From bd2e7561003e87a3a2bd4944fdb1127560c189ad Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 21:38:59 +0200 Subject: [PATCH 010/439] Add XObjects fonts to the list of page fonts and has a forEach method to the Dict class --- PDFFont.js | 13 ++++++++++++ pdf.js | 34 +++++++++++++++++++++++-------- test.js | 60 +++++++++++++++++++++++------------------------------- 3 files changed, 64 insertions(+), 43 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 9c6c620bb..56e93c19a 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -580,9 +580,22 @@ var FontsUtils = { * and valid in the point of view of the sanitizer. */ var TrueType = function(aFile) { + var header = this._readOpenTypeHeader(aFile); this.data = aFile; }; +TrueType.prototype = { + _readOpenTypeHeader: function(aFile) { + return { + version: aFile.getBytes(4), + numTables: FontsUtils.bytesToInteger(aFile.getBytes(2)), + searchRange: FontsUtils.bytesToInteger(aFile.getBytes(2)), + entrySelector: FontsUtils.bytesToInteger(aFile.getBytes(2)), + rangeShift: FontsUtils.bytesToInteger(aFile.getBytes(2)) + } + } +}; + /** * This dictionary holds decoded fonts data. */ diff --git a/pdf.js b/pdf.js index bbfa7186a..afcb39fff 100644 --- a/pdf.js +++ b/pdf.js @@ -563,6 +563,10 @@ var Dict = (function() { set: function(key, value) { this.map[key] = value; }, + forEach: function(aCallback) { + for (var key in this.map) + aCallback(key, this.map[key]); + }, toString: function() { var keys = []; for (var key in this.map) @@ -1404,16 +1408,30 @@ var Page = (function() { }, get fonts() { var xref = this.xref; - var fonts = []; - var resources = xref.fetchIfRef(this.resources); - var fontResource = resources.get("Font"); - for (var id in fontResource.map) { - var res = xref.fetch(fontResource.get(id)); - var descriptor = xref.fetch(res.get("FontDescriptor")); - fonts.push(descriptor.get("FontName").toString()); + var fontsDict = new Dict(); + + // Get the fonts use on the page + var fontResources = resources.get("Font"); + fontResources.forEach(function(fontKey, fontData) { + fontsDict.set(fontKey, xref.fetch(fontData)) + }); + + // Get the fonts use on xobjects of the page if any + var xobjs = xref.fetchIfRef(resources.get("XObject")); + if (xobjs) { + xobjs.forEach(function(key, xobj) { + xobj = xref.fetchIfRef(xobj); + assertWellFormed(IsStream(xobj), "XObject should be a stream"); + + var xobjFonts = xobj.dict.get("Resources").get("Font"); + xobjFonts.forEach(function(fontKey, fontData) { + fontsDict.set(fontKey, xref.fetch(fontData)) + }); + }); } - return shadow(this, "fonts", fonts); + + return shadow(this, "fonts", fontsDict); }, display: function(gfx) { var xref = this.xref; diff --git a/test.js b/test.js index f2fdcfdf7..071b2f097 100644 --- a/test.js +++ b/test.js @@ -76,47 +76,37 @@ function displayPage(num) { // of the page to be fully loaded before loading the page var fontsReady = true; var fonts = page.fonts; - for (var i = 0; i < fonts.length; i++) { - var fontName = fonts[i].replace("+", "_"); - var font = Fonts[fontName]; - if (!font) { - // load the new font - var xref = page.xref; - var resources = xref.fetchIfRef(page.resources); - var fontResource = resources.get("Font"); - for (var id in fontResource.map) { - var res = xref.fetch(fontResource.get(id)); - var descriptor = xref.fetch(res.get("FontDescriptor")); - var name = descriptor.get("FontName").toString(); - if (name == fontName.replace("_", "+")) { - var subtype = res.get("Subtype").name; - var fontFile = page.xref.fetchIfRef(descriptor.get("FontFile")); - if (!fontFile) - fontFile = page.xref.fetchIfRef(descriptor.get("FontFile2")); + var xref = page.xref; + fonts.forEach(function(fontKey, fontDict) { + var descriptor = xref.fetch(fontDict.get("FontDescriptor")); + var fontName = descriptor.get("FontName").name; + fontName = fontName.replace("+", "_"); - // Generate the custom cmap of the font - var encoding = xref.fetch(res.get("Encoding")); - var differences = encoding.get("Differences"); + // Check if the font has been loaded or is still loading + var font = Fonts[fontName]; + if (!font) { + var fontFile = xref.fetchIfRef(descriptor.get2("FontFile", "FontFile2")); + // Generate the custom cmap of the font if needed var encodingMap = {}; - var index = 0; - for (var j = 0; j < differences.length; j++) { - var data = differences[j]; - if (IsNum(data)) - index = data; - else - encodingMap[index++] = data; + if (fontDict.has("Encoding")) { + var encoding = xref.fetchIfRef(fontDict.get("Encoding")); + if (IsDict(encoding)) { + var differences = encoding.get("Differences"); + var index = 0; + for (var j = 0; j < differences.length; j++) { + var data = differences[j]; + IsNum(data) ? index = data : encodingMap[index++] = data; + } + } } + var subtype = fontDict.get("Subtype").name; new Font(fontName, fontFile, encodingMap, subtype); - fontsReady = false; - break; - } + return fontsReady = false; + } else if (font.loading) { + return fontsReady = false; } - } else if (font.loading) { - fontsReady = false; - break; - } - } + }); // If everything is ready do not delayed the page loading any more if (fontsReady) From c8c4326ca870de68b56698433198c00ebb418e89 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 14 Jun 2011 21:51:11 +0200 Subject: [PATCH 011/439] Remove direct access to the underlying map object of dict in the fonts builder --- PDFFont.js | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 56e93c19a..58c61e051 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -135,25 +135,25 @@ Font.prototype = { canvas.setAttribute("heigth", 70); document.body.appendChild(canvas); - // Get the first character of the font + // Retrieve font charset + var charset = null; var page = pdfDocument.getPage(pageNum); var xref = page.xref; - var resources = xref.fetchIfRef(page.resources); - var fontResource = resources.get("Font"); - var charset = ""; - for (var id in fontResource.map) { - var res = xref.fetch(fontResource.get(id)); - var descriptor = xref.fetch(res.get("FontDescriptor")); + + var fonts = page.fonts; + fonts.forEach(function(fontKey, fontData) { + var descriptor = xref.fetch(fontData.get("FontDescriptor")); var name = descriptor.get("FontName").toString(); var font = Fonts[name.replace("+", "_")]; if (font && font.loading && name == fontName.replace("_", "+")) { - charset = descriptor.get("CharSet").split("/"); - break; + charset = descriptor.get("CharSet"); + charset = charset ? charset.split("/") : null; + return; } - } + }); - // Warn if the charset is not found, this is likely a bug! - var testCharset = charset; + // Warn if the charset is not found, this is likely + var testCharset = charset || []; if (!charset) { warn("No charset found for: " + fontName); } else { @@ -1358,26 +1358,26 @@ CFF.prototype = { }, getOrderedCharStrings: function(aFont) { - var dict = aFont.get("CharStrings") var charstrings = []; - for (var glyph in dict.map) { + + var glyphs = aFont.get("CharStrings") + glyphs.forEach(function(glyph, glyphData) { var unicode = GlyphsUnicode[glyph]; if (!unicode) { if (glyph != ".notdef") warn(glyph + " does not have an entry in the glyphs unicode dictionary"); - continue; + } else { + var b1 = parseInt("0x" + unicode[0] + unicode[1]); + var b2 = parseInt("0x" + unicode[2] + unicode[3]); + unicode = FontsUtils.bytesToInteger([b1, b2]); + + charstrings.push({ + glyph: glyph, + unicode: unicode, + charstring: glyphData.slice() + }); } - - var b1 = parseInt("0x" + unicode[0] + unicode[1]); - var b2 = parseInt("0x" + unicode[2] + unicode[3]); - unicode = FontsUtils.bytesToInteger([b1, b2]); - - charstrings.push({ - glyph: glyph, - unicode: unicode, - charstring: dict.map[glyph].slice() - }); - } + }); charstrings.sort(function(a, b) { return a.unicode > b.unicode; From b7360823a2bc4df527f2ac84a852431909b15566 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 14 Jun 2011 13:49:50 -0700 Subject: [PATCH 012/439] Cleaned up code, renamed PDFFunction class --- pdf.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index 1910a216a..0beb5e22e 100644 --- a/pdf.js +++ b/pdf.js @@ -1961,7 +1961,9 @@ var CanvasGraphics = (function() { }, fillAxialShading: function(sh) { - var cds = sh.get("Coords"); + var coordsArr = sh.get("Coords"); + var x0 = coordsArr[0], y0 = coordsArr[1], + x1 = coordsArr[2], y1 = coordsArr[3]; var t0 = 0.0, t1 = 1.0; if (sh.has("Domain")) { @@ -1981,17 +1983,14 @@ var CanvasGraphics = (function() { error("No support for array of functions"); else if (!IsFunction(fnObj)) error("Invalid function"); - fn = new Function(this.xref, fnObj); + fn = new PDFFunction(this.xref, fnObj); - var gradient = this.ctx.createLinearGradient(cds[0], cds[1], cds[2], cds[3]); + var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); var step = (t1 - t0) / 10; for (var i = t0; i <= t1; i += step) { var c = fn.func([i]); - var clength = c.length; - for (var j = 0; j < clength; ++j) - c[j] = Math.round(c[j] * 255); - gradient.addColorStop(i, "rgb("+c[0] + "," + c[1] + "," + c[2] + ")"); + gradient.addColorStop(i, this.makeCssRgb.apply(this,c)); } this.ctx.fillStyle = gradient; @@ -2311,7 +2310,7 @@ var ColorSpace = (function() { return constructor; })(); -var Function = (function() { +var PDFFunction = (function() { function constructor(xref, fn) { var dict = fn.dict; if (!dict) From b9771416babf470c39d9718f92939429a7db960e Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 18:31:14 -0700 Subject: [PATCH 013/439] compile PDF command streams into JS code --- pdf.js | 136 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 54 deletions(-) diff --git a/pdf.js b/pdf.js index 418db2462..bea42ad2e 100644 --- a/pdf.js +++ b/pdf.js @@ -1395,8 +1395,7 @@ var Page = (function() { gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], width: mediaBox[2] - mediaBox[0], height: mediaBox[3] - mediaBox[1] }); - gfx.interpret(new Parser(new Lexer(contents), false), - xref, resources); + gfx.execute(contents, xref, resources); gfx.endDrawing(); } }; @@ -1605,65 +1604,65 @@ var CanvasGraphics = (function() { this.xobjs = null; this.map = { // Graphics state - w: this.setLineWidth, - J: this.setLineCap, - j: this.setLineJoin, - d: this.setDash, - ri: this.setRenderingIntent, - i: this.setFlatness, - gs: this.setGState, - q: this.save, - Q: this.restore, - cm: this.transform, + w: "setLineWidth", + J: "setLineCap", + j: "setLineJoin", + d: "setDash", + ri: "setRenderingIntent", + i: "setFlatness", + gs: "setGState", + q: "save", + Q: "restore", + cm: "transform", // Path - m: this.moveTo, - l: this.lineTo, - c: this.curveTo, - h: this.closePath, - re: this.rectangle, - S: this.stroke, - f: this.fill, - "f*": this.eoFill, - B: this.fillStroke, - b: this.closeFillStroke, - n: this.endPath, + m: "moveTo", + l: "lineTo", + c: "curveTo", + h: "closePath", + re: "rectangle", + S: "stroke", + f: "fill", + "f*": "eoFill", + B: "fillStroke", + b: "closeFillStroke", + n: "endPath", // Clipping - W: this.clip, - "W*": this.eoClip, + W: "clip", + "W*": "eoClip", // Text - BT: this.beginText, - ET: this.endText, - TL: this.setLeading, - Tf: this.setFont, - Td: this.moveText, - Tm: this.setTextMatrix, - "T*": this.nextLine, - Tj: this.showText, - TJ: this.showSpacedText, + BT: "beginText", + ET: "endText", + TL: "setLeading", + Tf: "setFont", + Td: "moveText", + Tm: "setTextMatrix", + "T*": "nextLine", + Tj: "showText", + TJ: "showSpacedText", // Type3 fonts // Color - CS: this.setStrokeColorSpace, - cs: this.setFillColorSpace, - SC: this.setStrokeColor, - SCN: this.setStrokeColorN, - sc: this.setFillColor, - scn: this.setFillColorN, - G: this.setStrokeGray, - g: this.setFillGray, - RG: this.setStrokeRGBColor, - rg: this.setFillRGBColor, + CS: "setStrokeColorSpace", + cs: "setFillColorSpace", + SC: "setStrokeColor", + SCN: "setStrokeColorN", + sc: "setFillColor", + scn: "setFillColorN", + G: "setStrokeGray", + g: "setFillGray", + RG: "setStrokeRGBColor", + rg: "setFillRGBColor", // Shading - sh: this.shadingFill, + sh: "shadingFill", // Images // XObjects - Do: this.paintXObject, + Do: "paintXObject", // Marked content // Compatibility @@ -1683,13 +1682,38 @@ var CanvasGraphics = (function() { this.ctx.translate(0, -mediaBox.height); }, - interpret: function(parser, xref, resources) { + execute: function(stream, xref, resources) { + if (!stream.execute) + this.compile(stream, xref, resources); + var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; this.xref = xref; this.res = resources || new Dict(); this.xobjs = this.res.get("XObject") || new Dict(); this.xobjs = this.xref.fetchIfRef(this.xobjs); + stream.execute(this, stream.objpool); + + this.xobjs = savedXobjs; + this.res = savedRes; + this.xref = savedXref; + }, + + compile: function(stream, xref, resources) { + var parser = new Parser(new Lexer(stream), false); + var objpool = []; + + function emitArg(arg) { + if (typeof arg == "object" || typeof arg == "string") { + var index = objpool.length; + objpool[index] = arg; + return "objpool[" + index + "]"; + } + return arg; + } + + var src = "{\n"; + var args = []; var map = this.map; var obj; @@ -1699,7 +1723,12 @@ var CanvasGraphics = (function() { var fn = map[cmd]; assertWellFormed(fn, "Unknown command '" + cmd + "'"); // TODO figure out how to type-check vararg functions - fn.apply(this, args); + + src += "gfx."; + src += fn; + src += "("; + src += args.map(emitArg).join(","); + src += ");\n"; args.length = 0; } else { @@ -1708,9 +1737,10 @@ var CanvasGraphics = (function() { } } - this.xobjs = savedXobjs; - this.res = savedRes; - this.xref = savedXref; + src += "}"; + + stream.execute = new Function("gfx", "objpool", src); + stream.objpool = objpool; }, endDrawing: function() { @@ -2026,9 +2056,7 @@ var CanvasGraphics = (function() { this.clip(); this.endPath(); } - - this.interpret(new Parser(new Lexer(form), false), - this.xref, form.dict.get("Resources")); + this.execute(form, this.xref, form.dict.get("Resources")); this.restore(); }, From 1dcd42b66c3dd3fadcc4fca66f4d8908f26d5645 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 15 Jun 2011 04:46:48 +0200 Subject: [PATCH 014/439] Add a basic support for TrueType (generate fonts with OS/2 table) --- PDFFont.js | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++- pdf.js | 18 +++-- test.js | 4 +- 3 files changed, 246 insertions(+), 9 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 58c61e051..fd7e0d86f 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -581,11 +581,213 @@ var FontsUtils = { */ var TrueType = function(aFile) { var header = this._readOpenTypeHeader(aFile); - this.data = aFile; + var numTables = header.numTables; + + // Check that required tables are present + var requiredTables = [ + "OS/2", + "cmap", + "head", + "hhea", + "hmtx", + "maxp", + "name", + "post" + ]; + + var tables = []; + for (var i = 0; i < numTables; i++) { + var table = this._readTableEntry(aFile); + var index = requiredTables.indexOf(table.tag); + if (index != -1) + requiredTables.splice(index, 1); + + tables.push(table); + } + tables.sort(function(a, b) { + return a.tag > b.tag; + }); + + // If any tables are still in the array this means some required tables are + // missing, which means that we need to rebuild the font in order to pass + // the sanitizer. + if (requiredTables.length && requiredTables[0] == "OS/2") { + OS2 = [ + 0x00, 0x03, // version + 0x02, 0x24, // xAvgCharWidth + 0x01, 0xF4, // usWeightClass + 0x00, 0x05, // usWidthClass + 0x00, 0x00, // fstype + 0x02, 0x8A, // ySubscriptXSize + 0x02, 0xBB, // ySubscriptYSize + 0x00, 0x00, // ySubscriptXOffset + 0x00, 0x8C, // ySubscriptYOffset + 0x02, 0x8A, // ySuperScriptXSize + 0x02, 0xBB, // ySuperScriptYSize + 0x00, 0x00, // ySuperScriptXOffset + 0x01, 0xDF, // ySuperScriptYOffset + 0x00, 0x31, // yStrikeOutSize + 0x01, 0x02, // yStrikeOutPosition + 0x00, 0x00, // sFamilyClass + 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) + 0x2A, 0x32, 0x31, 0x2A, // achVendID + 0x00, 0x20, // fsSelection + 0x00, 0x2D, // usFirstCharIndex + 0x00, 0x7A, // usLastCharIndex + 0x00, 0x03, // sTypoAscender + 0x00, 0x20, // sTypeDescender + 0x00, 0x38, // sTypoLineGap + 0x00, 0x5A, // usWinAscent + 0x02, 0xB4, // usWinDescent + 0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31) + 0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63) + 0x00, 0x00, // sxHeight + 0x00, 0x00, // sCapHeight + 0x00, 0x01, // usDefaultChar + 0x00, 0xCD, // usBreakChar + 0x00, 0x02 // usMaxContext + ]; + + // Create a new file to hold the new version of our truetype with a new + // header and new offsets + var stream = aFile.stream || aFile; + var ttf = new Uint8Array(stream.length + 16 + OS2.length); + + // The new numbers of tables will be the last one plus the num of missing + // tables + var numTables = header.numTables + 1; + + // The offsets object holds at the same time a representation of where + // to write the table entry information about a table and another offset + // representing the offset where to draw the actual data of a particular + // table + var offsets = { + currentOffset: 0, + virtualOffset: numTables * (4 * 4) + }; + + // Write the sfnt header with one more table + this._createOpenTypeHeader(ttf, offsets, numTables); + + // Insert the missing table + tables.unshift({ + tag: "OS/2", + data: OS2 + }); + + // rewrite the tables but tweak offsets + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var data = []; + + var tableData = table.data; + for (var j = 0; j < tableData.length; j++) + data.push(tableData[j]); + this._createTableEntry(ttf, offsets, table.tag, data); + } + + // Add the table datas + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var tableData = table.data; + ttf.set(tableData, offsets.currentOffset); + offsets.currentOffset += tableData.length; + + if (0) { + var data = []; + for (var j = 0; j < tableData.length; j++) + d.push(tableData[j]); + log("data for table: " + table.tag + ": " + data); + } + + // 4-byte aligned data + while (offsets.currentOffset & 3) + offsets.currentOffset++; + } + + var fontData = []; + for (var i = 0; i < ttf.length; i++) + fontData.push(ttf[i]); + + this.data = ttf; + //writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".ttf"); + return; + } else if (requiredTables.lenght) { + error("Table " + requiredTables[0] + " is missing from the TruType font"); + } else { + this.data = aFile; + } }; TrueType.prototype = { - _readOpenTypeHeader: function(aFile) { + _createOpenTypeHeader: function tt_createOpenTypeHeader(aFile, aOffsets, aNumTables) { + // sfnt version (4 bytes) + // XXX if we want to merge this function and the one from the Font class + // XXX this need to be adapted + var version = [0x00, 0x01, 0x00, 0X00]; + + // numTables (2 bytes) + var numTables = aNumTables; + + // searchRange (2 bytes) + var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); + var searchRange = tablesMaxPower2 * 16; + + // entrySelector (2 bytes) + var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); + + // rangeShift (2 bytes) + var rangeShift = numTables * 16 - searchRange; + + var header = [].concat(version, + FontsUtils.integerToBytes(numTables, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(entrySelector, 2), + FontsUtils.integerToBytes(rangeShift, 2)); + aFile.set(header, aOffsets.currentOffset); + aOffsets.currentOffset += header.length; + aOffsets.virtualOffset += header.length; + }, + + _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) { + // tag + var tag = [ + aTag.charCodeAt(0), + aTag.charCodeAt(1), + aTag.charCodeAt(2), + aTag.charCodeAt(3) + ]; + + // Per spec tables must be 4-bytes align so add some 0x00 if needed + while (aData.length & 3) + aData.push(0x00); + + while (aOffsets.virtualOffset & 3) + aOffsets.virtualOffset++; + + // offset + var offset = aOffsets.virtualOffset; + + // length + var length = aData.length; + + // checksum + var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + + var tableEntry = [].concat(tag, + FontsUtils.integerToBytes(checksum, 4), + FontsUtils.integerToBytes(offset, 4), + FontsUtils.integerToBytes(length, 4)); + aFile.set(tableEntry, aOffsets.currentOffset); + aOffsets.currentOffset += tableEntry.length; + aOffsets.virtualOffset += aData.length; + }, + + _readOpenTypeHeader: function tt_readOpenTypeHeader(aFile) { return { version: aFile.getBytes(4), numTables: FontsUtils.bytesToInteger(aFile.getBytes(2)), @@ -593,6 +795,33 @@ TrueType.prototype = { entrySelector: FontsUtils.bytesToInteger(aFile.getBytes(2)), rangeShift: FontsUtils.bytesToInteger(aFile.getBytes(2)) } + }, + + _readTableEntry: function tt_readTableEntry(aFile) { + // tag + var tag = aFile.getBytes(4); + tag = String.fromCharCode(tag[0]) + + String.fromCharCode(tag[1]) + + String.fromCharCode(tag[2]) + + String.fromCharCode(tag[3]); + + var checksum = FontsUtils.bytesToInteger(aFile.getBytes(4)); + var offset = FontsUtils.bytesToInteger(aFile.getBytes(4)); + var length = FontsUtils.bytesToInteger(aFile.getBytes(4)); + + // Read the table associated data + var currentPosition = aFile.pos; + aFile.pos = aFile.start + offset; + var data = aFile.getBytes(length); + aFile.pos = currentPosition; + + return { + tag: tag, + checksum: checksum, + length: offset, + offset: length, + data: data + } } }; diff --git a/pdf.js b/pdf.js index afcb39fff..f46362f7f 100644 --- a/pdf.js +++ b/pdf.js @@ -52,7 +52,7 @@ var Stream = (function() { this.bytes = new Uint8Array(arrayBuffer); this.start = start || 0; this.pos = this.start; - this.end = (start + length) || arrayBuffer.byteLength; + this.end = (start + length) || this.bytes.byteLength; this.dict = dict; } @@ -1411,11 +1411,13 @@ var Page = (function() { var resources = xref.fetchIfRef(this.resources); var fontsDict = new Dict(); - // Get the fonts use on the page + // Get the fonts use on the page if any var fontResources = resources.get("Font"); - fontResources.forEach(function(fontKey, fontData) { - fontsDict.set(fontKey, xref.fetch(fontData)) - }); + if (IsDict(fontResources)) { + fontResources.forEach(function(fontKey, fontData) { + fontsDict.set(fontKey, xref.fetch(fontData)) + }); + } // Get the fonts use on xobjects of the page if any var xobjs = xref.fetchIfRef(resources.get("XObject")); @@ -1864,7 +1866,11 @@ var CanvasGraphics = (function() { this.current.leading = leading; }, setFont: function(fontRef, size) { - var font = this.res.get("Font").get(fontRef.name); + var font = this.res.get("Font"); + if (!IsDict(font)) + return; + + font = font.get(fontRef.name); font = this.xref.fetchIfRef(font); if (!font) return; diff --git a/test.js b/test.js index 071b2f097..2b99dc136 100644 --- a/test.js +++ b/test.js @@ -85,7 +85,9 @@ function displayPage(num) { // Check if the font has been loaded or is still loading var font = Fonts[fontName]; if (!font) { - var fontFile = xref.fetchIfRef(descriptor.get2("FontFile", "FontFile2")); + var fontFile = descriptor.get2("FontFile", "FontFile2"); + fontFile = xref.fetchIfRef(fontFile); + // Generate the custom cmap of the font if needed var encodingMap = {}; if (fontDict.has("Encoding")) { From aecc4ebbb742b4724922853bf57c1e06ff8c7315 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 20:36:45 -0700 Subject: [PATCH 015/439] return ready-to-run closure from compile that captures its objpool --- pdf.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdf.js b/pdf.js index bea42ad2e..20299909e 100644 --- a/pdf.js +++ b/pdf.js @@ -1684,7 +1684,7 @@ var CanvasGraphics = (function() { execute: function(stream, xref, resources) { if (!stream.execute) - this.compile(stream, xref, resources); + stream.execute = this.compile(stream, xref, resources); var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; this.xref = xref; @@ -1692,7 +1692,7 @@ var CanvasGraphics = (function() { this.xobjs = this.res.get("XObject") || new Dict(); this.xobjs = this.xref.fetchIfRef(this.xobjs); - stream.execute(this, stream.objpool); + stream.execute(this); this.xobjs = savedXobjs; this.res = savedRes; @@ -1724,7 +1724,7 @@ var CanvasGraphics = (function() { assertWellFormed(fn, "Unknown command '" + cmd + "'"); // TODO figure out how to type-check vararg functions - src += "gfx."; + src += "this."; src += fn; src += "("; src += args.map(emitArg).join(","); @@ -1739,8 +1739,8 @@ var CanvasGraphics = (function() { src += "}"; - stream.execute = new Function("gfx", "objpool", src); - stream.objpool = objpool; + var fn = new Function("objpool", src); + return function (gfx) { fn.call(gfx, objpool); }; }, endDrawing: function() { From f7e90f569c989fc5e317a242df3a91d68eb515a2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 15 Jun 2011 05:40:54 +0200 Subject: [PATCH 016/439] Add Encodings.js and change the code to generate a CharSet per font, this will allow future changes to the OpenType font generator --- Encodings.js | 1552 ++++++++++++++++++++++++++++++++++++++++++++++++++ PDFFont.js | 46 +- test.html | 1 + test.js | 19 +- 4 files changed, 1584 insertions(+), 34 deletions(-) create mode 100644 Encodings.js diff --git a/Encodings.js b/Encodings.js new file mode 100644 index 000000000..d32a399c8 --- /dev/null +++ b/Encodings.js @@ -0,0 +1,1552 @@ + +var Encodings = { + ExpertEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "space", + "exclamsmall", + "Hungarumlautsmall", + null, + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + null, + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + null, + null, + null, + "isuperior", + null, + null, + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + null, + null, + "rsuperior", + "ssuperior", + "tsuperior", + null, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + null, + "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", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + null, + null, + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + null, + "Dotaccentsmall", + null, + null, + "Macronsmall", + null, + null, + "figuredash", + "hypheninferior", + null, + null, + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + null, + null, + null, + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + null, + null, + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "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" + ], + MacExpertEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "space", + "exclamsmall", + "Hungarumlautsmall", + "centoldstyle", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + null, + "threequartersemdash", + null, + "questionsmall", + null, + null, + null, + null, + "Ethsmall", + null, + null, + "onequarter", + "onehalf", + "threequarters", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + null, + null, + null, + null, + null, + null, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + null, + "parenrightinferior", + "Circumflexsmall", + "hypheninferior", + "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", + null, + null, + "asuperior", + "centsuperior", + null, + null, + null, + null, + "Aacutesmall", + "Agravesmall", + "Acircumflexsmall", + "Adieresissmall", + "Atildesmall", + "Aringsmall", + "Ccedillasmall", + "Eacutesmall", + "Egravesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Iacutesmall", + "Igravesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ntildesmall", + "Oacutesmall", + "Ogravesmall", + "Ocircumflexsmall", + "Odieresissmall", + "Otildesmall", + "Uacutesmall", + "Ugravesmall", + "Ucircumflexsmall", + "Udieresissmall", + null, + "eightsuperior", + "fourinferior", + "threeinferior", + "sixinferior", + "eightinferior", + "seveninferior", + "Scaronsmall", + null, + "centinferior", + "twoinferior", + null, + "Dieresissmall", + null, + "Caronsmall", + "osuperior", + "fiveinferior", + null, + "commainferior", + "periodinferior", + "Yacutesmall", + null, + "dollarinferior", + null, + null, + "Thornsmall", + null, + "nineinferior", + "zeroinferior", + "Zcaronsmall", + "AEsmall", + "Oslashsmall", + "questiondownsmall", + "oneinferior", + "Lslashsmall", + null, + null, + null, + null, + null, + null, + "Cedillasmall", + null, + null, + null, + null, + null, + "OEsmall", + "figuredash", + "hyphensuperior", + null, + null, + null, + null, + "exclamdownsmall", + null, + "Ydieresissmall", + null, + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "ninesuperior", + "zerosuperior", + null, + "esuperior", + "rsuperior", + "tsuperior", + null, + null, + "isuperior", + "ssuperior", + "dsuperior", + null, + null, + null, + null, + null, + "lsuperior", + "Ogoneksmall", + "Brevesmall", + "Macronsmall", + "bsuperior", + "nsuperior", + "msuperior", + "commasuperior", + "periodsuperior", + "Dotaccentsmall", + "Ringsmall", + null, + null, + null, + null + ], + MacRomanEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "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", + "grave", + "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", + null, + "Adieresis", + "Aring", + "Ccedilla", + "Eacute", + "Ntilde", + "Odieresis", + "Udieresis", + "aacute", + "agrave", + "acircumflex", + "adieresis", + "atilde", + "aring", + "ccedilla", + "eacute", + "egrave", + "ecircumflex", + "edieresis", + "iacute", + "igrave", + "icircumflex", + "idieresis", + "ntilde", + "oacute", + "ograve", + "ocircumflex", + "odieresis", + "otilde", + "uacute", + "ugrave", + "ucircumflex", + "udieresis", + "dagger", + "degree", + "cent", + "sterling", + "section", + "bullet", + "paragraph", + "germandbls", + "registered", + "copyright", + "trademark", + "acute", + "dieresis", + "notequal", + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu", + "partialdiff", + "summation", + "product", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Omega", + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "Delta", + "guillemotleft", + "guillemotright", + "ellipsis", + "space", + "Agrave", + "Atilde", + "Otilde", + "OE", + "oe", + "endash", + "emdash", + "quotedblleft", + "quotedblright", + "quoteleft", + "quoteright", + "divide", + "lozenge", + "ydieresis", + "Ydieresis", + "fraction", + "currency", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "daggerdbl", + "periodcentered", + "quotesinglbase", + "quotedblbase", + "perthousand", + "Acircumflex", + "Ecircumflex", + "Aacute", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Oacute", + "Ocircumflex", + "apple", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron" + ], + StandardEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "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", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + null, + "endash", + "dagger", + "daggerdbl", + "periodcentered", + null, + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + null, + "questiondown", + null, + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + null, + "ring", + "cedilla", + null, + "hungarumlaut", + "ogonek", + "caron", + "emdash", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "AE", + null, + "ordfeminine", + null, + null, + null, + null, + "Lslash", + "Oslash", + "OE", + "ordmasculine", + null, + null, + null, + null, + null, + "ae", + null, + null, + null, + "dotlessi", + null, + null, + "lslash", + "oslash", + "oe", + "germandbls", + null, + null, + null, + null + ], + WinAnsiEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "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", + "grave", + "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", + "bullet", + "Euro", + "bullet", + "quotesinglbase", + "florin", + "quotedblbase", + "ellipsis", + "dagger", + "daggerdbl", + "circumflex", + "perthousand", + "Scaron", + "guilsinglleft", + "OE", + "bullet", + "Zcaron", + "bullet", + "bullet", + "quoteleft", + "quoteright", + "quotedblleft", + "quotedblright", + "bullet", + "endash", + "emdash", + "tilde", + "trademark", + "scaron", + "guilsinglright", + "oe", + "bullet", + "zcaron", + "Ydieresis", + "space", + "exclamdown", + "cent", + "sterling", + "currency", + "yen", + "brokenbar", + "section", + "dieresis", + "copyright", + "ordfeminine", + "guillemotleft", + "logicalnot", + "hyphen", + "registered", + "macron", + "degree", + "plusminus", + "twosuperior", + "threesuperior", + "acute", + "mu", + "paragraph", + "periodcentered", + "cedilla", + "onesuperior", + "ordmasculine", + "guillemotright", + "onequarter", + "onehalf", + "threequarters", + "questiondown", + "Agrave", + "Aacute", + "Acircumflex", + "Atilde", + "Adieresis", + "Aring", + "AE", + "Ccedilla", + "Egrave", + "Eacute", + "Ecircumflex", + "Edieresis", + "Igrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Eth", + "Ntilde", + "Ograve", + "Oacute", + "Ocircumflex", + "Otilde", + "Odieresis", + "multiply", + "Oslash", + "Ugrave", + "Uacute", + "Ucircumflex", + "Udieresis", + "Yacute", + "Thorn", + "germandbls", + "agrave", + "aacute", + "acircumflex", + "atilde", + "adieresis", + "aring", + "ae", + "ccedilla", + "egrave", + "eacute", + "ecircumflex", + "edieresis", + "igrave", + "iacute", + "icircumflex", + "idieresis", + "eth", + "ntilde", + "ograve", + "oacute", + "ocircumflex", + "otilde", + "odieresis", + "divide", + "oslash", + "ugrave", + "uacute", + "ucircumflex", + "udieresis", + "yacute", + "thorn", + "ydieresis" + ], + zapfDingbatsEncoding: [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "space", + "a1", + "a2", + "a202", + "a3", + "a4", + "a5", + "a119", + "a118", + "a117", + "a11", + "a12", + "a13", + "a14", + "a15", + "a16", + "a105", + "a17", + "a18", + "a19", + "a20", + "a21", + "a22", + "a23", + "a24", + "a25", + "a26", + "a27", + "a28", + "a6", + "a7", + "a8", + "a9", + "a10", + "a29", + "a30", + "a31", + "a32", + "a33", + "a34", + "a35", + "a36", + "a37", + "a38", + "a39", + "a40", + "a41", + "a42", + "a43", + "a44", + "a45", + "a46", + "a47", + "a48", + "a49", + "a50", + "a51", + "a52", + "a53", + "a54", + "a55", + "a56", + "a57", + "a58", + "a59", + "a60", + "a61", + "a62", + "a63", + "a64", + "a65", + "a66", + "a67", + "a68", + "a69", + "a70", + "a71", + "a72", + "a73", + "a74", + "a203", + "a75", + "a204", + "a76", + "a77", + "a78", + "a79", + "a81", + "a82", + "a83", + "a84", + "a97", + "a98", + "a99", + "a100", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "a101", + "a102", + "a103", + "a104", + "a106", + "a107", + "a108", + "a112", + "a111", + "a110", + "a109", + "a120", + "a121", + "a122", + "a123", + "a124", + "a125", + "a126", + "a127", + "a128", + "a129", + "a130", + "a131", + "a132", + "a133", + "a134", + "a135", + "a136", + "a137", + "a138", + "a139", + "a140", + "a141", + "a142", + "a143", + "a144", + "a145", + "a146", + "a147", + "a148", + "a149", + "a150", + "a151", + "a152", + "a153", + "a154", + "a155", + "a156", + "a157", + "a158", + "a159", + "a160", + "a161", + "a163", + "a164", + "a196", + "a165", + "a192", + "a166", + "a167", + "a168", + "a169", + "a170", + "a171", + "a172", + "a173", + "a162", + "a174", + "a175", + "a176", + "a177", + "a178", + "a179", + "a193", + "a180", + "a199", + "a181", + "a200", + "a182", + null, + "a201", + "a183", + "a184", + "a197", + "a185", + "a194", + "a198", + "a186", + "a195", + "a187", + "a188", + "a189", + "a190", + "a191", + null + ] +}; + diff --git a/PDFFont.js b/PDFFont.js index fd7e0d86f..ff06c5e4e 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -40,7 +40,7 @@ var Fonts = { unicodeFromCode: function fonts_unicodeFromCode(aCode) { var active = this._active; - if (!active) + if (!active || !active.encoding) return aCode; var difference = active.encoding[aCode]; @@ -60,7 +60,7 @@ var Fonts = { * As an improvment the last parameter can be replaced by an automatic guess * of the font type based on the first byte of the file. */ -var Font = function(aName, aFile, aEncoding, aType) { +var Font = function(aName, aFile, aEncoding, aCharset, aType) { this.name = aName; // If the font has already been decoded simply return @@ -95,6 +95,7 @@ var Font = function(aName, aFile, aEncoding, aType) { Fonts[aName] = { data: this.font, encoding: aEncoding, + charset: aCharset ? aCharset.slice() : null, loading: true } @@ -125,10 +126,10 @@ Font.prototype = { // Actually there is not event when a font has finished downloading so // the following tons of code are a dirty hack to 'guess' when a font is // ready - var debug = false; + var debug = true; var canvas = document.createElement("canvas"); - var style = "position:absolute; top: " + + var style = "border: 1px solid black; position:absolute; top: " + (debug ? (80 * fontCount) : "-200") + "px; left: 100px;"; canvas.setAttribute("style", style); canvas.setAttribute("width", 100); @@ -136,40 +137,19 @@ Font.prototype = { document.body.appendChild(canvas); // Retrieve font charset - var charset = null; - var page = pdfDocument.getPage(pageNum); - var xref = page.xref; - - var fonts = page.fonts; - fonts.forEach(function(fontKey, fontData) { - var descriptor = xref.fetch(fontData.get("FontDescriptor")); - var name = descriptor.get("FontName").toString(); - var font = Fonts[name.replace("+", "_")]; - if (font && font.loading && name == fontName.replace("_", "+")) { - charset = descriptor.get("CharSet"); - charset = charset ? charset.split("/") : null; - return; - } - }); - - // Warn if the charset is not found, this is likely - var testCharset = charset || []; - if (!charset) { - warn("No charset found for: " + fontName); - } else { - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && testCharset.length <= 30) - testCharset = testCharset.concat(charset.slice()); - } + var charset = Fonts[fontName].charset || []; + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); // Get the font size canvas think it will be var ctx = canvas.getContext("2d"); var testString = ""; - for (var i = 0; i < testCharset.length; i++) { - var unicode = new Number("0x" + GlyphsUnicode[testCharset[i]]); + for (var i = 0; i < charset.length; i++) { + var unicode = new Number("0x" + GlyphsUnicode[charset[i]]); if (!unicode) - error("Unicode for " + testCharset[i] + " is has not been found in the glyphs list"); + error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); testString += String.fromCharCode(unicode); } ctx.font = "20px " + fontName + ", Symbol"; diff --git a/test.html b/test.html index 8d649a149..d18f9599b 100644 --- a/test.html +++ b/test.html @@ -7,6 +7,7 @@ + diff --git a/test.js b/test.js index 2b99dc136..1dffac549 100644 --- a/test.js +++ b/test.js @@ -93,17 +93,34 @@ function displayPage(num) { if (fontDict.has("Encoding")) { var encoding = xref.fetchIfRef(fontDict.get("Encoding")); if (IsDict(encoding)) { + + // Build an map between codes and glyphs var differences = encoding.get("Differences"); var index = 0; for (var j = 0; j < differences.length; j++) { var data = differences[j]; IsNum(data) ? index = data : encodingMap[index++] = data; } + + // Get the font charset + var charset = descriptor.get("CharSet").split("/"); + + } else if (IsName(encoding)) { + var encoding = Encodings[encoding]; + var widths = xref.fetchIfRef(fontDict.get("Widths")); + var firstchar = xref.fetchIfRef(fontDict.get("FirstChar")); + + var charset = []; + for (var j = 0; j < widths.length; j++) { + var index = widths[j]; + if (index) + charset.push(encoding[j + firstchar]); + } } } var subtype = fontDict.get("Subtype").name; - new Font(fontName, fontFile, encodingMap, subtype); + new Font(fontName, fontFile, encodingMap, charset, subtype); return fontsReady = false; } else if (font.loading) { return fontsReady = false; From 73350b1f46d44707ebcc8563dea0da7aa06043f3 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 15 Jun 2011 05:42:15 +0200 Subject: [PATCH 017/439] Forgot to turn off some debug flags --- PDFFont.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PDFFont.js b/PDFFont.js index ff06c5e4e..f20f7e24f 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -126,7 +126,7 @@ Font.prototype = { // Actually there is not event when a font has finished downloading so // the following tons of code are a dirty hack to 'guess' when a font is // ready - var debug = true; + var debug = false; var canvas = document.createElement("canvas"); var style = "border: 1px solid black; position:absolute; top: " + From 7afaca2d35e9c06785bc63c0b0aa855d352ddaa5 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 22:54:49 -0700 Subject: [PATCH 018/439] eagerly compile XForm objects --- pdf.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 20299909e..48e20c455 100644 --- a/pdf.js +++ b/pdf.js @@ -1689,8 +1689,7 @@ var CanvasGraphics = (function() { var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; this.xref = xref; this.res = resources || new Dict(); - this.xobjs = this.res.get("XObject") || new Dict(); - this.xobjs = this.xref.fetchIfRef(this.xobjs); + this.xobjs = xref.fetchIfRef(this.res.get("XObject")) || new Dict(); stream.execute(this); @@ -1700,6 +1699,8 @@ var CanvasGraphics = (function() { }, compile: function(stream, xref, resources) { + var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict(); + var parser = new Parser(new Lexer(stream), false); var objpool = []; @@ -1724,6 +1725,22 @@ var CanvasGraphics = (function() { assertWellFormed(fn, "Unknown command '" + cmd + "'"); // TODO figure out how to type-check vararg functions + if (cmd == "Do") { // eagerly compile XForm objects + var name = args[0].name; + var xobj = xobjs.get(name); + if (xobj) { + xobj = xref.fetchIfRef(xobj); + assertWellFormed(IsStream(xobj), "XObject should be a stream"); + + var type = xobj.dict.get("Subtype"); + assertWellFormed(IsName(type), "XObject should have a Name subtype"); + + if ("Form" == type.name) { + this.compile(xobj, xref, xobj.dict.get("Resources")); + } + } + } + src += "this."; src += fn; src += "("; From 5acb9a16deb909697da08aeef36e1056439ed97f Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 23:16:53 -0700 Subject: [PATCH 019/439] cache results of compilation --- pdf.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pdf.js b/pdf.js index 48e20c455..d65151e46 100644 --- a/pdf.js +++ b/pdf.js @@ -1395,7 +1395,9 @@ var Page = (function() { gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], width: mediaBox[2] - mediaBox[0], height: mediaBox[3] - mediaBox[1] }); - gfx.execute(contents, xref, resources); + if (!this.code) + this.code = gfx.compile(contents, xref, resources); + gfx.execute(this.code, xref, resources); gfx.endDrawing(); } }; @@ -1682,16 +1684,13 @@ var CanvasGraphics = (function() { this.ctx.translate(0, -mediaBox.height); }, - execute: function(stream, xref, resources) { - if (!stream.execute) - stream.execute = this.compile(stream, xref, resources); - + execute: function(code, xref, resources) { var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; this.xref = xref; this.res = resources || new Dict(); this.xobjs = xref.fetchIfRef(this.res.get("XObject")) || new Dict(); - stream.execute(this); + code(this); this.xobjs = savedXobjs; this.res = savedRes; @@ -1699,6 +1698,7 @@ var CanvasGraphics = (function() { }, compile: function(stream, xref, resources) { + console.log("compiling"); var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict(); var parser = new Parser(new Lexer(stream), false); @@ -1725,7 +1725,7 @@ var CanvasGraphics = (function() { assertWellFormed(fn, "Unknown command '" + cmd + "'"); // TODO figure out how to type-check vararg functions - if (cmd == "Do") { // eagerly compile XForm objects + if (cmd == "Do" && !args[0].code) { // eagerly compile XForm objects var name = args[0].name; var xobj = xobjs.get(name); if (xobj) { @@ -1736,7 +1736,7 @@ var CanvasGraphics = (function() { assertWellFormed(IsName(type), "XObject should have a Name subtype"); if ("Form" == type.name) { - this.compile(xobj, xref, xobj.dict.get("Resources")); + args[0].code = this.compile(xobj, xref, xobj.dict.get("Resources")); } } } @@ -2050,9 +2050,9 @@ var CanvasGraphics = (function() { var type = xobj.dict.get("Subtype"); assertWellFormed(IsName(type), "XObject should have a Name subtype"); if ("Image" == type.name) { - this.paintImageXObject(xobj, false); + this.paintImageXObject(obj, xobj, false); } else if ("Form" == type.name) { - this.paintFormXObject(xobj); + this.paintFormXObject(obj, xobj); } else if ("PS" == type.name) { warn("(deprecated) PostScript XObjects are not supported"); } else { @@ -2060,25 +2060,26 @@ var CanvasGraphics = (function() { } }, - paintFormXObject: function(form) { + paintFormXObject: function(ref, stream) { this.save(); - var matrix = form.dict.get("Matrix"); + var matrix = stream.dict.get("Matrix"); if (matrix && IsArray(matrix) && 6 == matrix.length) this.transform.apply(this, matrix); - var bbox = form.dict.get("BBox"); + var bbox = stream.dict.get("BBox"); if (bbox && IsArray(bbox) && 4 == bbox.length) { this.rectangle.apply(this, bbox); this.clip(); this.endPath(); } - this.execute(form, this.xref, form.dict.get("Resources")); + + this.execute(ref.code, this.xref, stream.dict.get("Resources")); this.restore(); }, - paintImageXObject: function(image, inline) { + paintImageXObject: function(ref, image, inline) { this.save(); if (image.getParams) { // JPX/JPEG2000 streams directly contain bits per component From fbb2f497fdd579b350452c4ea3d5c08c62b30a49 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 23:22:19 -0700 Subject: [PATCH 020/439] pdf is using a dumb name, content makes much more sense than Contents --- pdf.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pdf.js b/pdf.js index d65151e46..23f249781 100644 --- a/pdf.js +++ b/pdf.js @@ -1373,8 +1373,8 @@ var Page = (function() { } constructor.prototype = { - get contents() { - return shadow(this, "contents", this.pageDict.get("Contents")); + get content() { + return shadow(this, "content", this.pageDict.get("Contents")); }, get resources() { return shadow(this, "resources", this.pageDict.get("Resources")); @@ -1387,16 +1387,16 @@ var Page = (function() { }, display: function(gfx) { var xref = this.xref; - var contents = xref.fetchIfRef(this.contents); + var content = xref.fetchIfRef(this.content); var resources = xref.fetchIfRef(this.resources); var mediaBox = xref.fetchIfRef(this.mediaBox); - assertWellFormed(IsStream(contents) && IsDict(resources), - "invalid page contents or resources"); + assertWellFormed(IsStream(content) && IsDict(resources), + "invalid page content or resources"); gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], width: mediaBox[2] - mediaBox[0], height: mediaBox[3] - mediaBox[1] }); if (!this.code) - this.code = gfx.compile(contents, xref, resources); + this.code = gfx.compile(content, xref, resources); gfx.execute(this.code, xref, resources); gfx.endDrawing(); } From 0ef077c44c7ed1fc447acf1aff96ba2c18ee1412 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 23:34:11 -0700 Subject: [PATCH 021/439] eagerly translate all fonts (a no-op currently) --- pdf.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 23f249781..5aec4e76a 100644 --- a/pdf.js +++ b/pdf.js @@ -1677,6 +1677,10 @@ var CanvasGraphics = (function() { const EO_CLIP = {}; constructor.prototype = { + translateFont: function(fontDict) { + return fontDict; + }, + beginDrawing: function(mediaBox) { var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height; this.ctx.save(); @@ -1698,7 +1702,6 @@ var CanvasGraphics = (function() { }, compile: function(stream, xref, resources) { - console.log("compiling"); var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict(); var parser = new Parser(new Lexer(stream), false); @@ -1739,6 +1742,15 @@ var CanvasGraphics = (function() { args[0].code = this.compile(xobj, xref, xobj.dict.get("Resources")); } } + } else if (cmd == "Tf") { // eagerly collect all fonts + var fontRes = resources.get("Font"); + if (fontRes) { + fontRes = xref.fetchIfRef(fontRes); + var font = xref.fetchIfRef(fontRes.get(args[0].name)); + assertWellFormed(IsDict(font)); + if (!font.translated) + font.translated = this.translateFont(font); + } } src += "this."; From 77bc59681edd6c46ac5f8f2057be6bdf7b5e5c08 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 23:41:26 -0700 Subject: [PATCH 022/439] completed async font loading framework --- pdf.js | 25 ++++++++++++++++++++----- test.html | 7 +++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/pdf.js b/pdf.js index 5aec4e76a..633437e7e 100644 --- a/pdf.js +++ b/pdf.js @@ -1385,6 +1385,14 @@ var Page = (function() { ? obj : null)); }, + compile: function(gfx, fonts) { + if (!this.code) { + var xref = this.xref; + var content = xref.fetchIfRef(this.content); + var resources = xref.fetchIfRef(this.resources); + this.code = gfx.compile(content, xref, resources, fonts); + } + }, display: function(gfx) { var xref = this.xref; var content = xref.fetchIfRef(this.content); @@ -1395,8 +1403,6 @@ var Page = (function() { gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], width: mediaBox[2] - mediaBox[0], height: mediaBox[3] - mediaBox[1] }); - if (!this.code) - this.code = gfx.compile(content, xref, resources); gfx.execute(this.code, xref, resources); gfx.endDrawing(); } @@ -1701,7 +1707,7 @@ var CanvasGraphics = (function() { this.xref = savedXref; }, - compile: function(stream, xref, resources) { + compile: function(stream, xref, resources, fonts) { var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict(); var parser = new Parser(new Lexer(stream), false); @@ -1739,7 +1745,10 @@ var CanvasGraphics = (function() { assertWellFormed(IsName(type), "XObject should have a Name subtype"); if ("Form" == type.name) { - args[0].code = this.compile(xobj, xref, xobj.dict.get("Resources")); + args[0].code = this.compile(xobj, + xref, + xobj.dict.get("Resources"), + fonts); } } } else if (cmd == "Tf") { // eagerly collect all fonts @@ -1748,8 +1757,14 @@ var CanvasGraphics = (function() { fontRes = xref.fetchIfRef(fontRes); var font = xref.fetchIfRef(fontRes.get(args[0].name)); assertWellFormed(IsDict(font)); - if (!font.translated) + if (!font.translated) { font.translated = this.translateFont(font); + if (fonts && font.translated) { + // keep track of each font we translated so the caller can + // load them asynchronously before calling display on a page + fonts.push(font.translated); + } + } } } diff --git a/test.html b/test.html index f78f22ce2..e59d0577e 100644 --- a/test.html +++ b/test.html @@ -95,6 +95,13 @@ function displayPage(num) { ctx.restore(); var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + + // This should be called when font loading is complete page.display(gfx); var t2 = Date.now(); From b5dcf986eb6361b970cf012968924d33719fcb02 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 14 Jun 2011 23:44:59 -0700 Subject: [PATCH 023/439] clarify API a bit and hand in xref and resources to ease translation --- pdf.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 633437e7e..6e6935f13 100644 --- a/pdf.js +++ b/pdf.js @@ -1683,8 +1683,8 @@ var CanvasGraphics = (function() { const EO_CLIP = {}; constructor.prototype = { - translateFont: function(fontDict) { - return fontDict; + translateFont: function(fontDict, xref, resources) { + return "translated"; }, beginDrawing: function(mediaBox) { @@ -1758,7 +1758,7 @@ var CanvasGraphics = (function() { var font = xref.fetchIfRef(fontRes.get(args[0].name)); assertWellFormed(IsDict(font)); if (!font.translated) { - font.translated = this.translateFont(font); + font.translated = this.translateFont(font, xref, resources); if (fonts && font.translated) { // keep track of each font we translated so the caller can // load them asynchronously before calling display on a page From 97bb956ac9c5fc06b88775852bf3952acd240f4b Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Wed, 15 Jun 2011 00:20:26 -0700 Subject: [PATCH 024/439] measure load/compile/render times --- test.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test.html b/test.html index e59d0577e..9cadf2e1f 100644 --- a/test.html +++ b/test.html @@ -101,12 +101,14 @@ function displayPage(num) { var fonts = []; page.compile(gfx, fonts); + var t2 = Date.now(); + // This should be called when font loading is complete page.display(gfx); - var t2 = Date.now(); + var t3 = Date.now(); - infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms"; + infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms"; } function nextPage() { From 2519e4f53b02cebbec59f4194288e4e2a7108e8a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 15 Jun 2011 09:21:59 +0200 Subject: [PATCH 025/439] Make Type1 glyphs use the default width they declare --- PDFFont.js | 68 ++++++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index f20f7e24f..89dc22d42 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -1375,10 +1375,10 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { * as descrived in 'Using Subroutines' of 'Adobe Type 1 Font Format', * chapter 8. */ - this.flattenCharstring = function(aCharstring, aDefaultWidth, aSubrs) { + this.flattenCharstring = function(aCharstring, aSubrs) { operandStack.clear(); executionStack.clear(); - executionStack.push(aCharstring); + executionStack.push(aCharstring.slice()); var leftSidebearing = 0; var lastPoint = 0; @@ -1392,24 +1392,13 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { switch (obj) { case "hsbw": var charWidthVector = operandStack.pop(); - leftSidebearing = operandStack.pop(); - - if (charWidthVector != aDefaultWidth) - operandStack.push(charWidthVector - aDefaultWidth); - break; - - case "rmoveto": - var dy = operandStack.pop(); - var dx = operandStack.pop(); + var leftSidebearing = operandStack.pop(); + operandStack.push(charWidthVector); if (leftSidebearing) { - dx += leftSidebearing; - leftSidebearing = 0; + operandStack.push(leftSidebearing); + operandStack.push("hmoveto"); } - - operandStack.push(dx); - operandStack.push(dy); - operandStack.push("rmoveto"); break; case "div": @@ -1445,12 +1434,13 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { break; case "callothersubr": - // XXX need to be improved var index = operandStack.pop(); var count = operandStack.pop(); var data = operandStack.pop(); + // XXX The callothersubr needs to support at least the 3 defaults + // otherSubrs of the spec if (index != 3) - dump("callothersubr for index: " + index); + error("callothersubr for index: " + index); operandStack.push(3); operandStack.push("callothersubr"); break; @@ -1490,25 +1480,6 @@ var CFF = function(aFontFile) { }; CFF.prototype = { - getDefaultWidth: function(aCharstrings) { - var defaultWidth = 0; - var defaultUsedCount = 0; - - var widths = {}; - for (var i = 0; i < aCharstrings.length; i++) { - var width = aCharstrings[i].charstring[1]; - var usedCount = (widths[width] || 0) + 1; - - if (usedCount > defaultUsedCount) { - defaultUsedCount = usedCount; - defaultWidth = width; - } - - widths[width] = usedCount; - } - return parseInt(defaultWidth); - }, - createCFFIndexHeader: function(aObjects, aIsByte) { var data = []; @@ -1602,7 +1573,6 @@ CFF.prototype = { }; var charstrings = this.getOrderedCharStrings(aFont); - var defaultWidth = this.getDefaultWidth(charstrings); var charstringsCount = 0; var charstringsDataLength = 0; @@ -1617,7 +1587,7 @@ CFF.prototype = { error("glyphs already exists!"); glyphsChecker[glyph] = true; - var flattened = parser.flattenCharstring(charstring, defaultWidth, subrs); + var flattened = parser.flattenCharstring(charstring, subrs); glyphs.push(flattened); charstringsCount++; charstringsDataLength += flattened.length; @@ -1712,8 +1682,6 @@ CFF.prototype = { charstringsIndex = charstringsIndex.join(" ").split(" "); // XXX why? - var fontBBox = aFont.get("FontBBox"); - //Top Dict Index var topDictIndex = [ 0x00, 0x01, 0x01, 0x01, 0x30, @@ -1724,6 +1692,7 @@ CFF.prototype = { 248, 31, 4 // Weight ]; + var fontBBox = aFont.get("FontBBox"); for (var i = 0; i < fontBBox.length; i++) topDictIndex = topDictIndex.concat(this.encodeNumber(fontBBox[i])); topDictIndex.push(5) // FontBBox; @@ -1768,19 +1737,22 @@ CFF.prototype = { currentOffset += charstringsIndex.length; // Private Data - var privateData = [ - 248, 136, 20, - 248, 136, 21, + var defaultWidth = this.encodeNumber(0); + var privateData = [].concat( + defaultWidth, [20], + defaultWidth, [21], + [ 119, 159, 248, 97, 159, 247, 87, 159, 6, 30, 10, 3, 150, 37, 255, 12, 9, - 139, 12, 10, - 172, 10, + 139, 12, + 10, 172, 10, 172, 150, 143, 146, 150, 146, 12, 12, 247, 32, 11, 247, 10, 161, 147, 154, 150, 143, 12, 13, 139, 12, 14, 28, 0, 55, 19 - ]; + ]); + privateData = privateData.join(" ").split(" "); cff.set(privateData, currentOffset); currentOffset += privateData.length; From 6a9f7def456c1ef528d3180de9df2884988dff23 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Wed, 15 Jun 2011 00:37:15 -0700 Subject: [PATCH 026/439] fixes suggested by @brendaneich --- pdf.js | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/pdf.js b/pdf.js index 6e6935f13..3468c7b88 100644 --- a/pdf.js +++ b/pdf.js @@ -590,7 +590,7 @@ function IsString(v) { } function IsNull(v) { - return v == null; + return v === null; } function IsName(v) { @@ -617,27 +617,6 @@ function IsRef(v) { return v instanceof Ref; } -function IsFunction(v) { - var fnDict; - if (typeof v != "object") - return false; - else if (IsDict(v)) - fnDict = v; - else if (IsStream(v)) - fnDict = v.dict; - else - return false; - return fnDict.has("FunctionType"); -} - -function IsFunctionDict(v) { - return IsFunction(v) && IsDict(v); -} - -function IsFunctionStream(v) { - return IsFunction(v) && IsStream(v); -} - var EOF = {}; function IsEOF(v) { @@ -841,10 +820,12 @@ var Lexer = (function() { ch = stream.getChar(); if (ch == '>') { break; - } else if (!ch) { + } + if (!ch) { warn("Unterminated hex string"); break; - } else if (specialChars[ch.charCodeAt(0)] != 1) { + } + if (specialChars[ch.charCodeAt(0)] != 1) { var x, x2; if (((x = ToHexDigit(ch)) == -1) || ((x2 = ToHexDigit(stream.getChar())) == -1)) { @@ -1722,7 +1703,7 @@ var CanvasGraphics = (function() { return arg; } - var src = "{\n"; + var src = ""; var args = []; var map = this.map; @@ -1781,9 +1762,7 @@ var CanvasGraphics = (function() { } } - src += "}"; - - var fn = new Function("objpool", src); + var fn = Function("objpool", src); return function (gfx) { fn.call(gfx, objpool); }; }, From 0f2d4c7011d605620bbcea543ec6f66004ff89c0 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 15 Jun 2011 11:34:47 -0700 Subject: [PATCH 027/439] cleaned up fetchIfRef, changed switch-case to array lookup, changed IsFunction to IsPDFFunction --- pdf.js | 78 +++++++++++++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/pdf.js b/pdf.js index 0beb5e22e..d4df52452 100644 --- a/pdf.js +++ b/pdf.js @@ -617,7 +617,7 @@ function IsRef(v) { return v instanceof Ref; } -function IsFunction(v) { +function IsPDFFunction(v) { var fnDict; if (typeof v != "object") return false; @@ -1911,18 +1911,16 @@ var CanvasGraphics = (function() { // Shading shadingFill: function(entryRef) { - var shadingRes = this.res.get("Shading"); - if (!shadingRes) - return; - var xref = this.xref; - shadingRes = xref.fetchIfRef(shadingRes); - var shading = shadingRes.get(entryRef.name); + var res = this.res; + + var shadingRes = xref.fetchIfRef(res.get("Shading")); + if (!shadingRes) + error("No shading resource found"); + + var shading = xref.fetchIfRef(shadingRes.get(entryRef.name)); if (!shading) - return; - shading = xref.fetchIfRef(shading); - if (!shading) - return; + error("No shading object found"); this.save(); @@ -1940,22 +1938,14 @@ var CanvasGraphics = (function() { if (background) TODO("handle background colors"); - var type = shading.get("ShadingType"); - switch (type) { - case 1: - this.fillFunctionShading(shading); - break; - case 2: - this.fillAxialShading(shading); - break; - case 3: - this.fillRadialShading(shading); - break; - case 4: case 5: case 6: case 7: - TODO("shading fill type "+ type); - default: - malformed("Unknown shading type "+ type); - } + const types = [null, this.fillFunctionShading, + this.fillAxialShading, this.fillRadialShading]; + + var typeNum = shading.get("ShadingType"); + var fillFn = types[typeNum]; + if (!fillFn) + error("Unknown type of shading"); + fillFn.apply(this, [shading]); this.restore(); }, @@ -1981,7 +1971,7 @@ var CanvasGraphics = (function() { fnObj = this.xref.fetchIfRef(fnObj); if (IsArray(fnObj)) error("No support for array of functions"); - else if (!IsFunction(fnObj)) + else if (!IsPDFFunction(fnObj)) error("Invalid function"); fn = new PDFFunction(this.xref, fnObj); @@ -1990,12 +1980,14 @@ var CanvasGraphics = (function() { for (var i = t0; i <= t1; i += step) { var c = fn.func([i]); - gradient.addColorStop(i, this.makeCssRgb.apply(this,c)); + gradient.addColorStop(i, this.makeCssRgb.apply(this, c)); } this.ctx.fillStyle = gradient; - // HACK to draw the gradient onto an infinite rectangle + // HACK to draw the gradient onto an infinite rectangle. + // PDF gradients are drawn across the entire image while + // Canvas only allows gradients to be drawn in a rectangle this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); }, @@ -2316,24 +2308,16 @@ var PDFFunction = (function() { if (!dict) dict = fn; - var type = dict.get("FunctionType"); - - switch(type) { - case 0: - this.constructSampled(fn, dict); - break; - case 2: - this.constructInterpolated(); - break; - case 3: - this.constructStiched(); - break; - case 4: - this.constructPostScript(); - break; - default: + const types = [this.constructSampled, null, + this.constructInterpolated, this.constructStiched, + this.constructPostScript]; + + var typeNum = dict.get("FunctionType"); + var typeFn = types[typeNum]; + if (!typeFn) error("Unknown type of function"); - } + + typeFn.apply(this, [fn, dict]); }; constructor.prototype = { From 07c81a624e17bd321f7fc48b5fc34ee5d45e584b Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 15 Jun 2011 14:24:44 -0500 Subject: [PATCH 028/439] implement some operators and add TODOs for remaining undefined ones --- pdf.js | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/pdf.js b/pdf.js index 3468c7b88..517b2b27c 100644 --- a/pdf.js +++ b/pdf.js @@ -1596,6 +1596,7 @@ var CanvasGraphics = (function() { w: "setLineWidth", J: "setLineCap", j: "setLineJoin", + M: "setMiterLimit", d: "setDash", ri: "setRenderingIntent", i: "setFlatness", @@ -1608,13 +1609,18 @@ var CanvasGraphics = (function() { m: "moveTo", l: "lineTo", c: "curveTo", + v: "curveTo2", + y: "curveTo3", h: "closePath", re: "rectangle", S: "stroke", + s: "closeStroke", f: "fill", "f*": "eoFill", B: "fillStroke", + "B*": "eoFillStroke", b: "closeFillStroke", + "b*": "closeEOFillStroke", n: "endPath", // Clipping @@ -1624,15 +1630,25 @@ var CanvasGraphics = (function() { // Text BT: "beginText", ET: "endText", + Tc: "setCharSpacing", + Tw: "setWordSpacing", + Tz: "setHScale", TL: "setLeading", Tf: "setFont", + Tr: "setTextRenderingMode", + Ts: "setTextRise", Td: "moveText", + TD: "setLeadingMoveText", Tm: "setTextMatrix", "T*": "nextLine", Tj: "showText", TJ: "showSpacedText", + "'": "nextLineShowText", + '"': "nextLineSetSpacingShowText", // Type3 fonts + d0: "setCharWidth", + d1: "setCharWidthAndBounds", // Color CS: "setStrokeColorSpace", @@ -1645,16 +1661,28 @@ var CanvasGraphics = (function() { g: "setFillGray", RG: "setStrokeRGBColor", rg: "setFillRGBColor", + K: "setStrokeCMYKColor", + k: "setFillCMYKColor", // Shading sh: "shadingFill", // Images + BI: "beginInlineImage", + // XObjects Do: "paintXObject", // Marked content + MP: "markPoint", + DP: "markPointProps", + BMC: "beginMarkedContent", + BDC: "beginMarkedContentProps", + EMC: "endMarkedContent", + // Compatibility + BX: "beginCompat", + EX: "endCompat", }; } @@ -1780,6 +1808,9 @@ var CanvasGraphics = (function() { setLineJoin: function(style) { this.ctx.lineJoin = LINE_JOIN_STYLES[style]; }, + setMiterLimit: function(limit) { + this.ctx.miterLimit = limit; + }, setDash: function(dashArray, dashPhase) { TODO("set dash"); }, @@ -1818,6 +1849,12 @@ var CanvasGraphics = (function() { curveTo: function(x1, y1, x2, y2, x3, y3) { this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); }, + curveTo2: function(x2, y2, x3, y3) { + TODO("'v' operator: need current point in gfx context"); + }, + curveTo3: function(x1, y1, x3, y3) { + this.curveTo(x1, y1, x3, y3, x3, y3); + }, closePath: function() { this.ctx.closePath(); }, @@ -1828,6 +1865,10 @@ var CanvasGraphics = (function() { this.ctx.stroke(); this.consumePath(); }, + closeStroke: function() { + this.closePath(); + this.stroke(); + }, fill: function() { this.ctx.fill(); this.consumePath(); @@ -1842,9 +1883,19 @@ var CanvasGraphics = (function() { this.ctx.stroke(); this.consumePath(); }, + eoFillStroke: function() { + var savedFillRule = this.setEOFillRule(); + this.fillStroke(); + this.restoreFillRule(savedFillRule); + }, closeFillStroke: function() { return this.fillStroke(); }, + closeEOFillStroke: function() { + var savedFillRule = this.setEOFillRule(); + this.fillStroke(); + this.restoreFillRule(savedFillRule); + }, endPath: function() { this.consumePath(); }, @@ -1865,6 +1916,15 @@ var CanvasGraphics = (function() { }, endText: function() { }, + setCharSpacing: function(spacing) { + TODO("character (glyph?) spacing"); + }, + setWordSpacing: function(spacing) { + TODO("word spacing"); + }, + setHSpacing: function(scale) { + TODO("horizontal text scale"); + }, setLeading: function(leading) { this.current.leading = leading; }, @@ -1880,10 +1940,20 @@ var CanvasGraphics = (function() { TODO("using hard-coded font for testing"); this.ctx.font = this.current.fontSize +'px "Nimbus Roman No9 L"'; }, + setTextRenderingMode: function(mode) { + TODO("text rendering mode"); + }, + setTextRise: function(rise) { + TODO("text rise"); + }, moveText: function (x, y) { this.current.x = this.current.lineX += x; this.current.y = this.current.lineY += y; }, + setLeadingMoveText: function(x, y) { + this.setLeading(-y); + this.moveText(x, y); + }, setTextMatrix: function(a, b, c, d, e, f) { this.current.textMatrix = [ a, b, c, d, e, f ]; this.current.x = this.current.lineX = 0; @@ -1915,8 +1985,23 @@ var CanvasGraphics = (function() { } } }, + nextLineShowText: function(text) { + this.nextLine(); + this.showText(text); + }, + nextLineSetSpacingShowText: function(wordSpacing, charSpacing, text) { + this.setWordSpacing(wordSpacing); + this.setCharSpacing(charSpacing); + this.nextLineShowText(text); + }, // Type3 fonts + setCharWidth: function(xWidth, yWidth) { + TODO("type 3 fonts ('d0' operator)"); + }, + setCharWidthAndBounds: function(xWidth, yWidth, llx, lly, urx, ury) { + TODO("type 3 fonts ('d1' operator)"); + }, // Color setStrokeColorSpace: function(space) { @@ -1961,6 +2046,12 @@ var CanvasGraphics = (function() { setFillRGBColor: function(r, g, b) { this.ctx.fillStyle = this.makeCssRgb(r, g, b); }, + setStrokeCMYKColor: function(c, m, y, k) { + TODO("CMYK space"); + }, + setFillCMYKColor: function(c, m, y, k) { + TODO("CMYK space"); + }, // Shading shadingFill: function(entryRef) { @@ -2035,6 +2126,15 @@ var CanvasGraphics = (function() { this.consumePath(); }, + // Images + beginInlineImage: function() { + TODO("inline images"); + error("(Stream will not be parsed properly, bailing now)"); + // Like an inline stream: + // - key/value pairs up to Cmd(ID) + // - then image data up to Cmd(EI) + }, + // XObjects paintXObject: function(obj) { var xobj = this.xobjs.get(obj.name); @@ -2262,6 +2362,33 @@ var CanvasGraphics = (function() { this.restore(); }, + // Marked content + + markPoint: function(tag) { + TODO("Marked content"); + }, + markPointProps: function(tag, properties) { + TODO("Marked content"); + }, + beginMarkedContent: function(tag) { + TODO("Marked content"); + }, + beginMarkedContentProps: function(tag, properties) { + TODO("Marked content"); + }, + endMarkedContent: function() { + TODO("Marked content"); + }, + + // Compatibility + + beginCompat: function() { + TODO("ignore undefined operators (should we do that anyway?)"); + }, + endCompat: function() { + TODO("stop ignoring undefined operators"); + }, + // Helper functions consumePath: function() { From 7fb6c434c5b4c8067f89f4b81ee6522f1d9c2612 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 15 Jun 2011 12:55:48 -0700 Subject: [PATCH 029/439] implement setDash --- pdf.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 10e661129..17537d233 100644 --- a/pdf.js +++ b/pdf.js @@ -1825,7 +1825,8 @@ var CanvasGraphics = (function() { this.ctx.miterLimit = limit; }, setDash: function(dashArray, dashPhase) { - TODO("set dash"); + this.ctx.mozDash = dashArray; + this.ctx.mozDashOffset = dashPhase; }, setRenderingIntent: function(intent) { TODO("set rendering intent"); From 650ed04a702485e209843bbfe38fc5a0faeed905 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 15 Jun 2011 23:02:30 +0200 Subject: [PATCH 030/439] Get rid of the PostScript interpreter (part 1) --- PDFFont.js | 448 ++++++++++++----------------------------------------- test.js | 4 +- 2 files changed, 105 insertions(+), 347 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 89dc22d42..e54f3ec4b 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -14,7 +14,7 @@ var kMaxGlyphsCount = 65526; /** * Maximum time to wait for a font to be loaded by @font-face */ -var kMaxWaitForFontFace = 2000; +var kMaxWaitForFontFace = 1000; /* * Useful for debugging when you want to certains operations depending on how @@ -59,8 +59,11 @@ var Fonts = { * * As an improvment the last parameter can be replaced by an automatic guess * of the font type based on the first byte of the file. + * + * XXX There is now too many parameters, this should be turned into an + * object containing all the required informations about the font */ -var Font = function(aName, aFile, aEncoding, aCharset, aType) { +var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { this.name = aName; // If the font has already been decoded simply return @@ -73,7 +76,7 @@ var Font = function(aName, aFile, aEncoding, aCharset, aType) { var start = Date.now(); switch (aType) { case "Type1": - var cff = new CFF(aFile); + var cff = new CFF(aName, aBBox, aFile); this.mimetype = "font/otf"; // Wrap the CFF data inside an OTF font file @@ -175,7 +178,7 @@ Font.prototype = { if (debug) ctx.fillText(testString, 20, 50); - }, 150, this); + }, 20, this); /** Hack end */ @@ -402,7 +405,7 @@ Font.prototype = { this._createTableEntry(otf, offsets, "OS/2", OS2); //XXX Getting charstrings here seems wrong since this is another CFF glue - var charstrings = aFont.getOrderedCharStrings(aFont.font); + var charstrings = aFont.getOrderedCharStrings(aFont.glyphs); /** CMAP */ cmap = this._createCMAPTable(charstrings); @@ -851,9 +854,7 @@ var Stack = function(aStackSize) { }; }; -var Type1Parser = function(aAsciiStream, aBinaryStream) { - var lexer = aAsciiStream ? new Lexer(aAsciiStream) : null; - +var Type1Parser = function() { // Turn on this flag for additional debugging logs var debug = false; @@ -862,30 +863,6 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { log(aData); }; - // Hold the fontName as declared inside the /FontName postscript directive - // XXX This is a hack but at the moment I need it to map the name declared - // in the PDF and the name in the PS code. - var fontName = ""; - - /* - * Parse a whole Type1 font stream (from the first segment to the last) - * assuming the 'eexec' block is binary data and fill up the 'Fonts' - * dictionary with the font informations. - */ - var self = this; - this.parse = function() { - if (!debug) { - while (!processNextToken()) {}; - return fontName; - } else { - // debug mode is used to debug postcript processing - setTimeout(function() { - if (!processNextToken()) - self.parse(); - }, 0); - } - }; - /* * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence * of Plaintext Bytes. The function took a key as a parameter which can be @@ -894,7 +871,7 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { var kEexecEncryptionKey = 55665; var kCharStringsEncryptionKey = 4330; - function decrypt(aStream, aKey, aDiscardNumber) { + function decrypt(aStream, aKey, aDiscardNumber, aByteArray) { var start = Date.now(); var r = aKey, c1 = 52845, c2 = 22719; var decryptedString = []; @@ -903,7 +880,10 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { var count = aStream.length; for (var i = 0; i < count; i++) { value = aStream.getByte(); - decryptedString[i] = String.fromCharCode(value ^ (r >> 8)); + if (aByteArray) + decryptedString[i] = value ^ (r >> 8); + else + decryptedString[i] = String.fromCharCode(value ^ (r >> 8)); r = ((value + r) * c1 + c2) & ((1 << 16) - 1); } var end = Date.now(); @@ -1017,7 +997,7 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { var end = Date.now(); dump("Time to decode charString of length " + count + " is " + (end - start)); return charString; - } + }; /* * The operand stack holds arbitrary PostScript objects that are the operands @@ -1068,305 +1048,76 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { */ function nextInStack() { var currentProcedure = executionStack.peek(); - if (currentProcedure) { - var command = currentProcedure.shift(); - if (!currentProcedure.length) - executionStack.pop(); - return command; - } - - return lexer.getObj(); + var command = currentProcedure.shift(); + if (!currentProcedure.length) + executionStack.pop(); + return command; }; - /* - * Get the next token from the executionStack and process it. - * Actually the function does not process the third segment of a Type1 font - * and end on 'closefile'. - * - * The method thrown an error if it encounters an unknown token. + /** + * Returns an object containing a Subrs array and a CharStrings array + * extracted from and eexec encrypted block of data */ - function processNextToken() { - var obj = nextInStack(); - if (operandIsArray && !IsCmd(obj, "{") && !IsCmd(obj, "[") && - !IsCmd(obj, "]") && !IsCmd(obj, "}")) { - dump("Adding an object: " + obj +" to array " + operandIsArray); - var currentArray = operandStack.peek(); - for (var i = 1; i < operandIsArray; i++) - currentArray = currentArray[currentArray.length - 1]; + this.extractFontInfo = function(aStream) { + var eexecString = decrypt(new Stream(aStream), kEexecEncryptionKey, 4, true); + var subrs = [], glyphs = []; + var inSubrs = inGlyphs = false; + var glyph = ""; - currentArray.push(obj); - } else if (IsBool(obj) || IsInt(obj) || IsNum(obj) || IsString(obj)) { - dump("Value: " + obj); - operandStack.push(obj); - } else if (IsName(obj)) { - dump("Name: " + obj.name); - operandStack.push(obj.name); - } else if (IsCmd(obj)) { - var command = obj.cmd; - dump(command); + var token = ""; + var index = 0; + var length = 0; - switch (command) { - case "[": - case "{": - dump("Start" + (command == "{" ? " Executable " : " ") + "Array"); - operandIsArray++; - var currentArray = operandStack; - for (var i = 1; i < operandIsArray; i++) - if (currentArray.peek) - currentArray = currentArray.peek(); - else - currentArray = currentArray[currentArray.length - 1]; - currentArray.push([]); - break; + var count = eexecString.length; + var c = ""; + for (var i = 0; i < count; i++) { + var c = eexecString[i]; - case "]": - case "}": - var currentArray = operandStack.peek(); - for (var i = 1; i < operandIsArray; i++) - currentArray = currentArray[currentArray.length - 1]; - dump("End" + (command == "}" ? " Executable " : " ") + "Array: " + currentArray.join(" ")); - operandIsArray--; - break; + if (inSubrs && c == 0x52) { + length = parseInt(length); + var stream = new Stream(eexecString.slice(i + 3, i + 3 + length)); + var encodedSubr = decrypt(stream, kCharStringsEncryptionKey, 4).join(""); + var subr = decodeCharString(new StringStream(encodedSubr)); - case "if": - var procedure = operandStack.pop(); - var bool = operandStack.pop(); - if (!IsBool(bool)) { - dump("if: " + bool); - // we need to execute things, let be dirty - executionStack.push(bool); - } else { - dump("if ( " + bool + " ) { " + procedure + " }"); - if (bool) - executionStack.push(procedure); - } - break; + subrs.push(subr); + i += 3 + length; + } else if (inGlyphs && c == 0x52) { + length = parseInt(length); + var stream = new Stream(eexecString.slice(i + 3, i + 3 + length)); + var encodedCharstring = decrypt(stream, kCharStringsEncryptionKey, 4).join(""); + var subr = decodeCharString(new StringStream(encodedCharstring)); - case "ifelse": - var procedure1 = operandStack.pop(); - var procedure2 = operandStack.pop(); - var bool = !!operandStack.pop(); - dump("if ( " + bool + " ) { " + procedure2 + " } else { " + procedure1 + " }"); - executionStack.push(bool ? procedure2 : procedure1); - break; + glyphs.push({ + glyph: glyph, + data: subr + }); + i += 3 + length; + } else if (inGlyphs && c == 0x2F) { + token = ""; + glyph = ""; - case "for": - var procedure = operandStack.pop(); - var limit = operandStack.pop(); - var increment = operandStack.pop(); - var initial = operandStack.pop(); - for (var i = 0; i < limit; i += increment) { - operandStack.push(i); - executionStack.push(procedure.slice()); - } - break; - - case "dup": - dump("duplicate: " + operandStack.peek()); - operandStack.push(operandStack.peek()); - break; - - case "mark": - operandStack.push("mark"); - break; - - case "cleartomark": - var command = ""; - do { - command = operandStack.pop(); - } while (command != "mark"); - break; - - case "put": - var data = operandStack.pop(); - var indexOrKey = operandStack.pop(); - var object = operandStack.pop(); - dump("put " + data + " in " + object + "[" + indexOrKey + "]"); - object.set ? object.set(indexOrKey, data) - : object[indexOrKey] = data; - break; - - case "pop": - operandStack.pop(); - break; - - case "exch": - var operand1 = operandStack.pop(); - var operand2 = operandStack.pop(); - operandStack.push(operand1); - operandStack.push(operand2); - break; - - case "get": - var indexOrKey = operandStack.pop(); - var object = operandStack.pop(); - var data = object.get ? object.get(indexOrKey) : object[indexOrKey]; - dump("get " + object + "[" + indexOrKey + "]: " + data); - operandStack.push(data); - break; - - case "currentdict": - var dict = dictionaryStack.peek(); - operandStack.push(dict); - break; - - case "systemdict": - operandStack.push(systemDict); - break; - - case "readonly": - case "executeonly": - case "noaccess": - // Do nothing for the moment - break; - - case "currentfile": - operandStack.push("currentfile"); - break; - - case "array": - var size = operandStack.pop(); - var array = new Array(size); - operandStack.push(array); - break; - - case "dict": - var size = operandStack.pop(); - var dict = new Dict(size); - operandStack.push(dict); - break; - - case "begin": - dictionaryStack.push(operandStack.pop()); - break; - - case "end": - dictionaryStack.pop(); - break; - - case "def": - var value = operandStack.pop(); - var key = operandStack.pop(); - dump("def: " + key + " = " + value); - dictionaryStack.peek().set(key, value); - break; - - case "definefont": - var font = operandStack.pop(); - var key = operandStack.pop(); - dump("definefont " + font + " with key: " + key); - - // The key will be the identifier to recognize this font - fontName = key; - PSFonts.set(key, font); - - operandStack.push(font); - break; - - case "known": - var name = operandStack.pop(); - var dict = operandStack.pop(); - var data = !!dict.get(name); - dump("known: " + data + " :: " + name + " in dict: " + dict); - operandStack.push(data); - break; - - case "exec": - executionStack.push(operandStack.pop()); - break; - - case "eexec": - // All the first segment data has been read, decrypt the second segment - // and start interpreting it in order to decode it - var file = operandStack.pop(); - var eexecString = decrypt(aBinaryStream, kEexecEncryptionKey, 4).join(""); - lexer = new Lexer(new StringStream(eexecString)); - break; - - case "LenIV": - error("LenIV: argh! we need to modify the length of discard characters for charStrings"); - break; - - case "closefile": - var file = operandStack.pop(); - return true; - break; - - case "index": - var operands = []; - var size = operandStack.pop(); - for (var i = 0; i < size; i++) - operands.push(operandStack.pop()); - - var newOperand = operandStack.peek(); - - while (operands.length) - operandStack.push(operands.pop()); - - operandStack.push(newOperand); - break; - - case "string": - var size = operandStack.pop(); - var str = (new Array(size + 1)).join(" "); - operandStack.push(str); - break; - - case "readstring": - var str = operandStack.pop(); - var size = str.length; - - var file = operandStack.pop(); - - // Add '1' because of the space separator, this is dirty - var stream = lexer.stream.makeSubStream(lexer.stream.start + lexer.stream.pos + 1, size); - lexer.stream.skip(size + 1); - - var charString = decrypt(stream, kCharStringsEncryptionKey, 4).join(""); - var charStream = new StringStream(charString); - var decodedCharString = decodeCharString(charStream); - operandStack.push(decodedCharString); - - // boolean indicating if the operation is a success or not - operandStack.push(true); - break; - - case "StandardEncoding": - // For some reason the value is considered as a command, maybe it is - // because of the uppercase 'S' - operandStack.push(obj.cmd); - break; - - default: - var command = null; - if (IsCmd(obj)) { - for (var i = 0; i < dictionaryStack.count(); i++) { - if (command = dictionaryStack.get(i).get(obj.cmd)) { - dump("found in dictionnary for " + obj.cmd + " command: " + command); - executionStack.push(command.slice()); - break; - } - } - } - - if (!command) { - log("operandStack: " + operandStack); - log("dictionaryStack: " + dictionaryStack); - log(obj); - error("Unknow command while parsing font"); - } - break; + while ((c = eexecString[++i]) != 0x20 && i < count) + glyph += String.fromCharCode(c); + } else if (c == 0x2F && eexecString[i+1] == 0x53 && !inGlyphs && !inSubrs) { + while ((c = eexecString[++i]) != 0x20) {}; + inSubrs = true; + } else if (c == 0x20) { + index = length; + length = token; + token = ""; + } else if (c == 0x2F && eexecString[i+1] == 0x43 && eexecString[i+2] == 0x68) { + while ((c = eexecString[++i]) != 0x20) {}; + inSubrs = false; + inGlyphs = true; + } else { + token += String.fromCharCode(c); } - } else if (obj) { - dump("unknow: " + obj); - operandStack.push(obj); - } else { // The End! - operandStack.dump(); - return true; } - - return false; - } + return { + subrs: subrs, + charstrings: glyphs + } + }; /* * Flatten the commands by interpreting the postscript code and replacing @@ -1462,19 +1213,25 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) { } }; -var CFF = function(aFontFile) { +var CFF = function(aFontName, aFontBBox, aFontFile) { var start = Date.now(); + // Get the data block containing glyphs and subrs informations var length1 = aFontFile.dict.get("Length1"); var length2 = aFontFile.dict.get("Length2"); + aFontFile.skip(length1); + var eexecBlock = aFontFile.getBytes(length2); - var ASCIIStream = new Stream(aFontFile.getBytes(length1)); - var binaryStream = new Stream(aFontFile.getBytes(length2)); + // Extract informations from it + var parser = new Type1Parser(); + var fontInfo = parser.extractFontInfo(eexecBlock); + fontInfo.name = aFontName; + fontInfo.bbox = aFontBBox; - this.parser = new Type1Parser(ASCIIStream, binaryStream); - var fontName = this.parser.parse(); - this.font = PSFonts.get(fontName); - this.data = this.convertToCFF(this.font); + // XXX + this.glyphs = fontInfo.charstrings; + + this.data = this.convertToCFF(fontInfo); var end = Date.now(); //log("Time to parse font is:" + (end - start)); }; @@ -1537,11 +1294,11 @@ CFF.prototype = { } }, - getOrderedCharStrings: function(aFont) { + getOrderedCharStrings: function(aGlyphs) { var charstrings = []; - var glyphs = aFont.get("CharStrings") - glyphs.forEach(function(glyph, glyphData) { + for (var i = 0; i < aGlyphs.length; i++) { + var glyph = aGlyphs[i].glyph; var unicode = GlyphsUnicode[glyph]; if (!unicode) { if (glyph != ".notdef") @@ -1554,10 +1311,10 @@ CFF.prototype = { charstrings.push({ glyph: glyph, unicode: unicode, - charstring: glyphData.slice() + charstring: aGlyphs[i].data.slice() }); } - }); + }; charstrings.sort(function(a, b) { return a.unicode > b.unicode; @@ -1565,20 +1322,20 @@ CFF.prototype = { return charstrings; }, - convertToCFF: function(aFont) { + convertToCFF: function(aFontInfo) { var debug = false; function dump(aMsg) { if (debug) log(aMsg); }; - var charstrings = this.getOrderedCharStrings(aFont); + var charstrings = this.getOrderedCharStrings(aFontInfo.charstrings); var charstringsCount = 0; var charstringsDataLength = 0; var glyphs = []; var glyphsChecker = {}; - var subrs = aFont.get("Private").get("Subrs"); + var subrs = aFontInfo.subrs; var parser = new Type1Parser(); for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i].charstring.slice(); @@ -1604,19 +1361,18 @@ CFF.prototype = { cff.set(header); // Names Index - var nameIndex = this.createCFFIndexHeader([aFont.get("FontName")]); + var nameIndex = this.createCFFIndexHeader([aFontInfo.name]); cff.set(nameIndex, currentOffset); currentOffset += nameIndex.length; // Calculate strings before writing the TopDICT index in order // to calculate correct relative offsets for storing 'charset' // and 'charstrings' data - var fontInfo = aFont.get("FontInfo"); - var version = fontInfo.get("version"); - var notice = fontInfo.get("Notice"); - var fullName = fontInfo.get("FullName"); - var familyName = fontInfo.get("FamilyName"); - var weight = fontInfo.get("Weight"); + var version = ""; + var notice = ""; + var fullName = ""; + var familyName = ""; + var weight = ""; var strings = [version, notice, fullName, familyName, weight]; var stringsIndex = this.createCFFIndexHeader(strings); @@ -1692,7 +1448,7 @@ CFF.prototype = { 248, 31, 4 // Weight ]; - var fontBBox = aFont.get("FontBBox"); + var fontBBox = aFontInfo.bbox; for (var i = 0; i < fontBBox.length; i++) topDictIndex = topDictIndex.concat(this.encodeNumber(fontBBox[i])); topDictIndex.push(5) // FontBBox; diff --git a/test.js b/test.js index 1dffac549..0fdb2aacf 100644 --- a/test.js +++ b/test.js @@ -119,8 +119,10 @@ function displayPage(num) { } } + var fontBBox = descriptor.get("FontBBox"); + var subtype = fontDict.get("Subtype").name; - new Font(fontName, fontFile, encodingMap, charset, subtype); + new Font(fontName, fontFile, encodingMap, charset, fontBBox, subtype); return fontsReady = false; } else if (font.loading) { return fontsReady = false; From 97e8a563232d53aba0680a0febed845462946463 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 16 Jun 2011 01:09:17 +0200 Subject: [PATCH 031/439] Remove some useless JS function calls --- PDFFont.js | 82 +++++++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index e54f3ec4b..f052ecf9f 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -1096,9 +1096,9 @@ var Type1Parser = function() { token = ""; glyph = ""; - while ((c = eexecString[++i]) != 0x20 && i < count) + while ((c = eexecString[++i]) != 0x20) glyph += String.fromCharCode(c); - } else if (c == 0x2F && eexecString[i+1] == 0x53 && !inGlyphs && !inSubrs) { + } else if (!inSubrs && !inGlyphs && c == 0x2F && eexecString[i+1] == 0x53) { while ((c = eexecString[++i]) != 0x20) {}; inSubrs = true; } else if (c == 0x20) { @@ -1127,7 +1127,9 @@ var Type1Parser = function() { * chapter 8. */ this.flattenCharstring = function(aCharstring, aSubrs) { + var operandStackIndex = 0; operandStack.clear(); + executionStack.clear(); executionStack.push(aCharstring.slice()); @@ -1135,48 +1137,13 @@ var Type1Parser = function() { var lastPoint = 0; while (true) { var obj = nextInStack(); - if (IsBool(obj) || IsInt(obj) || IsNum(obj)) { - dump("Value: " + obj); + if (IsInt(obj) || IsBool(obj)) { operandStack.push(obj); - } else if (IsString(obj)) { - dump("String: " + obj); + } else { switch (obj) { - case "hsbw": - var charWidthVector = operandStack.pop(); - var leftSidebearing = operandStack.pop(); - operandStack.push(charWidthVector); - - if (leftSidebearing) { - operandStack.push(leftSidebearing); - operandStack.push("hmoveto"); - } - break; - - case "div": - var num2 = operandStack.pop(); - var num1 = operandStack.pop(); - operandStack.push(num2 / num1); - break; - - case "setcurrentpoint": - case "dotsection": - case "seac": - case "sbw": - error(obj + " parsing is not implemented (yet)"); - break; - - case "closepath": - case "return": - break; - case "vstem3": - case "vstem": - operandStack.push("vstem"); - break; - - case "hstem": case "hstem3": - operandStack.push("hstem"); + operandStack.push(obj.slice(0, 5)); break; case "callsubr": @@ -1196,12 +1163,40 @@ var Type1Parser = function() { operandStack.push("callothersubr"); break; + case "div": + var num2 = operandStack.pop(); + var num1 = operandStack.pop(); + operandStack.push(num2 / num1); + break; + + case "pop": + operandStack.pop(); + break; + + case "closepath": + case "return": + break; + + case "hsbw": + var charWidthVector = operandStack.pop(); + var leftSidebearing = operandStack.pop(); + operandStack.push(charWidthVector); + + if (leftSidebearing) { + operandStack.push(leftSidebearing); + operandStack.push("hmoveto"); + } + break; + case "endchar": operandStack.push("endchar"); return operandStack.clone(); - case "pop": - operandStack.pop(); + case "setcurrentpoint": + case "dotsection": + case "seac": + case "sbw": + error(obj + " parsing is not implemented (yet)"); break; default: @@ -1214,8 +1209,6 @@ var Type1Parser = function() { }; var CFF = function(aFontName, aFontBBox, aFontFile) { - var start = Date.now(); - // Get the data block containing glyphs and subrs informations var length1 = aFontFile.dict.get("Length1"); var length2 = aFontFile.dict.get("Length2"); @@ -1223,6 +1216,7 @@ var CFF = function(aFontName, aFontBBox, aFontFile) { var eexecBlock = aFontFile.getBytes(length2); // Extract informations from it + var start = Date.now(); var parser = new Type1Parser(); var fontInfo = parser.extractFontInfo(eexecBlock); fontInfo.name = aFontName; From 509d608a3a08f2dbfd6e20dd7a8ceb9ccc58db42 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 16 Jun 2011 01:30:47 +0200 Subject: [PATCH 032/439] Use spaces to compare font size to detect when the @font-face rule works, this seems to be more accurate --- PDFFont.js | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index f052ecf9f..a8205753e 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -131,12 +131,20 @@ Font.prototype = { // ready var debug = false; + if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); + } + var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (80 * fontCount) : "-200") + "px; left: 100px;"; + var style = "border: 1px solid black; position:absolute; top: " + + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; canvas.setAttribute("style", style); - canvas.setAttribute("width", 100); - canvas.setAttribute("heigth", 70); + canvas.setAttribute("width", 340); + canvas.setAttribute("heigth", 100); document.body.appendChild(canvas); // Retrieve font charset @@ -146,16 +154,21 @@ Font.prototype = { while (count-- && charset.length <= 30) charset = charset.concat(charset.slice()); - // Get the font size canvas think it will be + // Get the font size canvas think it will be for 'spaces' var ctx = canvas.getContext("2d"); - var testString = ""; - for (var i = 0; i < charset.length; i++) { - var unicode = new Number("0x" + GlyphsUnicode[charset[i]]); - if (!unicode) - error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); - testString += String.fromCharCode(unicode); + var testString = " "; + + // When debugging use the characters provided by the charsets to visually + // see what's happening + if (debug) { + for (var i = 0; i < charset.length; i++) { + var unicode = new Number("0x" + GlyphsUnicode[charset[i]]); + if (!unicode) + error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); + testString += String.fromCharCode(unicode); + } } - ctx.font = "20px " + fontName + ", Symbol"; + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; var textWidth = ctx.mozMeasureText(testString); if (debug) @@ -163,7 +176,7 @@ Font.prototype = { var start = Date.now(); var interval = window.setInterval(function(self) { - ctx.font = "20px " + fontName + ", Symbol"; + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; // For some reasons the font has not loaded, so mark it loaded for the // page to proceed but cry From 1923337bab3dd38e98bf1c66400a6d85d71ab139 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 16 Jun 2011 02:17:45 +0200 Subject: [PATCH 033/439] Change the nominalWidth to not use the format 28,b0,b1 but b0-139 in order to pass the sanitizer and disable TrueType support until it fully works --- PDFFont.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index a8205753e..8c3abc7ec 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -31,7 +31,7 @@ var fontCount = 0; var Fonts = { _active: null, get active() { - return this._active; + return this._active || { encoding: {} }; }, set active(aFontName) { @@ -39,12 +39,7 @@ var Fonts = { }, unicodeFromCode: function fonts_unicodeFromCode(aCode) { - var active = this._active; - if (!active || !active.encoding) - return aCode; - - var difference = active.encoding[aCode]; - var unicode = GlyphsUnicode[difference]; + var unicode = GlyphsUnicode[this.active.encoding[aCode]]; return unicode ? "0x" + unicode : aCode; } }; @@ -84,6 +79,15 @@ var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { break; case "TrueType": + return Fonts[aName] = { + data: null, + encoding: {}, + charset: null, + loading: false + }; + + // TrueType is disabled for the moment since the sanitizer prevent it + // from loading this.mimetype = "font/ttf"; var ttf = new TrueType(aFile); this.font = ttf.data; @@ -1140,9 +1144,7 @@ var Type1Parser = function() { * chapter 8. */ this.flattenCharstring = function(aCharstring, aSubrs) { - var operandStackIndex = 0; operandStack.clear(); - executionStack.clear(); executionStack.push(aCharstring.slice()); @@ -1434,8 +1436,7 @@ CFF.prototype = { log("Glyph " + i + " has a wrong value: " + c + " in charstring: " + data); log("the default value is glyph " + charstrings[i].glyph + " and is supposed to be: " + charstrings[i].charstring); } - for (var k = 0; k < bytes.length; k++) - charstring.push(bytes[k]); + charstring = charstring.concat(bytes); } } r.push(charstring); @@ -1503,7 +1504,7 @@ CFF.prototype = { var defaultWidth = this.encodeNumber(0); var privateData = [].concat( defaultWidth, [20], - defaultWidth, [21], + [139, 21], // nominalWidth [ 119, 159, 248, 97, 159, 247, 87, 159, 6, 30, 10, 3, 150, 37, 255, 12, 9, From c9e0b056782a306da7f980db00388e73e0798572 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 16 Jun 2011 03:55:45 +0200 Subject: [PATCH 034/439] Resolve the char->glyphs mapping issue --- PDFFont.js | 2 +- pdf.js | 15 +++++++++------ test.js | 19 +++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index d106e0b23..48554d9d1 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -31,7 +31,7 @@ var fontCount = 0; var Fonts = { _active: null, get active() { - return this._active || { encoding: {} }; + return this._active || { encoding: [] }; }, set active(aName) { diff --git a/pdf.js b/pdf.js index 2b7eb1e1b..fe636bcf9 100644 --- a/pdf.js +++ b/pdf.js @@ -795,7 +795,6 @@ var Lexer = (function() { } } - x = Fonts.unicodeFromCode(x); str += String.fromCharCode(x); break; case '\r': @@ -811,8 +810,7 @@ var Lexer = (function() { } break; default: - var unicode = Fonts.unicodeFromCode(ch.charCodeAt(0)); - str += String.fromCharCode(unicode); + str += ch; break; } } while (!done); @@ -1730,7 +1728,7 @@ var CanvasGraphics = (function() { var descriptor = xref.fetch(fontDict.get("FontDescriptor")); var fontName = descriptor.get("FontName").name; fontName = fontName.replace("+", "_"); - + var font = Fonts[fontName]; if (!font) { var fontFile = descriptor.get2("FontFile", "FontFile2"); @@ -1760,7 +1758,7 @@ var CanvasGraphics = (function() { for (var j = 0; j < widths.length; j++) { var index = widths[j]; if (index) - charset.push(encoding[j + firstchar]); + charset.push(encoding[j + firstchar]); } } } @@ -2054,7 +2052,12 @@ var CanvasGraphics = (function() { this.ctx.scale(1, -1); this.ctx.transform.apply(this.ctx, this.current.textMatrix); - this.ctx.fillText(text, this.current.x, this.current.y); + // Replace characters code by glyphs code + var glyphs = []; + for (var i = 0; i < text.length; i++) + glyphs[i] = String.fromCharCode(Fonts.unicodeFromCode(text[i].charCodeAt(0))); + + this.ctx.fillText(glyphs.join(""), this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; this.ctx.restore(); diff --git a/test.js b/test.js index 75b720002..d0d386872 100644 --- a/test.js +++ b/test.js @@ -1,7 +1,7 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ -var pdfDocument, canvas, pageDisplay, pageNum, pageTimeout; +var pdfDocument, canvas, pageDisplay, pageNum, pageInterval; function load() { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; @@ -48,7 +48,7 @@ function gotoPage(num) { function displayPage(num) { if (pageNum != num) - window.clearTimeout(pageTimeout); + window.clearTimeout(pageInterval); document.getElementById("pageNumber").value = num; @@ -57,7 +57,6 @@ function displayPage(num) { var page = pdfDocument.getPage(pageNum = num); var t1 = Date.now(); - var ctx = canvas.getContext("2d"); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; @@ -73,17 +72,21 @@ function displayPage(num) { page.compile(gfx, fonts); var t2 = Date.now(); - var interval = setInterval(function() { + // FIXME This need to be replaced by an event + pageInterval = setInterval(function() { for (var i = 0; i < fonts.length; i++) { if (fonts[i].loading) return; } - - page.display(gfx); var t3 = Date.now(); + + clearInterval(pageInterval); + page.display(gfx); + + var t4 = Date.now(); + var infoDisplay = document.getElementById("info"); - infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms"; - clearInterval(interval); + infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; }, 10); } From 327e36b347102f7ed3cd76243dcae38b3b50e63d Mon Sep 17 00:00:00 2001 From: Soumya Deb Date: Thu, 16 Jun 2011 12:14:02 +0530 Subject: [PATCH 035/439] Test-page updated to allow the user open local PDFs --- test.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test.html b/test.html index 9cadf2e1f..aea4ec5ba 100644 --- a/test.html +++ b/test.html @@ -46,13 +46,16 @@ function queryParams() { } var canvas, numPages, pageDisplay, pageNum; -function load() { +function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; pageDisplay = document.getElementById("pageNumber"); infoDisplay = document.getElementById("info"); pageNum = parseInt(queryParams().page) || 1; - fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; + fileName = userInput; + if(!userInput){ + fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; + } open(fileName); } @@ -132,6 +135,9 @@ function gotoPage(num) {
+ + Date: Thu, 16 Jun 2011 09:34:43 +0200 Subject: [PATCH 036/439] Remove some debug leftovers and add some comments about future directions for the code --- PDFFont.js | 192 +++++++++++++++++++++++++++++++----------------- PDFFontUtils.js | 21 +++++- 2 files changed, 142 insertions(+), 71 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 48554d9d1..4278ae29a 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -16,10 +16,10 @@ var kMaxGlyphsCount = 65526; */ var kMaxWaitForFontFace = 1000; - /* - * Useful for debugging when you want to certains operations depending on how - * many fonts are loaded. - */ +/** + * Useful for debugging when you want to certains operations depending on how + * many fonts are loaded. + */ var fontCount = 0; /** @@ -55,7 +55,7 @@ var Fonts = { * As an improvment the last parameter can be replaced by an automatic guess * of the font type based on the first byte of the file. * - * XXX There is now too many parameters, this should be turned into an + * FIXME There is now too many parameters, this should be turned into an * object containing all the required informations about the font */ var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { @@ -110,6 +110,15 @@ var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { this.bind(); }; + +/** + * A bunch of the OpenType code is duplicate between this class and the + * TrueType code, this is intentional and will merge in a future version + * where all the code relative to OpenType will probably have its own + * class and will take decision without the Fonts consent. + * But at the moment it allows to develop around the TrueType rewriting + * on the fly without messing up with the 'regular' Type1 to OTF conversion. + */ Font.prototype = { name: null, font: null, @@ -477,7 +486,6 @@ Font.prototype = { /** HMTX */ hmtx = [0x01, 0xF4, 0x00, 0x00]; for (var i = 0; i < charstrings.length; i++) { - // XXX this can easily broke var charstring = charstrings[i].charstring; var width = FontsUtils.integerToBytes(charstring[1], 2); var lsb = FontsUtils.integerToBytes(charstring[0], 2); @@ -503,7 +511,7 @@ Font.prototype = { this._createTableEntry(otf, offsets, "name", name); /** POST */ - // XXX get those info from the Font dict! + // FIXME Get those informations from the FontInfo structure post = [ 0x00, 0x03, 0x00, 0x00, // Version number 0x00, 0x00, 0x01, 0x00, // italicAngle @@ -528,13 +536,15 @@ Font.prototype = { var fontData = []; for (var i = 0; i < offsets.currentOffset; i++) fontData.push(otf[i]); - - //writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".otf"); return fontData; } }; +/** + * FontsUtils is a static class dedicated to hold codes that are not related + * to fonts in particular and needs to be share between them. + */ var FontsUtils = { integerToBytes: function fu_integerToBytes(aValue, aBytesCount) { var bytes = []; @@ -549,7 +559,7 @@ var FontsUtils = { return bytes; }, - bytesToInteger: function(aBytesArray) { + bytesToInteger: function fu_bytesToInteger(aBytesArray) { var value = 0; for (var i = 0; i < aBytesArray.length; i++) value = (value << 8) + aBytesArray[i]; @@ -575,9 +585,14 @@ var FontsUtils = { /** Implementation dirty logic starts here */ /** - * At the moment TrueType is just a stub that does mostly nothing but in a - * (near?) future this class will rewrite the font to ensure it is well formed - * and valid in the point of view of the sanitizer. + * The TrueType class verify that the ttf embedded inside the PDF is correct in + * the point of view of the OTS sanitizer and rewrite it on the fly otherwise. + * + * At the moment the rewiting only support rewriting missing 'OS/2' table. + * This class is unused at the moment since the 'cmap' table of the test + * document is not missing but use and old version of the 'cmap' table that + * is deprecated and not supported by the sanitizer... + * */ var TrueType = function(aFile) { var header = this._readOpenTypeHeader(aFile); @@ -604,6 +619,8 @@ var TrueType = function(aFile) { tables.push(table); } + + // Tables needs to be written by ascendant alphabetic order tables.sort(function(a, b) { return a.tag > b.tag; }); @@ -714,7 +731,6 @@ var TrueType = function(aFile) { fontData.push(ttf[i]); this.data = ttf; - //writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".ttf"); return; } else if (requiredTables.lenght) { error("Table " + requiredTables[0] + " is missing from the TruType font"); @@ -825,6 +841,7 @@ TrueType.prototype = { } }; + /** * This dictionary holds decoded fonts data. */ @@ -954,19 +971,58 @@ var Type1Parser = function() { "6": "hlineto", "7": "vlineto", "8": "rrcurveto", - "9": "closepath", + + // closepath is a Type1 command that do not take argument and is useless + // in Type2 and it can simply be ignored. + "9": null, // closepath + "10": "callsubr", + + // return is normally used inside sub-routines to tells to the execution + // flow that it can be back to normal. + // During the translation process Type1 charstrings will be flattened and + // sub-routines will be embedded directly into the charstring directly, so + // this can be ignored safely. "11": "return", + "12": { - "0": "dotsection", - "1": "vstem3", - "3": "hstem3", - "6": "seac", - "7": "sbw", + // dotsection is a Type1 command to specify some hinting feature for dots + // that do not take a parameter and it can safely be ignored for Type2. + "0": null, // dotsection + + // [vh]stem3 are Type1 only and Type2 supports [vh]stem with multiple + // parameters, so instead of returning [vh]stem3 take a shortcut and + // return [vhstem] instead. + "1": "vstem", + "2": "hstem", + + // Type1 only command with command not (yet) built-in ,throw an error + "6": -1, // seac + "7": -1, //sbw + "12": "div", + + // callothersubr is a mechanism to make calls on the postscript + // interpreter. + // TODO When decodeCharstring encounter such a command it should + // directly do: + // - pop the previous charstring[] command into 'index' + // - pop the previous charstring[] command and ignore it, it is + // normally the number of element to push on the stack before + // the command but since everything will be pushed on the stack + // by the PS interpreter when it will read them that is safe to + // ignore this command + // - push the content of the OtherSubrs[index] inside charstring[] "16": "callothersubr", + "17": "pop", - "33": "setcurrentpoint" + + // setcurrentpoint sets the current point to x, y without performing a + // moveto (this is a one shot positionning command). This is used only + // with the return of an OtherSubrs call. + // TODO Implement the OtherSubrs charstring embedding and replace this + // call by a no-op, like 2 'pop' commands for example. + "33": null, //setcurrentpoint }, "13": "hsbw", "14": "endchar", @@ -986,12 +1042,27 @@ var Type1Parser = function() { value = aStream.getByte(); if (value < 32) { + var command = null; if (value == 12) { - value = charStringDictionary["12"][aStream.getByte()]; + var escape = aStream.getByte(); + command = charStringDictionary["12"][escape]; i++; } else { - value = charStringDictionary[value]; + command = charStringDictionary[value]; } + + // Some charstring commands are meaningless in Type2 and will return + // a null, let's just ignored them + if (!command && i < count) + continue; + else if (!command) + break; + else if (command == -1) { + log("decodeCharstring: " + charString); + error("Support for Type1 command " + value + " (" + escape + ") is not implemented"); + } + + value = command; } else if (value <= 246) { value = parseInt(value) - 139; } else if (value <= 250) { @@ -1140,7 +1211,7 @@ var Type1Parser = function() { * Flatten the commands by interpreting the postscript code and replacing * every 'callsubr', 'callothersubr' by the real commands. * At the moment OtherSubrs are not fully supported and only otherSubrs 0-4 - * as descrived in 'Using Subroutines' of 'Adobe Type 1 Font Format', + * as described in 'Using Subroutines' of 'Adobe Type 1 Font Format', * chapter 8. */ this.flattenCharstring = function(aCharstring, aSubrs) { @@ -1156,11 +1227,6 @@ var Type1Parser = function() { operandStack.push(obj); } else { switch (obj) { - case "vstem3": - case "hstem3": - operandStack.push(obj.slice(0, 5)); - break; - case "callsubr": var index = operandStack.pop(); executionStack.push(aSubrs[index].slice()); @@ -1188,7 +1254,6 @@ var Type1Parser = function() { operandStack.pop(); break; - case "closepath": case "return": break; @@ -1207,13 +1272,6 @@ var Type1Parser = function() { operandStack.push("endchar"); return operandStack.clone(); - case "setcurrentpoint": - case "dotsection": - case "seac": - case "sbw": - error(obj + " parsing is not implemented (yet)"); - break; - default: operandStack.push(obj); break; @@ -1345,6 +1403,20 @@ CFF.prototype = { var glyphs = []; var glyphsChecker = {}; var subrs = aFontInfo.subrs; + + // FIXME This code is actually the only reason the dummy PS Interpreter + // called Type1Parser continue to lives, basically the goal here is + // to embed the OtherSubrs/Subrs into the charstring directly. + // But since Type2 charstrings use a bias to index Subrs and can + // theorically store twice the number of Type1 we could directly + // save the OtherSubrs and Subrs in the Type2 table for Subrs + // and avoid this 'flattening' slow method. + // + // The other thinds done by this method is splitting the initial + // 'width lsb hswb' command of Type1 to something similar in Type2 + // that is: 'width dx moveto' but this can be done in the + // decodeCharstring method directly (maybe one day it will be called + // translateCharstring?) var parser = new Type1Parser(); for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i].charstring.slice(); @@ -1417,7 +1489,11 @@ CFF.prototype = { "hvcurveto": 31, }; - // Encode the glyph and add it to the FUX + // FIXME Concatenating array with this algorithm (O²) is expensive and + // can be avoided if the voodoo's dance of charstrings decoding + // encoding is left for dead. Actually charstrings command number + // are converted to a string and then back to a number with the + // next few lines of code... var r = [[0x40, 0x0E]]; for (var i = 0; i < glyphs.length; i++) { var data = glyphs[i].slice(); @@ -1427,7 +1503,7 @@ CFF.prototype = { if (!IsNum(c)) { var token = getNumFor[c]; if (!token) - error(c); + error("Token " + c + " is not recognized in charstring " + data); charstring.push(token); } else { try { @@ -1445,7 +1521,6 @@ CFF.prototype = { var charstringsIndex = this.createCFFIndexHeader(r, true); charstringsIndex = charstringsIndex.join(" ").split(" "); // XXX why? - //Top Dict Index var topDictIndex = [ 0x00, 0x01, 0x01, 0x01, 0x30, @@ -1480,25 +1555,17 @@ CFF.prototype = { topDictIndex.push(18); // Private topDictIndex = topDictIndex.join(" ").split(" "); - // Top Dict Index - cff.set(topDictIndex, currentOffset); - currentOffset += topDictIndex.length; + var indexes = [ + topDictIndex, stringsIndex, + globalSubrsIndex, charset, + charstringsIndex + ]; - // Strings Index - cff.set(stringsIndex, currentOffset); - currentOffset += stringsIndex.length; - - // Global Subrs Index - cff.set(globalSubrsIndex, currentOffset); - currentOffset += globalSubrsIndex.length; - - // Charset Index - cff.set(charset, currentOffset); - currentOffset += charset.length; - - // Fill charstrings data - cff.set(charstringsIndex, currentOffset); - currentOffset += charstringsIndex.length; + for (var i = 0; i < indexes.length; i++) { + var index = indexes[i]; + cff.set(index, currentOffset); + currentOffset += index.length; + } // Private Data var defaultWidth = this.encodeNumber(0); @@ -1532,19 +1599,10 @@ CFF.prototype = { cff.set(shit, currentOffset); currentOffset += shit.length; - - dump("==================== debug ===================="); - //var file = new Uint8Array(cff, 0, currentOffset); - //var parser = new Type2Parser(); - //parser.parse(new Stream(file)); - var fontData = []; for (var i = 0; i < currentOffset; i++) fontData.push(cff[i]); - //log("== write to file"); - //writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff"); - return fontData; } }; diff --git a/PDFFontUtils.js b/PDFFontUtils.js index 072dd48f1..e242121db 100644 --- a/PDFFontUtils.js +++ b/PDFFontUtils.js @@ -349,13 +349,26 @@ var Type2Parser = function(aFilePath) { }; /* -var cff = new Type2Parser("test.cff"); -cff.parse(); -*/ + * 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 (works only on Firefox in privilege mode"); + * 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"); From d7205753924e7e14bb65b231f1c6234da5261173 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Thu, 16 Jun 2011 09:37:15 -0700 Subject: [PATCH 037/439] add blogs and twitter link --- README | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README b/README index 18817c340..ee537f0a5 100644 --- a/README +++ b/README @@ -1,3 +1,12 @@ pdf.js is a technology demonstrator prototype to explore whether the HTML5 platform is complete enough to faithfully and efficiently render the ISO 32000-1:2008 Portable Document Format (PDF) without native code assistance. + +You can read more about pdf.js here: + +http://andreasgal.com/2011/06/15/pdf-js/ +http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/ + +Or follow us on twitter: @pdfjs + +http://twitter.com/#!/pdfjs From 5fa49ce3d6d9545a728ecc562c13df051c877308 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 16 Jun 2011 11:26:50 -0700 Subject: [PATCH 038/439] working version of tiling --- pdf.js | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 17537d233..771b18c30 100644 --- a/pdf.js +++ b/pdf.js @@ -1590,8 +1590,38 @@ var CanvasExtraState = (function() { // Start of text line (in text coordinates) this.lineX = 0.0; this.lineY = 0.0; + + this.transMatrix = IDENTITY_MATRIX; } constructor.prototype = { + applyTransform: function(point) { + var m = this.transMatrix + var x = point[0] * m[0] + point[1] * m[2] + m[4]; + var y = point[0] * m[1] + point[1] * m[3] + m[5]; + return [x,y]; + }, + concatTransform: function(m) { + var tm = this.transMatrix; + + var a = m[0] * tm[0] + m[1] * tm[2]; + var b = m[0] * tm[1] + m[1] * tm[3]; + var c = m[2] * tm[0] + m[3] * tm[2]; + var d = m[2] * tm[1] + m[3] * tm[3]; + var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; + var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; + this.transMatrix = [a, b, c, d, e, f] + }, + getInvTransform: function(matrix) { + var m = this.transMatrix; + var det = 1 / (m[0] * m[3] - m[1] * m[2]); + var a = m[3] * det; + var b = -m[1] * det; + var c = -m[2] * det; + var d = m[0] * det; + var e = (m[2] * m[5] - m[3] * m[4]) * det; + var f = (m[1] * m[4] - m[0] * m[5]) * det; + return [a, b, c, d, e, f] + } }; return constructor; })(); @@ -1851,6 +1881,7 @@ var CanvasGraphics = (function() { }, transform: function(a, b, c, d, e, f) { this.ctx.transform(a, b, c, d, e, f); + this.current.concatTransform([a,b,c,d,e,f]); }, // Path @@ -2023,6 +2054,11 @@ var CanvasGraphics = (function() { }, setFillColorSpace: function(space) { // TODO real impl + if (space.name === "Pattern") { + this.colorspace = "Pattern"; + } else { + this.colorspace = null; + } }, setStrokeColor: function(/*...*/) { // TODO real impl @@ -2046,7 +2082,104 @@ var CanvasGraphics = (function() { }, setFillColorN: function(/*...*/) { // TODO real impl - this.setFillColor.apply(this, arguments); + var args = arguments; + if (this.colorspace == "Pattern") { + var patternName = args[0]; + if (IsName(patternName)) { + var xref = this.xref; + var patternRes = xref.fetchIfRef(this.res.get("Pattern")); + if (!patternRes) + error("Unable to find pattern resource"); + + var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); + + var type = pattern.dict.get("PatternType"); + if (type === 1) { + this.tilingFill(pattern); + } else { + error("Unhandled pattern type"); + } + } + } else { + // TODO real impl + this.setFillColor.apply(this, arguments); + } + }, + tilingFill: function(pattern) { + this.save(); + var dict = pattern.dict; + + var paintType = dict.get("PaintType"); + if (paintType == 2) { + error("Unsupported paint type"); + } else { + // should go to default for color space + this.ctx.fillStyle = this.makeCssRgb(1, 1, 1); + this.ctx.strokeStyle = this.makeCssRgb(0, 0, 0); + } + + // not sure what to do with this + var tilingType = dict.get("TilingType"); + + var tempExtra = new CanvasExtraState(); + var matrix = dict.get("Matrix"); + if (matrix && IsArray(matrix) && 6 == matrix.length) + tempExtra.transMatrix = matrix; + + var bbox = dict.get("BBox"); + var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; + + var xstep = dict.get("XStep"); + var ystep = dict.get("YStep"); + + // top left corner should correspond to the top left of the bbox + var topLeft = tempExtra.applyTransform([x0,y0]); + // we want the canvas to be as large as the step size + var botRight = tempExtra.applyTransform([x0 + xstep, y0 + ystep]); + + var tmpCanvas = document.createElement("canvas"); + tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); + tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]); + + // set the new canvas element context as the graphics context + var tmpCtx = tmpCanvas.getContext("2d"); + var oldCtx = this.ctx; + this.ctx = tmpCtx; + + // normalize matrix transform so each step + // takes up the entire tmpCanvas + if (matrix[1] === 0 && matrix[2] === 0) { + matrix[0] = tmpCanvas.width / xstep; + matrix[3] = tmpCanvas.height / ystep; + tempExtra.transMatrix = matrix; + topLeft = tempExtra.applyTransform([x0,y0]); + } + + // move the top left corner of bounding box to [0,0] + tempExtra.transMatrix = [1, 0, 0, 1, -topLeft[0], -topLeft[1]]; + tempExtra.concatTransform(matrix); + matrix = tempExtra.transMatrix; + + this.transform.apply(this, matrix); + + if (bbox && IsArray(bbox) && 4 == bbox.length) { + this.rectangle.apply(this, bbox); + this.clip(); + this.endPath(); + } + + var xref = this.xref; + var res = xref.fetchIfRef(dict.get("Resources")); + if (!pattern.code) + pattern.code = this.compile(pattern, xref, res, []); + this.execute(pattern.code, xref, res); + + // set the old context + this.ctx = oldCtx; + this.restore(); + + var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); + this.ctx.fillStyle = pattern; }, setStrokeGray: function(gray) { this.setStrokeRGBColor(gray, gray, gray); From 72919470a993ea68e427e80a619235f136aae668 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 16 Jun 2011 12:03:50 -0700 Subject: [PATCH 039/439] Added comments --- pdf.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pdf.js b/pdf.js index 17537d233..904ff3906 100644 --- a/pdf.js +++ b/pdf.js @@ -2134,6 +2134,10 @@ var CanvasGraphics = (function() { fn = new PDFFunction(this.xref, fnObj); var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); + + // 10 samples seems good enough for now, but probably won't work + // if there are sharp color changes. Ideally, we could see the + // current image size and base the # samples on that. var step = (t1 - t0) / 10; for (var i = t0; i <= t1; i += step) { @@ -2146,6 +2150,8 @@ var CanvasGraphics = (function() { // HACK to draw the gradient onto an infinite rectangle. // PDF gradients are drawn across the entire image while // Canvas only allows gradients to be drawn in a rectangle + // Also, larger numbers seem to cause overflow which causes + // nothing to be drawn. this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); }, From 4959dcb6a9f6b2e3050bda9f8fe442771c99aa29 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 16 Jun 2011 17:03:15 -0700 Subject: [PATCH 040/439] initial implementation of predictor --- pdf.js | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 904ff3906..c2b8f160f 100644 --- a/pdf.js +++ b/pdf.js @@ -230,7 +230,24 @@ var FlateStream = (function() { 0x50007, 0x50017, 0x5000f, 0x00000 ]), 5]; - function constructor(stream) { + function constructor(stream, params) { + if (IsDict(params)) { + var predType = params.get("Predictor"); + if (predType && predType > 1) { + var colors = params.get("Colors"); + if (!colors) + colors = 1; + var bpc = params.get("BitsPerComponent"); + if (!bpc) + bpc = 8; + var cols = params.get("Columns"); + if (!cols) + cols = 1; + + this.pred = new FilterPredictor(this, predType, cols, + colors, bpc); + } + } this.stream = stream; this.dict = stream.dict; var cmf = stream.getByte(); @@ -506,6 +523,163 @@ var FlateStream = (function() { return constructor; })(); +var FilterPredictor = (function() { + function constructor(str, type, width, colors, bits) { + this.str = str; + this.type = type; + this.width = width; + this.colors = colors; + this.bits = bits; + + this.nVals = width * colors; + this.pixBytes = (colors * bits + 7) >> 3; + var rowBytes = (width * colors * bits + 7) >> 3; + this.rowBytes = rowBytes; + + if (width < 0 || colors < 0 || bits < 0 ||bits > 16) + error("Invalid predictor"); + + var prevLine = []; + for (var i = 0; i < rowBytes; ++i) + prevLine.push(0); + this.prevLine = prevLine; + this.prevIdx = rowBytes; + } + + constructor.prototype = { + getByte: function() { + if (this.prevIdx >= this.rowBytes) { + if(!this.getNextLine()) + return; + } + return this.prevLine[this.prevIdx]; + }, + getNextLine: function() { + if (this.type >= 10) { + var curType = this.str.getRawByte(); + if (!curType) + return; + curType += 10; + } else { + var curType = this.type; + } + + var line = []; + for (var i = 0; i < this.rowBytes - this.pixBytes; i++) + line.push(this.str.getRawByte()); + + var pixBytes = this.pixBytes; + var rowBytes = this.rowBytes; + var prevLine = this.prevLine; + + var upLeftBuf = []; + for (var i = 0, ii = pixBytes + 1; i < ii; ++i) + upLeftBuf.push(0); + + for (var i = pixBytes, ii = rowBybtes; i < ii; ++i) { + for (var j = pixBytes; j > 0; --j) { + upLeftBuf[j] = upLeftBuf[j - 1]; + upLeftBuf[0] = prevLine[i]; + + var c = line[i - pixBytes]; + if (!c) { + if (i > pixBytes) + break; + return; + } + switch (curType) { + case 11: + prevLine[i] = prevLine[i - pixBytes] + c; + break; + case 12: + prevLine[i] = prevLine[i] + c; + break; + case 13: + prevLine[i] = ((prevLine[i - pixBytes] + + prevLine[i]) >> 1) + c; + break; + case 14: + var left = prevLine[i - pixBytes]; + var up = prevLine[i]; + var upLeft = upLeftBuf[pixBytes]; + var p = left + up - upLeft; + + var pa = p - left; + if (pa < 0) + pa = -pa; + var pb = p - up; + if (pb < 0) + pb = -pb; + var pc = p - upLeft; + if (pc < 0) + pc = -pc; + + if (pa <= pb && pa <= pc) + prevLine[i] = left + c; + else if (pb <= pc) + prevLine[i] = up + c; + else + prevLine[i] = upLeft + c; + break; + case 10: + default: + prevLine[i] = c; + break; + } + } + } + var bits = this.bits; + var colors = this.colors; + + if (curPred === 2) { + if (bits === 1) { + var inbuf = prevLine[pixBytes - 1]; + for (var i = pixBytes; i < rowBytes; i+= 8) { + inBuf = (inBuf << 8) | prevLine[i]; + prevLine[i] ^= inBuf >> colors; + } + } else if (bits === 8) { + for (var i = pixBytes; i < rowBytes; ++i) + prevLine[i] += prevLine[i - colors]; + } else { + for (var i = 0, ii = colors + 1; i < ii; ++i) + upLeftBuf[i] = 0; + var bitMask = (1 << bits) - 1; + var inbuf = 0, outbut = 0; + var inbits = 0, outbits = 0; + var j = pixBytes, k = pixBytes; + var width = this.width; + for (var i = 0; i < width; ++i) { + for (var kk = 0; kk < colors; ++kk) { + if (inbits < bits) { + inbuf = (inbuf << 8) | (prevLine[j++] & 255); + inbits += 8; + } + upLeftBuf[kk] = (upLeftBuf[kk] + (inbuf >> + (inbits - bits))) & bitMask; + inbits -= bits; + outbuf = (outbuf << bits) | upLeftBuf[kk]; + outbits += bits; + if (outbits >= 8) { + prevLine[k++] = (outbuf >> (outbits - 8)); + outbits -= 8; + } + } + } + if (outbits > 0) { + prevLine[k++] = (outbuf << (8 - outbits)) + + (inbuf & ((1 << (8 - outbits)) - 1)) + } + } + } + prevIdx = pixBytes; + return true; + } + }; + + return constructor; +})(); + var DecryptStream = (function() { function constructor(str, fileKey, encAlgorithm, keyLength) { // TODO From eb6f7499dc8c556ef3f8f4e40d346f6bf194953a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 06:02:29 +0200 Subject: [PATCH 041/439] Rework some code to enhance performance (CIIM6/CIIM9 are rejected by the sanitizer now) --- PDFFont.js | 338 ++++++++++++++++++++---------------------------- PDFFontUtils.js | 3 +- 2 files changed, 142 insertions(+), 199 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 4278ae29a..1bf437066 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -546,7 +546,14 @@ Font.prototype = { * to fonts in particular and needs to be share between them. */ var FontsUtils = { + _bytesArray: new Uint8Array(4), integerToBytes: function fu_integerToBytes(aValue, aBytesCount) { + // If we want only one byte, take a fast path + if (aBytesCount == 1) { + this._bytesArray.set([aValue]); + return this._bytesArray[0]; + } + var bytes = []; for (var i = 0; i < aBytesCount; i++) bytes[i] = 0x00; @@ -1087,61 +1094,6 @@ var Type1Parser = function() { return charString; }; - /* - * The operand stack holds arbitrary PostScript objects that are the operands - * and results of PostScript operators being executed. The interpreter pushes - * objects on the operand stack when it encounters them as literal data in a - * program being executed. When an operator requires one or more operands, it - * obtains them by popping them off the top of the operand stack. When an - * operator returns one or more results, it does so by pushing them on the - * operand stack. - */ - var operandStack = new Stack(40); - - // Flag indicating if the topmost operand of the operandStack is an array - var operandIsArray = 0; - - /* - * The dictionary stack holds only dictionary objects. The current set of - * dictionaries on the dictionary stack defines the environment for all - * implicit name searches, such as those that occur when the interpreter - * encounters an executable name. The role of the dictionary stack is - * introduced in Section 3.3, “Data Types and Objects,” and is further - * explained in Section 3.5, “Execution.” of the PostScript Language - * Reference. - */ - var systemDict = new Dict(), - globalDict = new Dict(), - userDict = new Dict(); - - var dictionaryStack = new Stack(); - dictionaryStack.push(systemDict); - dictionaryStack.push(globalDict); - dictionaryStack.push(userDict); - - /* - * The execution stack holds executable objects (mainly procedures and files) - * that are in intermediate stages of execution. At any point in the - * execution of a PostScript program, this stack represents the program’s - * call stack. Whenever the interpreter suspends execution of an object to - * execute some other object, it pushes the new object on the execution - * stack. When the interpreter finishes executing an object, it pops that - * object off the execution stack and resumes executing the suspended object - * beneath it. - */ - var executionStack = new Stack(); - - /* - * Return the next token in the execution stack - */ - function nextInStack() { - var currentProcedure = executionStack.peek(); - var command = currentProcedure.shift(); - if (!currentProcedure.length) - executionStack.pop(); - return command; - }; - /** * Returns an object containing a Subrs array and a CharStrings array * extracted from and eexec encrypted block of data @@ -1205,79 +1157,6 @@ var Type1Parser = function() { subrs: subrs, charstrings: glyphs } - }; - - /* - * Flatten the commands by interpreting the postscript code and replacing - * every 'callsubr', 'callothersubr' by the real commands. - * At the moment OtherSubrs are not fully supported and only otherSubrs 0-4 - * as described in 'Using Subroutines' of 'Adobe Type 1 Font Format', - * chapter 8. - */ - this.flattenCharstring = function(aCharstring, aSubrs) { - operandStack.clear(); - executionStack.clear(); - executionStack.push(aCharstring.slice()); - - var leftSidebearing = 0; - var lastPoint = 0; - while (true) { - var obj = nextInStack(); - if (IsInt(obj) || IsBool(obj)) { - operandStack.push(obj); - } else { - switch (obj) { - case "callsubr": - var index = operandStack.pop(); - executionStack.push(aSubrs[index].slice()); - break; - - case "callothersubr": - var index = operandStack.pop(); - var count = operandStack.pop(); - var data = operandStack.pop(); - // XXX The callothersubr needs to support at least the 3 defaults - // otherSubrs of the spec - if (index != 3) - error("callothersubr for index: " + index); - operandStack.push(3); - operandStack.push("callothersubr"); - break; - - case "div": - var num2 = operandStack.pop(); - var num1 = operandStack.pop(); - operandStack.push(num2 / num1); - break; - - case "pop": - operandStack.pop(); - break; - - case "return": - break; - - case "hsbw": - var charWidthVector = operandStack.pop(); - var leftSidebearing = operandStack.pop(); - operandStack.push(charWidthVector); - - if (leftSidebearing) { - operandStack.push(leftSidebearing); - operandStack.push("hmoveto"); - } - break; - - case "endchar": - operandStack.push("endchar"); - return operandStack.clone(); - - default: - operandStack.push(obj); - break; - } - } - } } }; @@ -1339,10 +1218,11 @@ CFF.prototype = { return data; }, - encodeNumber: function(aValue) { + encodeNumber: function(aValue, aIsCharstring) { var x = 0; - // XXX we don't really care about Type2 optimization here... - if (aValue >= -32768 && aValue <= 32767) { + if (aIsCharstring && aValue >= -107 && aValue <= 107) { + return [aValue + 139]; + } else if (aValue >= -32768 && aValue <= 32767) { return [ 28, FontsUtils.integerToBytes(aValue >> 8, 1), @@ -1389,6 +1269,128 @@ CFF.prototype = { return charstrings; }, + /* + * Flatten the commands by interpreting the postscript code and replacing + * every 'callsubr', 'callothersubr' by the real commands. + * + * TODO This function also do a string to command number transformation + * that can probably be avoided if the Type1 decodeCharstring code is smarter + */ + commandsMap: { + "hstem": 1, + "vstem": 3, + "vmoveto": 4, + "rlineto": 5, + "hlineto": 6, + "vlineto": 7, + "rrcurveto": 8, + "endchar": 14, + "rmoveto": 21, + "hmoveto": 22, + "vhcurveto": 30, + "hvcurveto": 31, + }, + + flattenCharstring: function(aCharstring, aSubrs) { + var i = 0; + while (true) { + var obj = aCharstring[i]; + if (IsString(obj)) { + switch (obj) { + case "callsubr": + var subr = aSubrs[aCharstring[i- 1]].slice(); + if (subr.length > 1) { + subr = this.flattenCharstring(subr, aSubrs); + subr.pop(); + aCharstring.splice(i - 1, 2, subr); + } + else + aCharstring.splice(i - 1, 2); + + i -= 1; + break; + + case "callothersubr": + var index = aCharstring[i - 1]; + var count = aCharstring[i - 2]; + var data = aCharstring[i - 3]; + + // XXX The callothersubr needs to support at least the 3 defaults + // otherSubrs of the spec + if (index != 3) + error("callothersubr for index: " + index + " (" + aCharstring + ")"); + + if (!data) { + aCharstring.splice(i - 2, 3, "pop", 3); + i -= 2; + } else { + // 5 to remove the arguments, the callothersubr call and the pop command + aCharstring.splice(i - 3, 5, 3); + i -= 3; + } + break; + + case "div": + var num2 = aCharstring[i - 1]; + var num1 = aCharstring[i - 2]; + aCharstring.splice(i - 2, 3, num2 / num1); + i -= 2; + break; + + case "pop": + aCharstring.splice(i - 2, 2); + i -= 1; + break; + + + case "hsbw": + var charWidthVector = aCharstring[i - 1]; + var leftSidebearing = aCharstring[i - 2]; + aCharstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto"); + break; + + case "endchar": + case "return": + // CharString is ready to be re-encode to commands number at this point + for (var j = 0; j < aCharstring.length; j++) { + var command = aCharstring[j]; + if (IsNum(command)) { + var number = this.encodeNumber(command, true); + aCharstring.splice(j, 1); + for (var k = 0; k < number.length; k++) + aCharstring.splice(j + k, 0, number[k]); + j+= number.length - 1; + } else if (IsString(command)) { + var command = this.commandsMap[command]; + if (IsArray(command)) { + aCharstring.splice(j - 1, 1, command[0], command[1]); + j += 1; + } else { + aCharstring[j] = command; + } + } else if (IsArray(command)) { + aCharstring.splice(j, 1); + + // command has already been translated, just add them to the + // charstring directly + for (var k = 0; k < command.length; k++) + aCharstring.splice(j + k, 0, command[k]); + j+= command.length - 1; + } else { // what else? + error("Error while flattening the Type1 charstring: " + aCharstring); + } + } + return aCharstring; + + default: + break; + } + } + i++; + } + error("failing with i = " + i + " in charstring:" + aCharstring + "(" + aCharstring.length + ")"); + }, + convertToCFF: function(aFontInfo) { var debug = false; function dump(aMsg) { @@ -1398,39 +1400,24 @@ CFF.prototype = { var charstrings = this.getOrderedCharStrings(aFontInfo.charstrings); + // Starts the conversion of the Type1 charstrings to Type2 + var start = Date.now(); var charstringsCount = 0; var charstringsDataLength = 0; var glyphs = []; - var glyphsChecker = {}; - var subrs = aFontInfo.subrs; - - // FIXME This code is actually the only reason the dummy PS Interpreter - // called Type1Parser continue to lives, basically the goal here is - // to embed the OtherSubrs/Subrs into the charstring directly. - // But since Type2 charstrings use a bias to index Subrs and can - // theorically store twice the number of Type1 we could directly - // save the OtherSubrs and Subrs in the Type2 table for Subrs - // and avoid this 'flattening' slow method. - // - // The other thinds done by this method is splitting the initial - // 'width lsb hswb' command of Type1 to something similar in Type2 - // that is: 'width dx moveto' but this can be done in the - // decodeCharstring method directly (maybe one day it will be called - // translateCharstring?) - var parser = new Type1Parser(); for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i].charstring.slice(); var glyph = charstrings[i].glyph; - if (glyphsChecker[glyph]) - error("glyphs already exists!"); - glyphsChecker[glyph] = true; - var flattened = parser.flattenCharstring(charstring, subrs); + var flattened = this.flattenCharstring(charstring, aFontInfo.subrs); glyphs.push(flattened); charstringsCount++; charstringsDataLength += flattened.length; } + + var end = Date.now(); dump("There is " + charstringsCount + " glyphs (size: " + charstringsDataLength + ")"); + dump("Time to flatten the strings is : " + (end -start)); // Create a CFF font data var cff = new Uint8Array(kMaxFontFileSize); @@ -1473,52 +1460,7 @@ CFF.prototype = { charset.push(bytes[1]); } - // Convert charstrings - var getNumFor = { - "hstem": 1, - "vstem": 3, - "vmoveto": 4, - "rlineto": 5, - "hlineto": 6, - "vlineto": 7, - "rrcurveto": 8, - "endchar": 14, - "rmoveto": 21, - "hmoveto": 22, - "vhcurveto": 30, - "hvcurveto": 31, - }; - - // FIXME Concatenating array with this algorithm (O²) is expensive and - // can be avoided if the voodoo's dance of charstrings decoding - // encoding is left for dead. Actually charstrings command number - // are converted to a string and then back to a number with the - // next few lines of code... - var r = [[0x40, 0x0E]]; - for (var i = 0; i < glyphs.length; i++) { - var data = glyphs[i].slice(); - var charstring = []; - for (var j = 0; j < data.length; j++) { - var c = data[j]; - if (!IsNum(c)) { - var token = getNumFor[c]; - if (!token) - error("Token " + c + " is not recognized in charstring " + data); - charstring.push(token); - } else { - try { - var bytes = this.encodeNumber(c); - } catch(e) { - log("Glyph " + i + " has a wrong value: " + c + " in charstring: " + data); - log("the default value is glyph " + charstrings[i].glyph + " and is supposed to be: " + charstrings[i].charstring); - } - charstring = charstring.concat(bytes); - } - } - r.push(charstring); - } - - var charstringsIndex = this.createCFFIndexHeader(r, true); + var charstringsIndex = this.createCFFIndexHeader([[0x40, 0x0E]].concat(glyphs), true); charstringsIndex = charstringsIndex.join(" ").split(" "); // XXX why? //Top Dict Index diff --git a/PDFFontUtils.js b/PDFFontUtils.js index e242121db..086648fe2 100644 --- a/PDFFontUtils.js +++ b/PDFFontUtils.js @@ -310,7 +310,8 @@ var Type2Parser = function(aFilePath) { // 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); + var subrs = readFontIndexData(aStream, true); + dump(subrs); // Reading Private Dict var private = font.get("Private"); From 88512fbdd9fda60993ad718b97a407e81f5f33c1 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 06:06:24 +0200 Subject: [PATCH 042/439] Remove some leftovers from the previous patch --- PDFFont.js | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 1bf437066..4706121f2 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -589,8 +589,6 @@ var FontsUtils = { }; -/** Implementation dirty logic starts here */ - /** * The TrueType class verify that the ttf embedded inside the PDF is correct in * the point of view of the OTS sanitizer and rewrite it on the fly otherwise. @@ -852,49 +850,6 @@ TrueType.prototype = { /** * This dictionary holds decoded fonts data. */ -var PSFonts = new Dict(); - -var Stack = function(aStackSize) { - var innerStack = new Array(aStackSize || 0); - - this.push = function(aOperand) { - innerStack.push(aOperand); - }; - - this.pop = function() { - if (!this.count()) - throw new Error("stackunderflow"); - return innerStack.pop(); - }; - - this.peek = function() { - if (!this.count()) - return null; - return innerStack[innerStack.length - 1]; - }; - - this.get = function(aIndex) { - return innerStack[aIndex]; - }; - - this.clear = function() { - innerStack = []; - }; - - this.count = function() { - return innerStack.length; - }; - - this.dump = function() { - for (var i = 0; i < this.length; i++) - log(innerStack[i]); - }; - - this.clone = function() { - return innerStack.slice(); - }; -}; - var Type1Parser = function() { // Turn on this flag for additional debugging logs var debug = false; From 01847a0e29e93ad8585f2bbe5575c88b0a38e0e3 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 06:44:16 +0200 Subject: [PATCH 043/439] Get rid or IsNum/IsString/IsArray in flattenCharstring --- PDFFont.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 4706121f2..00637f2cf 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -188,7 +188,7 @@ Font.prototype = { ctx.fillText(testString, 20, 20); var start = Date.now(); - var interval = window.setInterval(function(self) { + var interval = window.setInterval(function canvasInterval(self) { ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; // For some reasons the font has not loaded, so mark it loaded for the @@ -1250,7 +1250,7 @@ CFF.prototype = { var i = 0; while (true) { var obj = aCharstring[i]; - if (IsString(obj)) { + if (obj.charAt) { switch (obj) { case "callsubr": var subr = aSubrs[aCharstring[i- 1]].slice(); @@ -1309,13 +1309,13 @@ CFF.prototype = { // CharString is ready to be re-encode to commands number at this point for (var j = 0; j < aCharstring.length; j++) { var command = aCharstring[j]; - if (IsNum(command)) { + if (parseFloat(command) == command) { var number = this.encodeNumber(command, true); aCharstring.splice(j, 1); for (var k = 0; k < number.length; k++) aCharstring.splice(j + k, 0, number[k]); j+= number.length - 1; - } else if (IsString(command)) { + } else if (command.charAt) { var command = this.commandsMap[command]; if (IsArray(command)) { aCharstring.splice(j - 1, 1, command[0], command[1]); @@ -1323,7 +1323,7 @@ CFF.prototype = { } else { aCharstring[j] = command; } - } else if (IsArray(command)) { + } else { aCharstring.splice(j, 1); // command has already been translated, just add them to the @@ -1331,8 +1331,6 @@ CFF.prototype = { for (var k = 0; k < command.length; k++) aCharstring.splice(j + k, 0, command[k]); j+= command.length - 1; - } else { // what else? - error("Error while flattening the Type1 charstring: " + aCharstring); } } return aCharstring; From 89c9bc39de7577c4a55430c609435c424b02d67d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 06:53:18 +0200 Subject: [PATCH 044/439] Add a direct translation to one of the way to format charstring number in flattenCharstring (28, x, y) --- PDFFont.js | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 00637f2cf..24c4a8c3e 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -1173,24 +1173,13 @@ CFF.prototype = { return data; }, - encodeNumber: function(aValue, aIsCharstring) { + encodeNumber: function(aValue) { var x = 0; - if (aIsCharstring && aValue >= -107 && aValue <= 107) { - return [aValue + 139]; - } else if (aValue >= -32768 && aValue <= 32767) { - return [ - 28, - FontsUtils.integerToBytes(aValue >> 8, 1), - FontsUtils.integerToBytes(aValue, 1) - ]; + if (aValue >= -32768 && aValue <= 32767) { + return [ 28, aValue >> 8, aValue ]; } else if (aValue >= (-2147483647-1) && aValue <= 2147483647) { return [ - 0xFF, - FontsUtils.integerToBytes(aValue >> 24, 1), - FontsUtils.integerToBytes(aValue >> 16, 1), - FontsUtils.integerToBytes(aValue >> 8, 1), - FontsUtils.integerToBytes(aValue, 1) - ]; + 0xFF, aValue >> 24, Value >> 16, aValue >> 8, aValue ]; } else { error("Value: " + aValue + " is not allowed"); } @@ -1227,7 +1216,7 @@ CFF.prototype = { /* * Flatten the commands by interpreting the postscript code and replacing * every 'callsubr', 'callothersubr' by the real commands. - * + * * TODO This function also do a string to command number transformation * that can probably be avoided if the Type1 decodeCharstring code is smarter */ @@ -1310,11 +1299,8 @@ CFF.prototype = { for (var j = 0; j < aCharstring.length; j++) { var command = aCharstring[j]; if (parseFloat(command) == command) { - var number = this.encodeNumber(command, true); - aCharstring.splice(j, 1); - for (var k = 0; k < number.length; k++) - aCharstring.splice(j + k, 0, number[k]); - j+= number.length - 1; + aCharstring.splice(j, 1, 28, command >> 8, command); + j+= 2; } else if (command.charAt) { var command = this.commandsMap[command]; if (IsArray(command)) { From d31bc90c855489a86c2de2f51a78981efdddb763 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 07:14:11 +0200 Subject: [PATCH 045/439] Use a typed array in the CMAP construction function --- PDFFont.js | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 24c4a8c3e..95d80bfc8 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -274,15 +274,15 @@ Font.prototype = { }, _createCMAPTable: function font_createCMAPTable(aGlyphs) { - var characters = new Array(kMaxGlyphsCount); - for (var i = 0; i < aGlyphs.length; i++) { + var characters = new Uint16Array(kMaxGlyphsCount); + for (var i = 0; i < aGlyphs.length; i++) characters[aGlyphs[i].unicode] = i + 1; - } // Separate the glyphs into continuous range of codes, aka segment. var ranges = []; var range = []; - for (var i = 0; i < characters.length; i++) { + var count = characters.length; + for (var i = 0; i < count; i++) { if (characters[i]) { range.push(i); } else if (range.length) { @@ -548,22 +548,18 @@ Font.prototype = { var FontsUtils = { _bytesArray: new Uint8Array(4), integerToBytes: function fu_integerToBytes(aValue, aBytesCount) { - // If we want only one byte, take a fast path + var bytes = this._bytesArray; + if (aBytesCount == 1) { - this._bytesArray.set([aValue]); - return this._bytesArray[0]; + bytes.set([aValue]); + return bytes[0]; + } else if (aBytesCount == 2) { + bytes.set([aValue >> 8, aValue]); + return [bytes[0], bytes[1]]; + } else if (aBytesCount == 4) { + bytes.set([aValue >> 24, aValue >> 16, aValue >> 8, aValue]); + return [bytes[0], bytes[1], bytes[2], bytes[3]]; } - - var bytes = []; - for (var i = 0; i < aBytesCount; i++) - bytes[i] = 0x00; - - do { - bytes[--aBytesCount] = (aValue & 0xFF); - aValue = aValue >> 8; - } while (aBytesCount && aValue > 0); - - return bytes; }, bytesToInteger: function fu_bytesToInteger(aBytesArray) { @@ -875,7 +871,7 @@ var Type1Parser = function() { var value = ""; var count = aStream.length; for (var i = 0; i < count; i++) { - value = aStream.getByte(); + value = aStream[i]; if (aByteArray) decryptedString[i] = value ^ (r >> 8); else @@ -1054,7 +1050,7 @@ var Type1Parser = function() { * extracted from and eexec encrypted block of data */ this.extractFontInfo = function(aStream) { - var eexecString = decrypt(new Stream(aStream), kEexecEncryptionKey, 4, true); + var eexecString = decrypt(aStream, kEexecEncryptionKey, 4, true); var subrs = [], glyphs = []; var inSubrs = inGlyphs = false; var glyph = ""; @@ -1070,16 +1066,16 @@ var Type1Parser = function() { if (inSubrs && c == 0x52) { length = parseInt(length); - var stream = new Stream(eexecString.slice(i + 3, i + 3 + length)); - var encodedSubr = decrypt(stream, kCharStringsEncryptionKey, 4).join(""); + var data = eexecString.slice(i + 3, i + 3 + length); + var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4).join(""); var subr = decodeCharString(new StringStream(encodedSubr)); subrs.push(subr); i += 3 + length; } else if (inGlyphs && c == 0x52) { length = parseInt(length); - var stream = new Stream(eexecString.slice(i + 3, i + 3 + length)); - var encodedCharstring = decrypt(stream, kCharStringsEncryptionKey, 4).join(""); + var data = eexecString.slice(i + 3, i + 3 + length); + var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4).join(""); var subr = decodeCharString(new StringStream(encodedCharstring)); glyphs.push({ From 35ceea1ff20b9f1b65b1dd2ef872401e7adeeb45 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 07:48:45 +0200 Subject: [PATCH 046/439] Do not use stream when it is not necessary --- PDFFont.js | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 95d80bfc8..5fa463250 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -990,32 +990,30 @@ var Type1Parser = function() { "31": "hvcurveto" }; - function decodeCharString(aStream) { - var start = Date.now(); + function decodeCharString(aArray) { var charString = []; var value = ""; - var count = aStream.length; + var count = aArray.length; for (var i = 0; i < count; i++) { - value = aStream.getByte(); + value = parseInt(aArray[i]); if (value < 32) { var command = null; if (value == 12) { - var escape = aStream.getByte(); + var escape = aArray[++i]; command = charStringDictionary["12"][escape]; - i++; } else { command = charStringDictionary[value]; } // Some charstring commands are meaningless in Type2 and will return // a null, let's just ignored them - if (!command && i < count) + if (!command && i < count) { continue; - else if (!command) + } else if (!command) { break; - else if (command == -1) { + } else if (command == -1) { log("decodeCharstring: " + charString); error("Support for Type1 command " + value + " (" + escape + ") is not implemented"); } @@ -1024,24 +1022,19 @@ var Type1Parser = function() { } else if (value <= 246) { value = parseInt(value) - 139; } else if (value <= 250) { - value = ((value - 247) * 256) + parseInt(aStream.getByte()) + 108; - i++; + value = ((value - 247) * 256) + parseInt(aArray[++i]) + 108; } else if (value <= 254) { - value = -((value - 251) * 256) - parseInt(aStream.getByte()) - 108; - i++; + value = -((value - 251) * 256) - parseInt(aArray[++i]) - 108; } else { - var byte = aStream.getByte(); + var byte = aArray[++i]; var high = (byte >> 1); - value = (byte - high) << 24 | aStream.getByte() << 16 | - aStream.getByte() << 8 | aStream.getByte(); - i += 4; + value = (byte - high) << 24 | aArray[++i] << 16 | + aArray[++i] << 8 | aArray[++i]; } charString.push(value); } - var end = Date.now(); - dump("Time to decode charString of length " + count + " is " + (end - start)); return charString; }; @@ -1067,16 +1060,16 @@ var Type1Parser = function() { if (inSubrs && c == 0x52) { length = parseInt(length); var data = eexecString.slice(i + 3, i + 3 + length); - var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4).join(""); - var subr = decodeCharString(new StringStream(encodedSubr)); + var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4, true); + var subr = decodeCharString(encodedSubr); subrs.push(subr); i += 3 + length; } else if (inGlyphs && c == 0x52) { length = parseInt(length); var data = eexecString.slice(i + 3, i + 3 + length); - var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4).join(""); - var subr = decodeCharString(new StringStream(encodedCharstring)); + var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4, true); + var subr = decodeCharString(encodedCharstring); glyphs.push({ glyph: glyph, @@ -1125,12 +1118,11 @@ var CFF = function(aFontName, aFontBBox, aFontFile) { fontInfo.name = aFontName; fontInfo.bbox = aFontBBox; - // XXX + // XXX This hold the glyph data as if, this should be improved this.glyphs = fontInfo.charstrings; this.data = this.convertToCFF(fontInfo); var end = Date.now(); - //log("Time to parse font is:" + (end - start)); }; CFF.prototype = { @@ -1232,13 +1224,22 @@ CFF.prototype = { }, flattenCharstring: function(aCharstring, aSubrs) { + var original = aCharstring.slice(); var i = 0; while (true) { var obj = aCharstring[i]; if (obj.charAt) { switch (obj) { case "callsubr": - var subr = aSubrs[aCharstring[i- 1]].slice(); + if (aCharstring[i - 1] == 351) { + log(original); + log(aCharstring); + error("..."); + aCharstring.splice(i - 1, 2); + continue; + } + + var subr = aSubrs[aCharstring[i - 1]].slice(); if (subr.length > 1) { subr = this.flattenCharstring(subr, aSubrs); subr.pop(); From b5915ab3cd823533d6a0eb478c0d360e9b7baa76 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 08:36:52 +0200 Subject: [PATCH 047/439] Fix CIMM6/CIIM9 --- PDFFont.js | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/PDFFont.js b/PDFFont.js index 5fa463250..2db7e745f 100644 --- a/PDFFont.js +++ b/PDFFont.js @@ -1223,31 +1223,25 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function(aCharstring, aSubrs) { + flattenCharstring: function(aGlyph, aCharstring, aSubrs) { var original = aCharstring.slice(); var i = 0; while (true) { var obj = aCharstring[i]; + if (obj == null) + return []; + if (obj.charAt) { switch (obj) { case "callsubr": - if (aCharstring[i - 1] == 351) { - log(original); - log(aCharstring); - error("..."); - aCharstring.splice(i - 1, 2); - continue; - } - var subr = aSubrs[aCharstring[i - 1]].slice(); if (subr.length > 1) { - subr = this.flattenCharstring(subr, aSubrs); + subr = this.flattenCharstring(aGlyph, subr, aSubrs); subr.pop(); aCharstring.splice(i - 1, 2, subr); - } - else + } else { aCharstring.splice(i - 1, 2); - + } i -= 1; break; @@ -1262,8 +1256,8 @@ CFF.prototype = { error("callothersubr for index: " + index + " (" + aCharstring + ")"); if (!data) { - aCharstring.splice(i - 2, 3, "pop", 3); - i -= 2; + aCharstring.splice(i - 2, 4, "pop", 3); + i -= 3; } else { // 5 to remove the arguments, the callothersubr call and the pop command aCharstring.splice(i - 3, 5, 3); @@ -1279,7 +1273,10 @@ CFF.prototype = { break; case "pop": - aCharstring.splice(i - 2, 2); + if (i) + aCharstring.splice(i - 2, 2); + else + aCharstring.splice(i - 1, 1); i -= 1; break; @@ -1287,7 +1284,11 @@ CFF.prototype = { case "hsbw": var charWidthVector = aCharstring[i - 1]; var leftSidebearing = aCharstring[i - 2]; - aCharstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto"); + + if (leftSidebearing) + aCharstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto"); + else + aCharstring.splice(i - 2, 3, charWidthVector); break; case "endchar": @@ -1345,7 +1346,7 @@ CFF.prototype = { var charstring = charstrings[i].charstring.slice(); var glyph = charstrings[i].glyph; - var flattened = this.flattenCharstring(charstring, aFontInfo.subrs); + var flattened = this.flattenCharstring(glyph, charstring, aFontInfo.subrs); glyphs.push(flattened); charstringsCount++; charstringsDataLength += flattened.length; From 4db56c5c97563adb9da6917f9eaf9230b69b2f3c Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 00:37:15 +0800 Subject: [PATCH 048/439] add blogs and twitter link --- README | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README b/README index 18817c340..ee537f0a5 100644 --- a/README +++ b/README @@ -1,3 +1,12 @@ pdf.js is a technology demonstrator prototype to explore whether the HTML5 platform is complete enough to faithfully and efficiently render the ISO 32000-1:2008 Portable Document Format (PDF) without native code assistance. + +You can read more about pdf.js here: + +http://andreasgal.com/2011/06/15/pdf-js/ +http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/ + +Or follow us on twitter: @pdfjs + +http://twitter.com/#!/pdfjs From 446e958b5de4ed25d37eb2c7db5cc37afbac25dd Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 09:11:03 +0200 Subject: [PATCH 049/439] Rename PDFFonts.js to fonts.js --- PDFFont.js => fonts.js | 0 PDFFontUtils.js => fonts_utils.js | 0 test.html | 7 +++---- 3 files changed, 3 insertions(+), 4 deletions(-) rename PDFFont.js => fonts.js (100%) rename PDFFontUtils.js => fonts_utils.js (100%) diff --git a/PDFFont.js b/fonts.js similarity index 100% rename from PDFFont.js rename to fonts.js diff --git a/PDFFontUtils.js b/fonts_utils.js similarity index 100% rename from PDFFontUtils.js rename to fonts_utils.js diff --git a/test.html b/test.html index 276ba30da..023cdeec2 100644 --- a/test.html +++ b/test.html @@ -1,15 +1,14 @@ -<<<<<<< HEAD Simple pdf.js page viewer - + + - - + From 5625a667ff3b35ae854a4cf1e2ae17fd06ea91f6 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 00:34:03 -0700 Subject: [PATCH 050/439] store unicode value as integer instead of hex string in glyphlist --- fonts.js | 2 +- glyphlist.js | 8406 +++++++++++++++++++++++++------------------------- 2 files changed, 4204 insertions(+), 4204 deletions(-) diff --git a/fonts.js b/fonts.js index 2db7e745f..e64001155 100644 --- a/fonts.js +++ b/fonts.js @@ -40,7 +40,7 @@ var Fonts = { unicodeFromCode: function fonts_unicodeFromCode(aCode) { var unicode = GlyphsUnicode[this.active.encoding[aCode]]; - return unicode ? "0x" + unicode : aCode; + return unicode ? unicode : aCode; } }; diff --git a/glyphlist.js b/glyphlist.js index e147f6c8a..f5a11b522 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1,1510 +1,1510 @@ var GlyphsUnicode = { - A: "0041", - AE: "00C6", - AEacute: "01FC", - AEmacron: "01E2", - AEsmall: "F7E6", - Aacute: "00C1", - Aacutesmall: "F7E1", - Abreve: "0102", - Abreveacute: "1EAE", - Abrevecyrillic: "04D0", - Abrevedotbelow: "1EB6", - Abrevegrave: "1EB0", - Abrevehookabove: "1EB2", - Abrevetilde: "1EB4", - Acaron: "01CD", - Acircle: "24B6", - Acircumflex: "00C2", - Acircumflexacute: "1EA4", - Acircumflexdotbelow: "1EAC", - Acircumflexgrave: "1EA6", - Acircumflexhookabove: "1EA8", - Acircumflexsmall: "F7E2", - Acircumflextilde: "1EAA", - Acute: "F6C9", - Acutesmall: "F7B4", - Acyrillic: "0410", - Adblgrave: "0200", - Adieresis: "00C4", - Adieresiscyrillic: "04D2", - Adieresismacron: "01DE", - Adieresissmall: "F7E4", - Adotbelow: "1EA0", - Adotmacron: "01E0", - Agrave: "00C0", - Agravesmall: "F7E0", - Ahookabove: "1EA2", - Aiecyrillic: "04D4", - Ainvertedbreve: "0202", - Alpha: "0391", - Alphatonos: "0386", - Amacron: "0100", - Amonospace: "FF21", - Aogonek: "0104", - Aring: "00C5", - Aringacute: "01FA", - Aringbelow: "1E00", - Aringsmall: "F7E5", - Asmall: "F761", - Atilde: "00C3", - Atildesmall: "F7E3", - Aybarmenian: "0531", - B: "0042", - Bcircle: "24B7", - Bdotaccent: "1E02", - Bdotbelow: "1E04", - Becyrillic: "0411", - Benarmenian: "0532", - Beta: "0392", - Bhook: "0181", - Blinebelow: "1E06", - Bmonospace: "FF22", - Brevesmall: "F6F4", - Bsmall: "F762", - Btopbar: "0182", - C: "0043", - Caarmenian: "053E", - Cacute: "0106", - Caron: "F6CA", - Caronsmall: "F6F5", - Ccaron: "010C", - Ccedilla: "00C7", - Ccedillaacute: "1E08", - Ccedillasmall: "F7E7", - Ccircle: "24B8", - Ccircumflex: "0108", - Cdot: "010A", - Cdotaccent: "010A", - Cedillasmall: "F7B8", - Chaarmenian: "0549", - Cheabkhasiancyrillic: "04BC", - Checyrillic: "0427", - Chedescenderabkhasiancyrillic: "04BE", - Chedescendercyrillic: "04B6", - Chedieresiscyrillic: "04F4", - Cheharmenian: "0543", - Chekhakassiancyrillic: "04CB", - Cheverticalstrokecyrillic: "04B8", - Chi: "03A7", - Chook: "0187", - Circumflexsmall: "F6F6", - Cmonospace: "FF23", - Coarmenian: "0551", - Csmall: "F763", - D: "0044", - DZ: "01F1", - DZcaron: "01C4", - Daarmenian: "0534", - Dafrican: "0189", - Dcaron: "010E", - Dcedilla: "1E10", - Dcircle: "24B9", - Dcircumflexbelow: "1E12", - Dcroat: "0110", - Ddotaccent: "1E0A", - Ddotbelow: "1E0C", - Decyrillic: "0414", - Deicoptic: "03EE", - Delta: "2206", - Deltagreek: "0394", - Dhook: "018A", - Dieresis: "F6CB", - DieresisAcute: "F6CC", - DieresisGrave: "F6CD", - Dieresissmall: "F7A8", - Digammagreek: "03DC", - Djecyrillic: "0402", - Dlinebelow: "1E0E", - Dmonospace: "FF24", - Dotaccentsmall: "F6F7", - Dslash: "0110", - Dsmall: "F764", - Dtopbar: "018B", - Dz: "01F2", - Dzcaron: "01C5", - Dzeabkhasiancyrillic: "04E0", - Dzecyrillic: "0405", - Dzhecyrillic: "040F", - E: "0045", - Eacute: "00C9", - Eacutesmall: "F7E9", - Ebreve: "0114", - Ecaron: "011A", - Ecedillabreve: "1E1C", - Echarmenian: "0535", - Ecircle: "24BA", - Ecircumflex: "00CA", - Ecircumflexacute: "1EBE", - Ecircumflexbelow: "1E18", - Ecircumflexdotbelow: "1EC6", - Ecircumflexgrave: "1EC0", - Ecircumflexhookabove: "1EC2", - Ecircumflexsmall: "F7EA", - Ecircumflextilde: "1EC4", - Ecyrillic: "0404", - Edblgrave: "0204", - Edieresis: "00CB", - Edieresissmall: "F7EB", - Edot: "0116", - Edotaccent: "0116", - Edotbelow: "1EB8", - Efcyrillic: "0424", - Egrave: "00C8", - Egravesmall: "F7E8", - Eharmenian: "0537", - Ehookabove: "1EBA", - Eightroman: "2167", - Einvertedbreve: "0206", - Eiotifiedcyrillic: "0464", - Elcyrillic: "041B", - Elevenroman: "216A", - Emacron: "0112", - Emacronacute: "1E16", - Emacrongrave: "1E14", - Emcyrillic: "041C", - Emonospace: "FF25", - Encyrillic: "041D", - Endescendercyrillic: "04A2", - Eng: "014A", - Enghecyrillic: "04A4", - Enhookcyrillic: "04C7", - Eogonek: "0118", - Eopen: "0190", - Epsilon: "0395", - Epsilontonos: "0388", - Ercyrillic: "0420", - Ereversed: "018E", - Ereversedcyrillic: "042D", - Escyrillic: "0421", - Esdescendercyrillic: "04AA", - Esh: "01A9", - Esmall: "F765", - Eta: "0397", - Etarmenian: "0538", - Etatonos: "0389", - Eth: "00D0", - Ethsmall: "F7F0", - Etilde: "1EBC", - Etildebelow: "1E1A", - Euro: "20AC", - Ezh: "01B7", - Ezhcaron: "01EE", - Ezhreversed: "01B8", - F: "0046", - Fcircle: "24BB", - Fdotaccent: "1E1E", - Feharmenian: "0556", - Feicoptic: "03E4", - Fhook: "0191", - Fitacyrillic: "0472", - Fiveroman: "2164", - Fmonospace: "FF26", - Fourroman: "2163", - Fsmall: "F766", - G: "0047", - GBsquare: "3387", - Gacute: "01F4", - Gamma: "0393", - Gammaafrican: "0194", - Gangiacoptic: "03EA", - Gbreve: "011E", - Gcaron: "01E6", - Gcedilla: "0122", - Gcircle: "24BC", - Gcircumflex: "011C", - Gcommaaccent: "0122", - Gdot: "0120", - Gdotaccent: "0120", - Gecyrillic: "0413", - Ghadarmenian: "0542", - Ghemiddlehookcyrillic: "0494", - Ghestrokecyrillic: "0492", - Gheupturncyrillic: "0490", - Ghook: "0193", - Gimarmenian: "0533", - Gjecyrillic: "0403", - Gmacron: "1E20", - Gmonospace: "FF27", - Grave: "F6CE", - Gravesmall: "F760", - Gsmall: "F767", - Gsmallhook: "029B", - Gstroke: "01E4", - H: "0048", - H18533: "25CF", - H18543: "25AA", - H18551: "25AB", - H22073: "25A1", - HPsquare: "33CB", - Haabkhasiancyrillic: "04A8", - Hadescendercyrillic: "04B2", - Hardsigncyrillic: "042A", - Hbar: "0126", - Hbrevebelow: "1E2A", - Hcedilla: "1E28", - Hcircle: "24BD", - Hcircumflex: "0124", - Hdieresis: "1E26", - Hdotaccent: "1E22", - Hdotbelow: "1E24", - Hmonospace: "FF28", - Hoarmenian: "0540", - Horicoptic: "03E8", - Hsmall: "F768", - Hungarumlaut: "F6CF", - Hungarumlautsmall: "F6F8", - Hzsquare: "3390", - I: "0049", - IAcyrillic: "042F", - IJ: "0132", - IUcyrillic: "042E", - Iacute: "00CD", - Iacutesmall: "F7ED", - Ibreve: "012C", - Icaron: "01CF", - Icircle: "24BE", - Icircumflex: "00CE", - Icircumflexsmall: "F7EE", - Icyrillic: "0406", - Idblgrave: "0208", - Idieresis: "00CF", - Idieresisacute: "1E2E", - Idieresiscyrillic: "04E4", - Idieresissmall: "F7EF", - Idot: "0130", - Idotaccent: "0130", - Idotbelow: "1ECA", - Iebrevecyrillic: "04D6", - Iecyrillic: "0415", - Ifraktur: "2111", - Igrave: "00CC", - Igravesmall: "F7EC", - Ihookabove: "1EC8", - Iicyrillic: "0418", - Iinvertedbreve: "020A", - Iishortcyrillic: "0419", - Imacron: "012A", - Imacroncyrillic: "04E2", - Imonospace: "FF29", - Iniarmenian: "053B", - Iocyrillic: "0401", - Iogonek: "012E", - Iota: "0399", - Iotaafrican: "0196", - Iotadieresis: "03AA", - Iotatonos: "038A", - Ismall: "F769", - Istroke: "0197", - Itilde: "0128", - Itildebelow: "1E2C", - Izhitsacyrillic: "0474", - Izhitsadblgravecyrillic: "0476", - J: "004A", - Jaarmenian: "0541", - Jcircle: "24BF", - Jcircumflex: "0134", - Jecyrillic: "0408", - Jheharmenian: "054B", - Jmonospace: "FF2A", - Jsmall: "F76A", - K: "004B", - KBsquare: "3385", - KKsquare: "33CD", - Kabashkircyrillic: "04A0", - Kacute: "1E30", - Kacyrillic: "041A", - Kadescendercyrillic: "049A", - Kahookcyrillic: "04C3", - Kappa: "039A", - Kastrokecyrillic: "049E", - Kaverticalstrokecyrillic: "049C", - Kcaron: "01E8", - Kcedilla: "0136", - Kcircle: "24C0", - Kcommaaccent: "0136", - Kdotbelow: "1E32", - Keharmenian: "0554", - Kenarmenian: "053F", - Khacyrillic: "0425", - Kheicoptic: "03E6", - Khook: "0198", - Kjecyrillic: "040C", - Klinebelow: "1E34", - Kmonospace: "FF2B", - Koppacyrillic: "0480", - Koppagreek: "03DE", - Ksicyrillic: "046E", - Ksmall: "F76B", - L: "004C", - LJ: "01C7", - LL: "F6BF", - Lacute: "0139", - Lambda: "039B", - Lcaron: "013D", - Lcedilla: "013B", - Lcircle: "24C1", - Lcircumflexbelow: "1E3C", - Lcommaaccent: "013B", - Ldot: "013F", - Ldotaccent: "013F", - Ldotbelow: "1E36", - Ldotbelowmacron: "1E38", - Liwnarmenian: "053C", - Lj: "01C8", - Ljecyrillic: "0409", - Llinebelow: "1E3A", - Lmonospace: "FF2C", - Lslash: "0141", - Lslashsmall: "F6F9", - Lsmall: "F76C", - M: "004D", - MBsquare: "3386", - Macron: "F6D0", - Macronsmall: "F7AF", - Macute: "1E3E", - Mcircle: "24C2", - Mdotaccent: "1E40", - Mdotbelow: "1E42", - Menarmenian: "0544", - Mmonospace: "FF2D", - Msmall: "F76D", - Mturned: "019C", - Mu: "039C", - N: "004E", - NJ: "01CA", - Nacute: "0143", - Ncaron: "0147", - Ncedilla: "0145", - Ncircle: "24C3", - Ncircumflexbelow: "1E4A", - Ncommaaccent: "0145", - Ndotaccent: "1E44", - Ndotbelow: "1E46", - Nhookleft: "019D", - Nineroman: "2168", - Nj: "01CB", - Njecyrillic: "040A", - Nlinebelow: "1E48", - Nmonospace: "FF2E", - Nowarmenian: "0546", - Nsmall: "F76E", - Ntilde: "00D1", - Ntildesmall: "F7F1", - Nu: "039D", - O: "004F", - OE: "0152", - OEsmall: "F6FA", - Oacute: "00D3", - Oacutesmall: "F7F3", - Obarredcyrillic: "04E8", - Obarreddieresiscyrillic: "04EA", - Obreve: "014E", - Ocaron: "01D1", - Ocenteredtilde: "019F", - Ocircle: "24C4", - Ocircumflex: "00D4", - Ocircumflexacute: "1ED0", - Ocircumflexdotbelow: "1ED8", - Ocircumflexgrave: "1ED2", - Ocircumflexhookabove: "1ED4", - Ocircumflexsmall: "F7F4", - Ocircumflextilde: "1ED6", - Ocyrillic: "041E", - Odblacute: "0150", - Odblgrave: "020C", - Odieresis: "00D6", - Odieresiscyrillic: "04E6", - Odieresissmall: "F7F6", - Odotbelow: "1ECC", - Ogoneksmall: "F6FB", - Ograve: "00D2", - Ogravesmall: "F7F2", - Oharmenian: "0555", - Ohm: "2126", - Ohookabove: "1ECE", - Ohorn: "01A0", - Ohornacute: "1EDA", - Ohorndotbelow: "1EE2", - Ohorngrave: "1EDC", - Ohornhookabove: "1EDE", - Ohorntilde: "1EE0", - Ohungarumlaut: "0150", - Oi: "01A2", - Oinvertedbreve: "020E", - Omacron: "014C", - Omacronacute: "1E52", - Omacrongrave: "1E50", - Omega: "2126", - Omegacyrillic: "0460", - Omegagreek: "03A9", - Omegaroundcyrillic: "047A", - Omegatitlocyrillic: "047C", - Omegatonos: "038F", - Omicron: "039F", - Omicrontonos: "038C", - Omonospace: "FF2F", - Oneroman: "2160", - Oogonek: "01EA", - Oogonekmacron: "01EC", - Oopen: "0186", - Oslash: "00D8", - Oslashacute: "01FE", - Oslashsmall: "F7F8", - Osmall: "F76F", - Ostrokeacute: "01FE", - Otcyrillic: "047E", - Otilde: "00D5", - Otildeacute: "1E4C", - Otildedieresis: "1E4E", - Otildesmall: "F7F5", - P: "0050", - Pacute: "1E54", - Pcircle: "24C5", - Pdotaccent: "1E56", - Pecyrillic: "041F", - Peharmenian: "054A", - Pemiddlehookcyrillic: "04A6", - Phi: "03A6", - Phook: "01A4", - Pi: "03A0", - Piwrarmenian: "0553", - Pmonospace: "FF30", - Psi: "03A8", - Psicyrillic: "0470", - Psmall: "F770", - Q: "0051", - Qcircle: "24C6", - Qmonospace: "FF31", - Qsmall: "F771", - R: "0052", - Raarmenian: "054C", - Racute: "0154", - Rcaron: "0158", - Rcedilla: "0156", - Rcircle: "24C7", - Rcommaaccent: "0156", - Rdblgrave: "0210", - Rdotaccent: "1E58", - Rdotbelow: "1E5A", - Rdotbelowmacron: "1E5C", - Reharmenian: "0550", - Rfraktur: "211C", - Rho: "03A1", - Ringsmall: "F6FC", - Rinvertedbreve: "0212", - Rlinebelow: "1E5E", - Rmonospace: "FF32", - Rsmall: "F772", - Rsmallinverted: "0281", - Rsmallinvertedsuperior: "02B6", - S: "0053", - SF010000: "250C", - SF020000: "2514", - SF030000: "2510", - SF040000: "2518", - SF050000: "253C", - SF060000: "252C", - SF070000: "2534", - SF080000: "251C", - SF090000: "2524", - SF100000: "2500", - SF110000: "2502", - SF190000: "2561", - SF200000: "2562", - SF210000: "2556", - SF220000: "2555", - SF230000: "2563", - SF240000: "2551", - SF250000: "2557", - SF260000: "255D", - SF270000: "255C", - SF280000: "255B", - SF360000: "255E", - SF370000: "255F", - SF380000: "255A", - SF390000: "2554", - SF400000: "2569", - SF410000: "2566", - SF420000: "2560", - SF430000: "2550", - SF440000: "256C", - SF450000: "2567", - SF460000: "2568", - SF470000: "2564", - SF480000: "2565", - SF490000: "2559", - SF500000: "2558", - SF510000: "2552", - SF520000: "2553", - SF530000: "256B", - SF540000: "256A", - Sacute: "015A", - Sacutedotaccent: "1E64", - Sampigreek: "03E0", - Scaron: "0160", - Scarondotaccent: "1E66", - Scaronsmall: "F6FD", - Scedilla: "015E", - Schwa: "018F", - Schwacyrillic: "04D8", - Schwadieresiscyrillic: "04DA", - Scircle: "24C8", - Scircumflex: "015C", - Scommaaccent: "0218", - Sdotaccent: "1E60", - Sdotbelow: "1E62", - Sdotbelowdotaccent: "1E68", - Seharmenian: "054D", - Sevenroman: "2166", - Shaarmenian: "0547", - Shacyrillic: "0428", - Shchacyrillic: "0429", - Sheicoptic: "03E2", - Shhacyrillic: "04BA", - Shimacoptic: "03EC", - Sigma: "03A3", - Sixroman: "2165", - Smonospace: "FF33", - Softsigncyrillic: "042C", - Ssmall: "F773", - Stigmagreek: "03DA", - T: "0054", - Tau: "03A4", - Tbar: "0166", - Tcaron: "0164", - Tcedilla: "0162", - Tcircle: "24C9", - Tcircumflexbelow: "1E70", - Tcommaaccent: "0162", - Tdotaccent: "1E6A", - Tdotbelow: "1E6C", - Tecyrillic: "0422", - Tedescendercyrillic: "04AC", - Tenroman: "2169", - Tetsecyrillic: "04B4", - Theta: "0398", - Thook: "01AC", - Thorn: "00DE", - Thornsmall: "F7FE", - Threeroman: "2162", - Tildesmall: "F6FE", - Tiwnarmenian: "054F", - Tlinebelow: "1E6E", - Tmonospace: "FF34", - Toarmenian: "0539", - Tonefive: "01BC", - Tonesix: "0184", - Tonetwo: "01A7", - Tretroflexhook: "01AE", - Tsecyrillic: "0426", - Tshecyrillic: "040B", - Tsmall: "F774", - Twelveroman: "216B", - Tworoman: "2161", - U: "0055", - Uacute: "00DA", - Uacutesmall: "F7FA", - Ubreve: "016C", - Ucaron: "01D3", - Ucircle: "24CA", - Ucircumflex: "00DB", - Ucircumflexbelow: "1E76", - Ucircumflexsmall: "F7FB", - Ucyrillic: "0423", - Udblacute: "0170", - Udblgrave: "0214", - Udieresis: "00DC", - Udieresisacute: "01D7", - Udieresisbelow: "1E72", - Udieresiscaron: "01D9", - Udieresiscyrillic: "04F0", - Udieresisgrave: "01DB", - Udieresismacron: "01D5", - Udieresissmall: "F7FC", - Udotbelow: "1EE4", - Ugrave: "00D9", - Ugravesmall: "F7F9", - Uhookabove: "1EE6", - Uhorn: "01AF", - Uhornacute: "1EE8", - Uhorndotbelow: "1EF0", - Uhorngrave: "1EEA", - Uhornhookabove: "1EEC", - Uhorntilde: "1EEE", - Uhungarumlaut: "0170", - Uhungarumlautcyrillic: "04F2", - Uinvertedbreve: "0216", - Ukcyrillic: "0478", - Umacron: "016A", - Umacroncyrillic: "04EE", - Umacrondieresis: "1E7A", - Umonospace: "FF35", - Uogonek: "0172", - Upsilon: "03A5", - Upsilon1: "03D2", - Upsilonacutehooksymbolgreek: "03D3", - Upsilonafrican: "01B1", - Upsilondieresis: "03AB", - Upsilondieresishooksymbolgreek: "03D4", - Upsilonhooksymbol: "03D2", - Upsilontonos: "038E", - Uring: "016E", - Ushortcyrillic: "040E", - Usmall: "F775", - Ustraightcyrillic: "04AE", - Ustraightstrokecyrillic: "04B0", - Utilde: "0168", - Utildeacute: "1E78", - Utildebelow: "1E74", - V: "0056", - Vcircle: "24CB", - Vdotbelow: "1E7E", - Vecyrillic: "0412", - Vewarmenian: "054E", - Vhook: "01B2", - Vmonospace: "FF36", - Voarmenian: "0548", - Vsmall: "F776", - Vtilde: "1E7C", - W: "0057", - Wacute: "1E82", - Wcircle: "24CC", - Wcircumflex: "0174", - Wdieresis: "1E84", - Wdotaccent: "1E86", - Wdotbelow: "1E88", - Wgrave: "1E80", - Wmonospace: "FF37", - Wsmall: "F777", - X: "0058", - Xcircle: "24CD", - Xdieresis: "1E8C", - Xdotaccent: "1E8A", - Xeharmenian: "053D", - Xi: "039E", - Xmonospace: "FF38", - Xsmall: "F778", - Y: "0059", - Yacute: "00DD", - Yacutesmall: "F7FD", - Yatcyrillic: "0462", - Ycircle: "24CE", - Ycircumflex: "0176", - Ydieresis: "0178", - Ydieresissmall: "F7FF", - Ydotaccent: "1E8E", - Ydotbelow: "1EF4", - Yericyrillic: "042B", - Yerudieresiscyrillic: "04F8", - Ygrave: "1EF2", - Yhook: "01B3", - Yhookabove: "1EF6", - Yiarmenian: "0545", - Yicyrillic: "0407", - Yiwnarmenian: "0552", - Ymonospace: "FF39", - Ysmall: "F779", - Ytilde: "1EF8", - Yusbigcyrillic: "046A", - Yusbigiotifiedcyrillic: "046C", - Yuslittlecyrillic: "0466", - Yuslittleiotifiedcyrillic: "0468", - Z: "005A", - Zaarmenian: "0536", - Zacute: "0179", - Zcaron: "017D", - Zcaronsmall: "F6FF", - Zcircle: "24CF", - Zcircumflex: "1E90", - Zdot: "017B", - Zdotaccent: "017B", - Zdotbelow: "1E92", - Zecyrillic: "0417", - Zedescendercyrillic: "0498", - Zedieresiscyrillic: "04DE", - Zeta: "0396", - Zhearmenian: "053A", - Zhebrevecyrillic: "04C1", - Zhecyrillic: "0416", - Zhedescendercyrillic: "0496", - Zhedieresiscyrillic: "04DC", - Zlinebelow: "1E94", - Zmonospace: "FF3A", - Zsmall: "F77A", - Zstroke: "01B5", - a: "0061", - aabengali: "0986", - aacute: "00E1", - aadeva: "0906", - aagujarati: "0A86", - aagurmukhi: "0A06", - aamatragurmukhi: "0A3E", - aarusquare: "3303", - aavowelsignbengali: "09BE", - aavowelsigndeva: "093E", - aavowelsigngujarati: "0ABE", - abbreviationmarkarmenian: "055F", - abbreviationsigndeva: "0970", - abengali: "0985", - abopomofo: "311A", - abreve: "0103", - abreveacute: "1EAF", - abrevecyrillic: "04D1", - abrevedotbelow: "1EB7", - abrevegrave: "1EB1", - abrevehookabove: "1EB3", - abrevetilde: "1EB5", - acaron: "01CE", - acircle: "24D0", - acircumflex: "00E2", - acircumflexacute: "1EA5", - acircumflexdotbelow: "1EAD", - acircumflexgrave: "1EA7", - acircumflexhookabove: "1EA9", - acircumflextilde: "1EAB", - acute: "00B4", - acutebelowcmb: "0317", - acutecmb: "0301", - acutecomb: "0301", - acutedeva: "0954", - acutelowmod: "02CF", - acutetonecmb: "0341", - acyrillic: "0430", - adblgrave: "0201", - addakgurmukhi: "0A71", - adeva: "0905", - adieresis: "00E4", - adieresiscyrillic: "04D3", - adieresismacron: "01DF", - adotbelow: "1EA1", - adotmacron: "01E1", - ae: "00E6", - aeacute: "01FD", - aekorean: "3150", - aemacron: "01E3", - afii00208: "2015", - afii08941: "20A4", - afii10017: "0410", - afii10018: "0411", - afii10019: "0412", - afii10020: "0413", - afii10021: "0414", - afii10022: "0415", - afii10023: "0401", - afii10024: "0416", - afii10025: "0417", - afii10026: "0418", - afii10027: "0419", - afii10028: "041A", - afii10029: "041B", - afii10030: "041C", - afii10031: "041D", - afii10032: "041E", - afii10033: "041F", - afii10034: "0420", - afii10035: "0421", - afii10036: "0422", - afii10037: "0423", - afii10038: "0424", - afii10039: "0425", - afii10040: "0426", - afii10041: "0427", - afii10042: "0428", - afii10043: "0429", - afii10044: "042A", - afii10045: "042B", - afii10046: "042C", - afii10047: "042D", - afii10048: "042E", - afii10049: "042F", - afii10050: "0490", - afii10051: "0402", - afii10052: "0403", - afii10053: "0404", - afii10054: "0405", - afii10055: "0406", - afii10056: "0407", - afii10057: "0408", - afii10058: "0409", - afii10059: "040A", - afii10060: "040B", - afii10061: "040C", - afii10062: "040E", - afii10063: "F6C4", - afii10064: "F6C5", - afii10065: "0430", - afii10066: "0431", - afii10067: "0432", - afii10068: "0433", - afii10069: "0434", - afii10070: "0435", - afii10071: "0451", - afii10072: "0436", - afii10073: "0437", - afii10074: "0438", - afii10075: "0439", - afii10076: "043A", - afii10077: "043B", - afii10078: "043C", - afii10079: "043D", - afii10080: "043E", - afii10081: "043F", - afii10082: "0440", - afii10083: "0441", - afii10084: "0442", - afii10085: "0443", - afii10086: "0444", - afii10087: "0445", - afii10088: "0446", - afii10089: "0447", - afii10090: "0448", - afii10091: "0449", - afii10092: "044A", - afii10093: "044B", - afii10094: "044C", - afii10095: "044D", - afii10096: "044E", - afii10097: "044F", - afii10098: "0491", - afii10099: "0452", - afii10100: "0453", - afii10101: "0454", - afii10102: "0455", - afii10103: "0456", - afii10104: "0457", - afii10105: "0458", - afii10106: "0459", - afii10107: "045A", - afii10108: "045B", - afii10109: "045C", - afii10110: "045E", - afii10145: "040F", - afii10146: "0462", - afii10147: "0472", - afii10148: "0474", - afii10192: "F6C6", - afii10193: "045F", - afii10194: "0463", - afii10195: "0473", - afii10196: "0475", - afii10831: "F6C7", - afii10832: "F6C8", - afii10846: "04D9", - afii299: "200E", - afii300: "200F", - afii301: "200D", - afii57381: "066A", - afii57388: "060C", - afii57392: "0660", - afii57393: "0661", - afii57394: "0662", - afii57395: "0663", - afii57396: "0664", - afii57397: "0665", - afii57398: "0666", - afii57399: "0667", - afii57400: "0668", - afii57401: "0669", - afii57403: "061B", - afii57407: "061F", - afii57409: "0621", - afii57410: "0622", - afii57411: "0623", - afii57412: "0624", - afii57413: "0625", - afii57414: "0626", - afii57415: "0627", - afii57416: "0628", - afii57417: "0629", - afii57418: "062A", - afii57419: "062B", - afii57420: "062C", - afii57421: "062D", - afii57422: "062E", - afii57423: "062F", - afii57424: "0630", - afii57425: "0631", - afii57426: "0632", - afii57427: "0633", - afii57428: "0634", - afii57429: "0635", - afii57430: "0636", - afii57431: "0637", - afii57432: "0638", - afii57433: "0639", - afii57434: "063A", - afii57440: "0640", - afii57441: "0641", - afii57442: "0642", - afii57443: "0643", - afii57444: "0644", - afii57445: "0645", - afii57446: "0646", - afii57448: "0648", - afii57449: "0649", - afii57450: "064A", - afii57451: "064B", - afii57452: "064C", - afii57453: "064D", - afii57454: "064E", - afii57455: "064F", - afii57456: "0650", - afii57457: "0651", - afii57458: "0652", - afii57470: "0647", - afii57505: "06A4", - afii57506: "067E", - afii57507: "0686", - afii57508: "0698", - afii57509: "06AF", - afii57511: "0679", - afii57512: "0688", - afii57513: "0691", - afii57514: "06BA", - afii57519: "06D2", - afii57534: "06D5", - afii57636: "20AA", - afii57645: "05BE", - afii57658: "05C3", - afii57664: "05D0", - afii57665: "05D1", - afii57666: "05D2", - afii57667: "05D3", - afii57668: "05D4", - afii57669: "05D5", - afii57670: "05D6", - afii57671: "05D7", - afii57672: "05D8", - afii57673: "05D9", - afii57674: "05DA", - afii57675: "05DB", - afii57676: "05DC", - afii57677: "05DD", - afii57678: "05DE", - afii57679: "05DF", - afii57680: "05E0", - afii57681: "05E1", - afii57682: "05E2", - afii57683: "05E3", - afii57684: "05E4", - afii57685: "05E5", - afii57686: "05E6", - afii57687: "05E7", - afii57688: "05E8", - afii57689: "05E9", - afii57690: "05EA", - afii57694: "FB2A", - afii57695: "FB2B", - afii57700: "FB4B", - afii57705: "FB1F", - afii57716: "05F0", - afii57717: "05F1", - afii57718: "05F2", - afii57723: "FB35", - afii57793: "05B4", - afii57794: "05B5", - afii57795: "05B6", - afii57796: "05BB", - afii57797: "05B8", - afii57798: "05B7", - afii57799: "05B0", - afii57800: "05B2", - afii57801: "05B1", - afii57802: "05B3", - afii57803: "05C2", - afii57804: "05C1", - afii57806: "05B9", - afii57807: "05BC", - afii57839: "05BD", - afii57841: "05BF", - afii57842: "05C0", - afii57929: "02BC", - afii61248: "2105", - afii61289: "2113", - afii61352: "2116", - afii61573: "202C", - afii61574: "202D", - afii61575: "202E", - afii61664: "200C", - afii63167: "066D", - afii64937: "02BD", - agrave: "00E0", - agujarati: "0A85", - agurmukhi: "0A05", - ahiragana: "3042", - ahookabove: "1EA3", - aibengali: "0990", - aibopomofo: "311E", - aideva: "0910", - aiecyrillic: "04D5", - aigujarati: "0A90", - aigurmukhi: "0A10", - aimatragurmukhi: "0A48", - ainarabic: "0639", - ainfinalarabic: "FECA", - aininitialarabic: "FECB", - ainmedialarabic: "FECC", - ainvertedbreve: "0203", - aivowelsignbengali: "09C8", - aivowelsigndeva: "0948", - aivowelsigngujarati: "0AC8", - akatakana: "30A2", - akatakanahalfwidth: "FF71", - akorean: "314F", - alef: "05D0", - alefarabic: "0627", - alefdageshhebrew: "FB30", - aleffinalarabic: "FE8E", - alefhamzaabovearabic: "0623", - alefhamzaabovefinalarabic: "FE84", - alefhamzabelowarabic: "0625", - alefhamzabelowfinalarabic: "FE88", - alefhebrew: "05D0", - aleflamedhebrew: "FB4F", - alefmaddaabovearabic: "0622", - alefmaddaabovefinalarabic: "FE82", - alefmaksuraarabic: "0649", - alefmaksurafinalarabic: "FEF0", - alefmaksurainitialarabic: "FEF3", - alefmaksuramedialarabic: "FEF4", - alefpatahhebrew: "FB2E", - alefqamatshebrew: "FB2F", - aleph: "2135", - allequal: "224C", - alpha: "03B1", - alphatonos: "03AC", - amacron: "0101", - amonospace: "FF41", - ampersand: "0026", - ampersandmonospace: "FF06", - ampersandsmall: "F726", - amsquare: "33C2", - anbopomofo: "3122", - angbopomofo: "3124", - angkhankhuthai: "0E5A", - angle: "2220", - anglebracketleft: "3008", - anglebracketleftvertical: "FE3F", - anglebracketright: "3009", - anglebracketrightvertical: "FE40", - angleleft: "2329", - angleright: "232A", - angstrom: "212B", - anoteleia: "0387", - anudattadeva: "0952", - anusvarabengali: "0982", - anusvaradeva: "0902", - anusvaragujarati: "0A82", - aogonek: "0105", - apaatosquare: "3300", - aparen: "249C", - apostrophearmenian: "055A", - apostrophemod: "02BC", - apple: "F8FF", - approaches: "2250", - approxequal: "2248", - approxequalorimage: "2252", - approximatelyequal: "2245", - araeaekorean: "318E", - araeakorean: "318D", - arc: "2312", - arighthalfring: "1E9A", - aring: "00E5", - aringacute: "01FB", - aringbelow: "1E01", - arrowboth: "2194", - arrowdashdown: "21E3", - arrowdashleft: "21E0", - arrowdashright: "21E2", - arrowdashup: "21E1", - arrowdblboth: "21D4", - arrowdbldown: "21D3", - arrowdblleft: "21D0", - arrowdblright: "21D2", - arrowdblup: "21D1", - arrowdown: "2193", - arrowdownleft: "2199", - arrowdownright: "2198", - arrowdownwhite: "21E9", - arrowheaddownmod: "02C5", - arrowheadleftmod: "02C2", - arrowheadrightmod: "02C3", - arrowheadupmod: "02C4", - arrowhorizex: "F8E7", - arrowleft: "2190", - arrowleftdbl: "21D0", - arrowleftdblstroke: "21CD", - arrowleftoverright: "21C6", - arrowleftwhite: "21E6", - arrowright: "2192", - arrowrightdblstroke: "21CF", - arrowrightheavy: "279E", - arrowrightoverleft: "21C4", - arrowrightwhite: "21E8", - arrowtableft: "21E4", - arrowtabright: "21E5", - arrowup: "2191", - arrowupdn: "2195", - arrowupdnbse: "21A8", - arrowupdownbase: "21A8", - arrowupleft: "2196", - arrowupleftofdown: "21C5", - arrowupright: "2197", - arrowupwhite: "21E7", - arrowvertex: "F8E6", - asciicircum: "005E", - asciicircummonospace: "FF3E", - asciitilde: "007E", - asciitildemonospace: "FF5E", - ascript: "0251", - ascriptturned: "0252", - asmallhiragana: "3041", - asmallkatakana: "30A1", - asmallkatakanahalfwidth: "FF67", - asterisk: "002A", - asteriskaltonearabic: "066D", - asteriskarabic: "066D", - asteriskmath: "2217", - asteriskmonospace: "FF0A", - asterisksmall: "FE61", - asterism: "2042", - asuperior: "F6E9", - asymptoticallyequal: "2243", - at: "0040", - atilde: "00E3", - atmonospace: "FF20", - atsmall: "FE6B", - aturned: "0250", - aubengali: "0994", - aubopomofo: "3120", - audeva: "0914", - augujarati: "0A94", - augurmukhi: "0A14", - aulengthmarkbengali: "09D7", - aumatragurmukhi: "0A4C", - auvowelsignbengali: "09CC", - auvowelsigndeva: "094C", - auvowelsigngujarati: "0ACC", - avagrahadeva: "093D", - aybarmenian: "0561", - ayin: "05E2", - ayinaltonehebrew: "FB20", - ayinhebrew: "05E2", - b: "0062", - babengali: "09AC", - backslash: "005C", - backslashmonospace: "FF3C", - badeva: "092C", - bagujarati: "0AAC", - bagurmukhi: "0A2C", - bahiragana: "3070", - bahtthai: "0E3F", - bakatakana: "30D0", - bar: "007C", - barmonospace: "FF5C", - bbopomofo: "3105", - bcircle: "24D1", - bdotaccent: "1E03", - bdotbelow: "1E05", - beamedsixteenthnotes: "266C", - because: "2235", - becyrillic: "0431", - beharabic: "0628", - behfinalarabic: "FE90", - behinitialarabic: "FE91", - behiragana: "3079", - behmedialarabic: "FE92", - behmeeminitialarabic: "FC9F", - behmeemisolatedarabic: "FC08", - behnoonfinalarabic: "FC6D", - bekatakana: "30D9", - benarmenian: "0562", - bet: "05D1", - beta: "03B2", - betasymbolgreek: "03D0", - betdagesh: "FB31", - betdageshhebrew: "FB31", - bethebrew: "05D1", - betrafehebrew: "FB4C", - bhabengali: "09AD", - bhadeva: "092D", - bhagujarati: "0AAD", - bhagurmukhi: "0A2D", - bhook: "0253", - bihiragana: "3073", - bikatakana: "30D3", - bilabialclick: "0298", - bindigurmukhi: "0A02", - birusquare: "3331", - blackcircle: "25CF", - blackdiamond: "25C6", - blackdownpointingtriangle: "25BC", - blackleftpointingpointer: "25C4", - blackleftpointingtriangle: "25C0", - blacklenticularbracketleft: "3010", - blacklenticularbracketleftvertical: "FE3B", - blacklenticularbracketright: "3011", - blacklenticularbracketrightvertical: "FE3C", - blacklowerlefttriangle: "25E3", - blacklowerrighttriangle: "25E2", - blackrectangle: "25AC", - blackrightpointingpointer: "25BA", - blackrightpointingtriangle: "25B6", - blacksmallsquare: "25AA", - blacksmilingface: "263B", - blacksquare: "25A0", - blackstar: "2605", - blackupperlefttriangle: "25E4", - blackupperrighttriangle: "25E5", - blackuppointingsmalltriangle: "25B4", - blackuppointingtriangle: "25B2", - blank: "2423", - blinebelow: "1E07", - block: "2588", - bmonospace: "FF42", - bobaimaithai: "0E1A", - bohiragana: "307C", - bokatakana: "30DC", - bparen: "249D", - bqsquare: "33C3", - braceex: "F8F4", - braceleft: "007B", - braceleftbt: "F8F3", - braceleftmid: "F8F2", - braceleftmonospace: "FF5B", - braceleftsmall: "FE5B", - bracelefttp: "F8F1", - braceleftvertical: "FE37", - braceright: "007D", - bracerightbt: "F8FE", - bracerightmid: "F8FD", - bracerightmonospace: "FF5D", - bracerightsmall: "FE5C", - bracerighttp: "F8FC", - bracerightvertical: "FE38", - bracketleft: "005B", - bracketleftbt: "F8F0", - bracketleftex: "F8EF", - bracketleftmonospace: "FF3B", - bracketlefttp: "F8EE", - bracketright: "005D", - bracketrightbt: "F8FB", - bracketrightex: "F8FA", - bracketrightmonospace: "FF3D", - bracketrighttp: "F8F9", - breve: "02D8", - brevebelowcmb: "032E", - brevecmb: "0306", - breveinvertedbelowcmb: "032F", - breveinvertedcmb: "0311", - breveinverteddoublecmb: "0361", - bridgebelowcmb: "032A", - bridgeinvertedbelowcmb: "033A", - brokenbar: "00A6", - bstroke: "0180", - bsuperior: "F6EA", - btopbar: "0183", - buhiragana: "3076", - bukatakana: "30D6", - bullet: "2022", - bulletinverse: "25D8", - bulletoperator: "2219", - bullseye: "25CE", - c: "0063", - caarmenian: "056E", - cabengali: "099A", - cacute: "0107", - cadeva: "091A", - cagujarati: "0A9A", - cagurmukhi: "0A1A", - calsquare: "3388", - candrabindubengali: "0981", - candrabinducmb: "0310", - candrabindudeva: "0901", - candrabindugujarati: "0A81", - capslock: "21EA", - careof: "2105", - caron: "02C7", - caronbelowcmb: "032C", - caroncmb: "030C", - carriagereturn: "21B5", - cbopomofo: "3118", - ccaron: "010D", - ccedilla: "00E7", - ccedillaacute: "1E09", - ccircle: "24D2", - ccircumflex: "0109", - ccurl: "0255", - cdot: "010B", - cdotaccent: "010B", - cdsquare: "33C5", - cedilla: "00B8", - cedillacmb: "0327", - cent: "00A2", - centigrade: "2103", - centinferior: "F6DF", - centmonospace: "FFE0", - centoldstyle: "F7A2", - centsuperior: "F6E0", - chaarmenian: "0579", - chabengali: "099B", - chadeva: "091B", - chagujarati: "0A9B", - chagurmukhi: "0A1B", - chbopomofo: "3114", - cheabkhasiancyrillic: "04BD", - checkmark: "2713", - checyrillic: "0447", - chedescenderabkhasiancyrillic: "04BF", - chedescendercyrillic: "04B7", - chedieresiscyrillic: "04F5", - cheharmenian: "0573", - chekhakassiancyrillic: "04CC", - cheverticalstrokecyrillic: "04B9", - chi: "03C7", - chieuchacirclekorean: "3277", - chieuchaparenkorean: "3217", - chieuchcirclekorean: "3269", - chieuchkorean: "314A", - chieuchparenkorean: "3209", - chochangthai: "0E0A", - chochanthai: "0E08", - chochingthai: "0E09", - chochoethai: "0E0C", - chook: "0188", - cieucacirclekorean: "3276", - cieucaparenkorean: "3216", - cieuccirclekorean: "3268", - cieuckorean: "3148", - cieucparenkorean: "3208", - cieucuparenkorean: "321C", - circle: "25CB", - circlemultiply: "2297", - circleot: "2299", - circleplus: "2295", - circlepostalmark: "3036", - circlewithlefthalfblack: "25D0", - circlewithrighthalfblack: "25D1", - circumflex: "02C6", - circumflexbelowcmb: "032D", - circumflexcmb: "0302", - clear: "2327", - clickalveolar: "01C2", - clickdental: "01C0", - clicklateral: "01C1", - clickretroflex: "01C3", - club: "2663", - clubsuitblack: "2663", - clubsuitwhite: "2667", - cmcubedsquare: "33A4", - cmonospace: "FF43", - cmsquaredsquare: "33A0", - coarmenian: "0581", - colon: "003A", - colonmonetary: "20A1", - colonmonospace: "FF1A", - colonsign: "20A1", - colonsmall: "FE55", - colontriangularhalfmod: "02D1", - colontriangularmod: "02D0", - comma: "002C", - commaabovecmb: "0313", - commaaboverightcmb: "0315", - commaaccent: "F6C3", - commaarabic: "060C", - commaarmenian: "055D", - commainferior: "F6E1", - commamonospace: "FF0C", - commareversedabovecmb: "0314", - commareversedmod: "02BD", - commasmall: "FE50", - commasuperior: "F6E2", - commaturnedabovecmb: "0312", - commaturnedmod: "02BB", - compass: "263C", - congruent: "2245", - contourintegral: "222E", - control: "2303", - controlACK: "0006", - controlBEL: "0007", - controlBS: "0008", - controlCAN: "0018", - controlCR: "000D", - controlDC1: "0011", - controlDC2: "0012", - controlDC3: "0013", - controlDC4: "0014", - controlDEL: "007F", - controlDLE: "0010", - controlEM: "0019", - controlENQ: "0005", - controlEOT: "0004", - controlESC: "001B", - controlETB: "0017", - controlETX: "0003", - controlFF: "000C", - controlFS: "001C", - controlGS: "001D", - controlHT: "0009", - controlLF: "000A", - controlNAK: "0015", - controlRS: "001E", - controlSI: "000F", - controlSO: "000E", - controlSOT: "0002", - controlSTX: "0001", - controlSUB: "001A", - controlSYN: "0016", - controlUS: "001F", - controlVT: "000B", - copyright: "00A9", - copyrightsans: "F8E9", - copyrightserif: "F6D9", - cornerbracketleft: "300C", - cornerbracketlefthalfwidth: "FF62", - cornerbracketleftvertical: "FE41", - cornerbracketright: "300D", - cornerbracketrighthalfwidth: "FF63", - cornerbracketrightvertical: "FE42", - corporationsquare: "337F", - cosquare: "33C7", - coverkgsquare: "33C6", - cparen: "249E", - cruzeiro: "20A2", - cstretched: "0297", - curlyand: "22CF", - curlyor: "22CE", - currency: "00A4", - cyrBreve: "F6D1", - cyrFlex: "F6D2", - cyrbreve: "F6D4", - cyrflex: "F6D5", - d: "0064", - daarmenian: "0564", - dabengali: "09A6", - dadarabic: "0636", - dadeva: "0926", - dadfinalarabic: "FEBE", - dadinitialarabic: "FEBF", - dadmedialarabic: "FEC0", - dagesh: "05BC", - dageshhebrew: "05BC", - dagger: "2020", - daggerdbl: "2021", - dagujarati: "0AA6", - dagurmukhi: "0A26", - dahiragana: "3060", - dakatakana: "30C0", - dalarabic: "062F", - dalet: "05D3", - daletdagesh: "FB33", - daletdageshhebrew: "FB33", + A: 0x0041, + AE: 0x00C6, + AEacute: 0x01FC, + AEmacron: 0x01E2, + AEsmall: 0xF7E6, + Aacute: 0x00C1, + Aacutesmall: 0xF7E1, + Abreve: 0x0102, + Abreveacute: 0x1EAE, + Abrevecyrillic: 0x04D0, + Abrevedotbelow: 0x1EB6, + Abrevegrave: 0x1EB0, + Abrevehookabove: 0x1EB2, + Abrevetilde: 0x1EB4, + Acaron: 0x01CD, + Acircle: 0x24B6, + Acircumflex: 0x00C2, + Acircumflexacute: 0x1EA4, + Acircumflexdotbelow: 0x1EAC, + Acircumflexgrave: 0x1EA6, + Acircumflexhookabove: 0x1EA8, + Acircumflexsmall: 0xF7E2, + Acircumflextilde: 0x1EAA, + Acute: 0xF6C9, + Acutesmall: 0xF7B4, + Acyrillic: 0x0410, + Adblgrave: 0x0200, + Adieresis: 0x00C4, + Adieresiscyrillic: 0x04D2, + Adieresismacron: 0x01DE, + Adieresissmall: 0xF7E4, + Adotbelow: 0x1EA0, + Adotmacron: 0x01E0, + Agrave: 0x00C0, + Agravesmall: 0xF7E0, + Ahookabove: 0x1EA2, + Aiecyrillic: 0x04D4, + Ainvertedbreve: 0x0202, + Alpha: 0x0391, + Alphatonos: 0x0386, + Amacron: 0x0100, + Amonospace: 0xFF21, + Aogonek: 0x0104, + Aring: 0x00C5, + Aringacute: 0x01FA, + Aringbelow: 0x1E00, + Aringsmall: 0xF7E5, + Asmall: 0xF761, + Atilde: 0x00C3, + Atildesmall: 0xF7E3, + Aybarmenian: 0x0531, + B: 0x0042, + Bcircle: 0x24B7, + Bdotaccent: 0x1E02, + Bdotbelow: 0x1E04, + Becyrillic: 0x0411, + Benarmenian: 0x0532, + Beta: 0x0392, + Bhook: 0x0181, + Blinebelow: 0x1E06, + Bmonospace: 0xFF22, + Brevesmall: 0xF6F4, + Bsmall: 0xF762, + Btopbar: 0x0182, + C: 0x0043, + Caarmenian: 0x053E, + Cacute: 0x0106, + Caron: 0xF6CA, + Caronsmall: 0xF6F5, + Ccaron: 0x010C, + Ccedilla: 0x00C7, + Ccedillaacute: 0x1E08, + Ccedillasmall: 0xF7E7, + Ccircle: 0x24B8, + Ccircumflex: 0x0108, + Cdot: 0x010A, + Cdotaccent: 0x010A, + Cedillasmall: 0xF7B8, + Chaarmenian: 0x0549, + Cheabkhasiancyrillic: 0x04BC, + Checyrillic: 0x0427, + Chedescenderabkhasiancyrillic: 0x04BE, + Chedescendercyrillic: 0x04B6, + Chedieresiscyrillic: 0x04F4, + Cheharmenian: 0x0543, + Chekhakassiancyrillic: 0x04CB, + Cheverticalstrokecyrillic: 0x04B8, + Chi: 0x03A7, + Chook: 0x0187, + Circumflexsmall: 0xF6F6, + Cmonospace: 0xFF23, + Coarmenian: 0x0551, + Csmall: 0xF763, + D: 0x0044, + DZ: 0x01F1, + DZcaron: 0x01C4, + Daarmenian: 0x0534, + Dafrican: 0x0189, + Dcaron: 0x010E, + Dcedilla: 0x1E10, + Dcircle: 0x24B9, + Dcircumflexbelow: 0x1E12, + Dcroat: 0x0110, + Ddotaccent: 0x1E0A, + Ddotbelow: 0x1E0C, + Decyrillic: 0x0414, + Deicoptic: 0x03EE, + Delta: 0x2206, + Deltagreek: 0x0394, + Dhook: 0x018A, + Dieresis: 0xF6CB, + DieresisAcute: 0xF6CC, + DieresisGrave: 0xF6CD, + Dieresissmall: 0xF7A8, + Digammagreek: 0x03DC, + Djecyrillic: 0x0402, + Dlinebelow: 0x1E0E, + Dmonospace: 0xFF24, + Dotaccentsmall: 0xF6F7, + Dslash: 0x0110, + Dsmall: 0xF764, + Dtopbar: 0x018B, + Dz: 0x01F2, + Dzcaron: 0x01C5, + Dzeabkhasiancyrillic: 0x04E0, + Dzecyrillic: 0x0405, + Dzhecyrillic: 0x040F, + E: 0x0045, + Eacute: 0x00C9, + Eacutesmall: 0xF7E9, + Ebreve: 0x0114, + Ecaron: 0x011A, + Ecedillabreve: 0x1E1C, + Echarmenian: 0x0535, + Ecircle: 0x24BA, + Ecircumflex: 0x00CA, + Ecircumflexacute: 0x1EBE, + Ecircumflexbelow: 0x1E18, + Ecircumflexdotbelow: 0x1EC6, + Ecircumflexgrave: 0x1EC0, + Ecircumflexhookabove: 0x1EC2, + Ecircumflexsmall: 0xF7EA, + Ecircumflextilde: 0x1EC4, + Ecyrillic: 0x0404, + Edblgrave: 0x0204, + Edieresis: 0x00CB, + Edieresissmall: 0xF7EB, + Edot: 0x0116, + Edotaccent: 0x0116, + Edotbelow: 0x1EB8, + Efcyrillic: 0x0424, + Egrave: 0x00C8, + Egravesmall: 0xF7E8, + Eharmenian: 0x0537, + Ehookabove: 0x1EBA, + Eightroman: 0x2167, + Einvertedbreve: 0x0206, + Eiotifiedcyrillic: 0x0464, + Elcyrillic: 0x041B, + Elevenroman: 0x216A, + Emacron: 0x0112, + Emacronacute: 0x1E16, + Emacrongrave: 0x1E14, + Emcyrillic: 0x041C, + Emonospace: 0xFF25, + Encyrillic: 0x041D, + Endescendercyrillic: 0x04A2, + Eng: 0x014A, + Enghecyrillic: 0x04A4, + Enhookcyrillic: 0x04C7, + Eogonek: 0x0118, + Eopen: 0x0190, + Epsilon: 0x0395, + Epsilontonos: 0x0388, + Ercyrillic: 0x0420, + Ereversed: 0x018E, + Ereversedcyrillic: 0x042D, + Escyrillic: 0x0421, + Esdescendercyrillic: 0x04AA, + Esh: 0x01A9, + Esmall: 0xF765, + Eta: 0x0397, + Etarmenian: 0x0538, + Etatonos: 0x0389, + Eth: 0x00D0, + Ethsmall: 0xF7F0, + Etilde: 0x1EBC, + Etildebelow: 0x1E1A, + Euro: 0x20AC, + Ezh: 0x01B7, + Ezhcaron: 0x01EE, + Ezhreversed: 0x01B8, + F: 0x0046, + Fcircle: 0x24BB, + Fdotaccent: 0x1E1E, + Feharmenian: 0x0556, + Feicoptic: 0x03E4, + Fhook: 0x0191, + Fitacyrillic: 0x0472, + Fiveroman: 0x2164, + Fmonospace: 0xFF26, + Fourroman: 0x2163, + Fsmall: 0xF766, + G: 0x0047, + GBsquare: 0x3387, + Gacute: 0x01F4, + Gamma: 0x0393, + Gammaafrican: 0x0194, + Gangiacoptic: 0x03EA, + Gbreve: 0x011E, + Gcaron: 0x01E6, + Gcedilla: 0x0122, + Gcircle: 0x24BC, + Gcircumflex: 0x011C, + Gcommaaccent: 0x0122, + Gdot: 0x0120, + Gdotaccent: 0x0120, + Gecyrillic: 0x0413, + Ghadarmenian: 0x0542, + Ghemiddlehookcyrillic: 0x0494, + Ghestrokecyrillic: 0x0492, + Gheupturncyrillic: 0x0490, + Ghook: 0x0193, + Gimarmenian: 0x0533, + Gjecyrillic: 0x0403, + Gmacron: 0x1E20, + Gmonospace: 0xFF27, + Grave: 0xF6CE, + Gravesmall: 0xF760, + Gsmall: 0xF767, + Gsmallhook: 0x029B, + Gstroke: 0x01E4, + H: 0x0048, + H18533: 0x25CF, + H18543: 0x25AA, + H18551: 0x25AB, + H22073: 0x25A1, + HPsquare: 0x33CB, + Haabkhasiancyrillic: 0x04A8, + Hadescendercyrillic: 0x04B2, + Hardsigncyrillic: 0x042A, + Hbar: 0x0126, + Hbrevebelow: 0x1E2A, + Hcedilla: 0x1E28, + Hcircle: 0x24BD, + Hcircumflex: 0x0124, + Hdieresis: 0x1E26, + Hdotaccent: 0x1E22, + Hdotbelow: 0x1E24, + Hmonospace: 0xFF28, + Hoarmenian: 0x0540, + Horicoptic: 0x03E8, + Hsmall: 0xF768, + Hungarumlaut: 0xF6CF, + Hungarumlautsmall: 0xF6F8, + Hzsquare: 0x3390, + I: 0x0049, + IAcyrillic: 0x042F, + IJ: 0x0132, + IUcyrillic: 0x042E, + Iacute: 0x00CD, + Iacutesmall: 0xF7ED, + Ibreve: 0x012C, + Icaron: 0x01CF, + Icircle: 0x24BE, + Icircumflex: 0x00CE, + Icircumflexsmall: 0xF7EE, + Icyrillic: 0x0406, + Idblgrave: 0x0208, + Idieresis: 0x00CF, + Idieresisacute: 0x1E2E, + Idieresiscyrillic: 0x04E4, + Idieresissmall: 0xF7EF, + Idot: 0x0130, + Idotaccent: 0x0130, + Idotbelow: 0x1ECA, + Iebrevecyrillic: 0x04D6, + Iecyrillic: 0x0415, + Ifraktur: 0x2111, + Igrave: 0x00CC, + Igravesmall: 0xF7EC, + Ihookabove: 0x1EC8, + Iicyrillic: 0x0418, + Iinvertedbreve: 0x020A, + Iishortcyrillic: 0x0419, + Imacron: 0x012A, + Imacroncyrillic: 0x04E2, + Imonospace: 0xFF29, + Iniarmenian: 0x053B, + Iocyrillic: 0x0401, + Iogonek: 0x012E, + Iota: 0x0399, + Iotaafrican: 0x0196, + Iotadieresis: 0x03AA, + Iotatonos: 0x038A, + Ismall: 0xF769, + Istroke: 0x0197, + Itilde: 0x0128, + Itildebelow: 0x1E2C, + Izhitsacyrillic: 0x0474, + Izhitsadblgravecyrillic: 0x0476, + J: 0x004A, + Jaarmenian: 0x0541, + Jcircle: 0x24BF, + Jcircumflex: 0x0134, + Jecyrillic: 0x0408, + Jheharmenian: 0x054B, + Jmonospace: 0xFF2A, + Jsmall: 0xF76A, + K: 0x004B, + KBsquare: 0x3385, + KKsquare: 0x33CD, + Kabashkircyrillic: 0x04A0, + Kacute: 0x1E30, + Kacyrillic: 0x041A, + Kadescendercyrillic: 0x049A, + Kahookcyrillic: 0x04C3, + Kappa: 0x039A, + Kastrokecyrillic: 0x049E, + Kaverticalstrokecyrillic: 0x049C, + Kcaron: 0x01E8, + Kcedilla: 0x0136, + Kcircle: 0x24C0, + Kcommaaccent: 0x0136, + Kdotbelow: 0x1E32, + Keharmenian: 0x0554, + Kenarmenian: 0x053F, + Khacyrillic: 0x0425, + Kheicoptic: 0x03E6, + Khook: 0x0198, + Kjecyrillic: 0x040C, + Klinebelow: 0x1E34, + Kmonospace: 0xFF2B, + Koppacyrillic: 0x0480, + Koppagreek: 0x03DE, + Ksicyrillic: 0x046E, + Ksmall: 0xF76B, + L: 0x004C, + LJ: 0x01C7, + LL: 0xF6BF, + Lacute: 0x0139, + Lambda: 0x039B, + Lcaron: 0x013D, + Lcedilla: 0x013B, + Lcircle: 0x24C1, + Lcircumflexbelow: 0x1E3C, + Lcommaaccent: 0x013B, + Ldot: 0x013F, + Ldotaccent: 0x013F, + Ldotbelow: 0x1E36, + Ldotbelowmacron: 0x1E38, + Liwnarmenian: 0x053C, + Lj: 0x01C8, + Ljecyrillic: 0x0409, + Llinebelow: 0x1E3A, + Lmonospace: 0xFF2C, + Lslash: 0x0141, + Lslashsmall: 0xF6F9, + Lsmall: 0xF76C, + M: 0x004D, + MBsquare: 0x3386, + Macron: 0xF6D0, + Macronsmall: 0xF7AF, + Macute: 0x1E3E, + Mcircle: 0x24C2, + Mdotaccent: 0x1E40, + Mdotbelow: 0x1E42, + Menarmenian: 0x0544, + Mmonospace: 0xFF2D, + Msmall: 0xF76D, + Mturned: 0x019C, + Mu: 0x039C, + N: 0x004E, + NJ: 0x01CA, + Nacute: 0x0143, + Ncaron: 0x0147, + Ncedilla: 0x0145, + Ncircle: 0x24C3, + Ncircumflexbelow: 0x1E4A, + Ncommaaccent: 0x0145, + Ndotaccent: 0x1E44, + Ndotbelow: 0x1E46, + Nhookleft: 0x019D, + Nineroman: 0x2168, + Nj: 0x01CB, + Njecyrillic: 0x040A, + Nlinebelow: 0x1E48, + Nmonospace: 0xFF2E, + Nowarmenian: 0x0546, + Nsmall: 0xF76E, + Ntilde: 0x00D1, + Ntildesmall: 0xF7F1, + Nu: 0x039D, + O: 0x004F, + OE: 0x0152, + OEsmall: 0xF6FA, + Oacute: 0x00D3, + Oacutesmall: 0xF7F3, + Obarredcyrillic: 0x04E8, + Obarreddieresiscyrillic: 0x04EA, + Obreve: 0x014E, + Ocaron: 0x01D1, + Ocenteredtilde: 0x019F, + Ocircle: 0x24C4, + Ocircumflex: 0x00D4, + Ocircumflexacute: 0x1ED0, + Ocircumflexdotbelow: 0x1ED8, + Ocircumflexgrave: 0x1ED2, + Ocircumflexhookabove: 0x1ED4, + Ocircumflexsmall: 0xF7F4, + Ocircumflextilde: 0x1ED6, + Ocyrillic: 0x041E, + Odblacute: 0x0150, + Odblgrave: 0x020C, + Odieresis: 0x00D6, + Odieresiscyrillic: 0x04E6, + Odieresissmall: 0xF7F6, + Odotbelow: 0x1ECC, + Ogoneksmall: 0xF6FB, + Ograve: 0x00D2, + Ogravesmall: 0xF7F2, + Oharmenian: 0x0555, + Ohm: 0x2126, + Ohookabove: 0x1ECE, + Ohorn: 0x01A0, + Ohornacute: 0x1EDA, + Ohorndotbelow: 0x1EE2, + Ohorngrave: 0x1EDC, + Ohornhookabove: 0x1EDE, + Ohorntilde: 0x1EE0, + Ohungarumlaut: 0x0150, + Oi: 0x01A2, + Oinvertedbreve: 0x020E, + Omacron: 0x014C, + Omacronacute: 0x1E52, + Omacrongrave: 0x1E50, + Omega: 0x2126, + Omegacyrillic: 0x0460, + Omegagreek: 0x03A9, + Omegaroundcyrillic: 0x047A, + Omegatitlocyrillic: 0x047C, + Omegatonos: 0x038F, + Omicron: 0x039F, + Omicrontonos: 0x038C, + Omonospace: 0xFF2F, + Oneroman: 0x2160, + Oogonek: 0x01EA, + Oogonekmacron: 0x01EC, + Oopen: 0x0186, + Oslash: 0x00D8, + Oslashacute: 0x01FE, + Oslashsmall: 0xF7F8, + Osmall: 0xF76F, + Ostrokeacute: 0x01FE, + Otcyrillic: 0x047E, + Otilde: 0x00D5, + Otildeacute: 0x1E4C, + Otildedieresis: 0x1E4E, + Otildesmall: 0xF7F5, + P: 0x0050, + Pacute: 0x1E54, + Pcircle: 0x24C5, + Pdotaccent: 0x1E56, + Pecyrillic: 0x041F, + Peharmenian: 0x054A, + Pemiddlehookcyrillic: 0x04A6, + Phi: 0x03A6, + Phook: 0x01A4, + Pi: 0x03A0, + Piwrarmenian: 0x0553, + Pmonospace: 0xFF30, + Psi: 0x03A8, + Psicyrillic: 0x0470, + Psmall: 0xF770, + Q: 0x0051, + Qcircle: 0x24C6, + Qmonospace: 0xFF31, + Qsmall: 0xF771, + R: 0x0052, + Raarmenian: 0x054C, + Racute: 0x0154, + Rcaron: 0x0158, + Rcedilla: 0x0156, + Rcircle: 0x24C7, + Rcommaaccent: 0x0156, + Rdblgrave: 0x0210, + Rdotaccent: 0x1E58, + Rdotbelow: 0x1E5A, + Rdotbelowmacron: 0x1E5C, + Reharmenian: 0x0550, + Rfraktur: 0x211C, + Rho: 0x03A1, + Ringsmall: 0xF6FC, + Rinvertedbreve: 0x0212, + Rlinebelow: 0x1E5E, + Rmonospace: 0xFF32, + Rsmall: 0xF772, + Rsmallinverted: 0x0281, + Rsmallinvertedsuperior: 0x02B6, + S: 0x0053, + SF010000: 0x250C, + SF020000: 0x2514, + SF030000: 0x2510, + SF040000: 0x2518, + SF050000: 0x253C, + SF060000: 0x252C, + SF070000: 0x2534, + SF080000: 0x251C, + SF090000: 0x2524, + SF100000: 0x2500, + SF110000: 0x2502, + SF190000: 0x2561, + SF200000: 0x2562, + SF210000: 0x2556, + SF220000: 0x2555, + SF230000: 0x2563, + SF240000: 0x2551, + SF250000: 0x2557, + SF260000: 0x255D, + SF270000: 0x255C, + SF280000: 0x255B, + SF360000: 0x255E, + SF370000: 0x255F, + SF380000: 0x255A, + SF390000: 0x2554, + SF400000: 0x2569, + SF410000: 0x2566, + SF420000: 0x2560, + SF430000: 0x2550, + SF440000: 0x256C, + SF450000: 0x2567, + SF460000: 0x2568, + SF470000: 0x2564, + SF480000: 0x2565, + SF490000: 0x2559, + SF500000: 0x2558, + SF510000: 0x2552, + SF520000: 0x2553, + SF530000: 0x256B, + SF540000: 0x256A, + Sacute: 0x015A, + Sacutedotaccent: 0x1E64, + Sampigreek: 0x03E0, + Scaron: 0x0160, + Scarondotaccent: 0x1E66, + Scaronsmall: 0xF6FD, + Scedilla: 0x015E, + Schwa: 0x018F, + Schwacyrillic: 0x04D8, + Schwadieresiscyrillic: 0x04DA, + Scircle: 0x24C8, + Scircumflex: 0x015C, + Scommaaccent: 0x0218, + Sdotaccent: 0x1E60, + Sdotbelow: 0x1E62, + Sdotbelowdotaccent: 0x1E68, + Seharmenian: 0x054D, + Sevenroman: 0x2166, + Shaarmenian: 0x0547, + Shacyrillic: 0x0428, + Shchacyrillic: 0x0429, + Sheicoptic: 0x03E2, + Shhacyrillic: 0x04BA, + Shimacoptic: 0x03EC, + Sigma: 0x03A3, + Sixroman: 0x2165, + Smonospace: 0xFF33, + Softsigncyrillic: 0x042C, + Ssmall: 0xF773, + Stigmagreek: 0x03DA, + T: 0x0054, + Tau: 0x03A4, + Tbar: 0x0166, + Tcaron: 0x0164, + Tcedilla: 0x0162, + Tcircle: 0x24C9, + Tcircumflexbelow: 0x1E70, + Tcommaaccent: 0x0162, + Tdotaccent: 0x1E6A, + Tdotbelow: 0x1E6C, + Tecyrillic: 0x0422, + Tedescendercyrillic: 0x04AC, + Tenroman: 0x2169, + Tetsecyrillic: 0x04B4, + Theta: 0x0398, + Thook: 0x01AC, + Thorn: 0x00DE, + Thornsmall: 0xF7FE, + Threeroman: 0x2162, + Tildesmall: 0xF6FE, + Tiwnarmenian: 0x054F, + Tlinebelow: 0x1E6E, + Tmonospace: 0xFF34, + Toarmenian: 0x0539, + Tonefive: 0x01BC, + Tonesix: 0x0184, + Tonetwo: 0x01A7, + Tretroflexhook: 0x01AE, + Tsecyrillic: 0x0426, + Tshecyrillic: 0x040B, + Tsmall: 0xF774, + Twelveroman: 0x216B, + Tworoman: 0x2161, + U: 0x0055, + Uacute: 0x00DA, + Uacutesmall: 0xF7FA, + Ubreve: 0x016C, + Ucaron: 0x01D3, + Ucircle: 0x24CA, + Ucircumflex: 0x00DB, + Ucircumflexbelow: 0x1E76, + Ucircumflexsmall: 0xF7FB, + Ucyrillic: 0x0423, + Udblacute: 0x0170, + Udblgrave: 0x0214, + Udieresis: 0x00DC, + Udieresisacute: 0x01D7, + Udieresisbelow: 0x1E72, + Udieresiscaron: 0x01D9, + Udieresiscyrillic: 0x04F0, + Udieresisgrave: 0x01DB, + Udieresismacron: 0x01D5, + Udieresissmall: 0xF7FC, + Udotbelow: 0x1EE4, + Ugrave: 0x00D9, + Ugravesmall: 0xF7F9, + Uhookabove: 0x1EE6, + Uhorn: 0x01AF, + Uhornacute: 0x1EE8, + Uhorndotbelow: 0x1EF0, + Uhorngrave: 0x1EEA, + Uhornhookabove: 0x1EEC, + Uhorntilde: 0x1EEE, + Uhungarumlaut: 0x0170, + Uhungarumlautcyrillic: 0x04F2, + Uinvertedbreve: 0x0216, + Ukcyrillic: 0x0478, + Umacron: 0x016A, + Umacroncyrillic: 0x04EE, + Umacrondieresis: 0x1E7A, + Umonospace: 0xFF35, + Uogonek: 0x0172, + Upsilon: 0x03A5, + Upsilon1: 0x03D2, + Upsilonacutehooksymbolgreek: 0x03D3, + Upsilonafrican: 0x01B1, + Upsilondieresis: 0x03AB, + Upsilondieresishooksymbolgreek: 0x03D4, + Upsilonhooksymbol: 0x03D2, + Upsilontonos: 0x038E, + Uring: 0x016E, + Ushortcyrillic: 0x040E, + Usmall: 0xF775, + Ustraightcyrillic: 0x04AE, + Ustraightstrokecyrillic: 0x04B0, + Utilde: 0x0168, + Utildeacute: 0x1E78, + Utildebelow: 0x1E74, + V: 0x0056, + Vcircle: 0x24CB, + Vdotbelow: 0x1E7E, + Vecyrillic: 0x0412, + Vewarmenian: 0x054E, + Vhook: 0x01B2, + Vmonospace: 0xFF36, + Voarmenian: 0x0548, + Vsmall: 0xF776, + Vtilde: 0x1E7C, + W: 0x0057, + Wacute: 0x1E82, + Wcircle: 0x24CC, + Wcircumflex: 0x0174, + Wdieresis: 0x1E84, + Wdotaccent: 0x1E86, + Wdotbelow: 0x1E88, + Wgrave: 0x1E80, + Wmonospace: 0xFF37, + Wsmall: 0xF777, + X: 0x0058, + Xcircle: 0x24CD, + Xdieresis: 0x1E8C, + Xdotaccent: 0x1E8A, + Xeharmenian: 0x053D, + Xi: 0x039E, + Xmonospace: 0xFF38, + Xsmall: 0xF778, + Y: 0x0059, + Yacute: 0x00DD, + Yacutesmall: 0xF7FD, + Yatcyrillic: 0x0462, + Ycircle: 0x24CE, + Ycircumflex: 0x0176, + Ydieresis: 0x0178, + Ydieresissmall: 0xF7FF, + Ydotaccent: 0x1E8E, + Ydotbelow: 0x1EF4, + Yericyrillic: 0x042B, + Yerudieresiscyrillic: 0x04F8, + Ygrave: 0x1EF2, + Yhook: 0x01B3, + Yhookabove: 0x1EF6, + Yiarmenian: 0x0545, + Yicyrillic: 0x0407, + Yiwnarmenian: 0x0552, + Ymonospace: 0xFF39, + Ysmall: 0xF779, + Ytilde: 0x1EF8, + Yusbigcyrillic: 0x046A, + Yusbigiotifiedcyrillic: 0x046C, + Yuslittlecyrillic: 0x0466, + Yuslittleiotifiedcyrillic: 0x0468, + Z: 0x005A, + Zaarmenian: 0x0536, + Zacute: 0x0179, + Zcaron: 0x017D, + Zcaronsmall: 0xF6FF, + Zcircle: 0x24CF, + Zcircumflex: 0x1E90, + Zdot: 0x017B, + Zdotaccent: 0x017B, + Zdotbelow: 0x1E92, + Zecyrillic: 0x0417, + Zedescendercyrillic: 0x0498, + Zedieresiscyrillic: 0x04DE, + Zeta: 0x0396, + Zhearmenian: 0x053A, + Zhebrevecyrillic: 0x04C1, + Zhecyrillic: 0x0416, + Zhedescendercyrillic: 0x0496, + Zhedieresiscyrillic: 0x04DC, + Zlinebelow: 0x1E94, + Zmonospace: 0xFF3A, + Zsmall: 0xF77A, + Zstroke: 0x01B5, + a: 0x0061, + aabengali: 0x0986, + aacute: 0x00E1, + aadeva: 0x0906, + aagujarati: 0x0A86, + aagurmukhi: 0x0A06, + aamatragurmukhi: 0x0A3E, + aarusquare: 0x3303, + aavowelsignbengali: 0x09BE, + aavowelsigndeva: 0x093E, + aavowelsigngujarati: 0x0ABE, + abbreviationmarkarmenian: 0x055F, + abbreviationsigndeva: 0x0970, + abengali: 0x0985, + abopomofo: 0x311A, + abreve: 0x0103, + abreveacute: 0x1EAF, + abrevecyrillic: 0x04D1, + abrevedotbelow: 0x1EB7, + abrevegrave: 0x1EB1, + abrevehookabove: 0x1EB3, + abrevetilde: 0x1EB5, + acaron: 0x01CE, + acircle: 0x24D0, + acircumflex: 0x00E2, + acircumflexacute: 0x1EA5, + acircumflexdotbelow: 0x1EAD, + acircumflexgrave: 0x1EA7, + acircumflexhookabove: 0x1EA9, + acircumflextilde: 0x1EAB, + acute: 0x00B4, + acutebelowcmb: 0x0317, + acutecmb: 0x0301, + acutecomb: 0x0301, + acutedeva: 0x0954, + acutelowmod: 0x02CF, + acutetonecmb: 0x0341, + acyrillic: 0x0430, + adblgrave: 0x0201, + addakgurmukhi: 0x0A71, + adeva: 0x0905, + adieresis: 0x00E4, + adieresiscyrillic: 0x04D3, + adieresismacron: 0x01DF, + adotbelow: 0x1EA1, + adotmacron: 0x01E1, + ae: 0x00E6, + aeacute: 0x01FD, + aekorean: 0x3150, + aemacron: 0x01E3, + afii00208: 0x2015, + afii08941: 0x20A4, + afii10017: 0x0410, + afii10018: 0x0411, + afii10019: 0x0412, + afii10020: 0x0413, + afii10021: 0x0414, + afii10022: 0x0415, + afii10023: 0x0401, + afii10024: 0x0416, + afii10025: 0x0417, + afii10026: 0x0418, + afii10027: 0x0419, + afii10028: 0x041A, + afii10029: 0x041B, + afii10030: 0x041C, + afii10031: 0x041D, + afii10032: 0x041E, + afii10033: 0x041F, + afii10034: 0x0420, + afii10035: 0x0421, + afii10036: 0x0422, + afii10037: 0x0423, + afii10038: 0x0424, + afii10039: 0x0425, + afii10040: 0x0426, + afii10041: 0x0427, + afii10042: 0x0428, + afii10043: 0x0429, + afii10044: 0x042A, + afii10045: 0x042B, + afii10046: 0x042C, + afii10047: 0x042D, + afii10048: 0x042E, + afii10049: 0x042F, + afii10050: 0x0490, + afii10051: 0x0402, + afii10052: 0x0403, + afii10053: 0x0404, + afii10054: 0x0405, + afii10055: 0x0406, + afii10056: 0x0407, + afii10057: 0x0408, + afii10058: 0x0409, + afii10059: 0x040A, + afii10060: 0x040B, + afii10061: 0x040C, + afii10062: 0x040E, + afii10063: 0xF6C4, + afii10064: 0xF6C5, + afii10065: 0x0430, + afii10066: 0x0431, + afii10067: 0x0432, + afii10068: 0x0433, + afii10069: 0x0434, + afii10070: 0x0435, + afii10071: 0x0451, + afii10072: 0x0436, + afii10073: 0x0437, + afii10074: 0x0438, + afii10075: 0x0439, + afii10076: 0x043A, + afii10077: 0x043B, + afii10078: 0x043C, + afii10079: 0x043D, + afii10080: 0x043E, + afii10081: 0x043F, + afii10082: 0x0440, + afii10083: 0x0441, + afii10084: 0x0442, + afii10085: 0x0443, + afii10086: 0x0444, + afii10087: 0x0445, + afii10088: 0x0446, + afii10089: 0x0447, + afii10090: 0x0448, + afii10091: 0x0449, + afii10092: 0x044A, + afii10093: 0x044B, + afii10094: 0x044C, + afii10095: 0x044D, + afii10096: 0x044E, + afii10097: 0x044F, + afii10098: 0x0491, + afii10099: 0x0452, + afii10100: 0x0453, + afii10101: 0x0454, + afii10102: 0x0455, + afii10103: 0x0456, + afii10104: 0x0457, + afii10105: 0x0458, + afii10106: 0x0459, + afii10107: 0x045A, + afii10108: 0x045B, + afii10109: 0x045C, + afii10110: 0x045E, + afii10145: 0x040F, + afii10146: 0x0462, + afii10147: 0x0472, + afii10148: 0x0474, + afii10192: 0xF6C6, + afii10193: 0x045F, + afii10194: 0x0463, + afii10195: 0x0473, + afii10196: 0x0475, + afii10831: 0xF6C7, + afii10832: 0xF6C8, + afii10846: 0x04D9, + afii299: 0x200E, + afii300: 0x200F, + afii301: 0x200D, + afii57381: 0x066A, + afii57388: 0x060C, + afii57392: 0x0660, + afii57393: 0x0661, + afii57394: 0x0662, + afii57395: 0x0663, + afii57396: 0x0664, + afii57397: 0x0665, + afii57398: 0x0666, + afii57399: 0x0667, + afii57400: 0x0668, + afii57401: 0x0669, + afii57403: 0x061B, + afii57407: 0x061F, + afii57409: 0x0621, + afii57410: 0x0622, + afii57411: 0x0623, + afii57412: 0x0624, + afii57413: 0x0625, + afii57414: 0x0626, + afii57415: 0x0627, + afii57416: 0x0628, + afii57417: 0x0629, + afii57418: 0x062A, + afii57419: 0x062B, + afii57420: 0x062C, + afii57421: 0x062D, + afii57422: 0x062E, + afii57423: 0x062F, + afii57424: 0x0630, + afii57425: 0x0631, + afii57426: 0x0632, + afii57427: 0x0633, + afii57428: 0x0634, + afii57429: 0x0635, + afii57430: 0x0636, + afii57431: 0x0637, + afii57432: 0x0638, + afii57433: 0x0639, + afii57434: 0x063A, + afii57440: 0x0640, + afii57441: 0x0641, + afii57442: 0x0642, + afii57443: 0x0643, + afii57444: 0x0644, + afii57445: 0x0645, + afii57446: 0x0646, + afii57448: 0x0648, + afii57449: 0x0649, + afii57450: 0x064A, + afii57451: 0x064B, + afii57452: 0x064C, + afii57453: 0x064D, + afii57454: 0x064E, + afii57455: 0x064F, + afii57456: 0x0650, + afii57457: 0x0651, + afii57458: 0x0652, + afii57470: 0x0647, + afii57505: 0x06A4, + afii57506: 0x067E, + afii57507: 0x0686, + afii57508: 0x0698, + afii57509: 0x06AF, + afii57511: 0x0679, + afii57512: 0x0688, + afii57513: 0x0691, + afii57514: 0x06BA, + afii57519: 0x06D2, + afii57534: 0x06D5, + afii57636: 0x20AA, + afii57645: 0x05BE, + afii57658: 0x05C3, + afii57664: 0x05D0, + afii57665: 0x05D1, + afii57666: 0x05D2, + afii57667: 0x05D3, + afii57668: 0x05D4, + afii57669: 0x05D5, + afii57670: 0x05D6, + afii57671: 0x05D7, + afii57672: 0x05D8, + afii57673: 0x05D9, + afii57674: 0x05DA, + afii57675: 0x05DB, + afii57676: 0x05DC, + afii57677: 0x05DD, + afii57678: 0x05DE, + afii57679: 0x05DF, + afii57680: 0x05E0, + afii57681: 0x05E1, + afii57682: 0x05E2, + afii57683: 0x05E3, + afii57684: 0x05E4, + afii57685: 0x05E5, + afii57686: 0x05E6, + afii57687: 0x05E7, + afii57688: 0x05E8, + afii57689: 0x05E9, + afii57690: 0x05EA, + afii57694: 0xFB2A, + afii57695: 0xFB2B, + afii57700: 0xFB4B, + afii57705: 0xFB1F, + afii57716: 0x05F0, + afii57717: 0x05F1, + afii57718: 0x05F2, + afii57723: 0xFB35, + afii57793: 0x05B4, + afii57794: 0x05B5, + afii57795: 0x05B6, + afii57796: 0x05BB, + afii57797: 0x05B8, + afii57798: 0x05B7, + afii57799: 0x05B0, + afii57800: 0x05B2, + afii57801: 0x05B1, + afii57802: 0x05B3, + afii57803: 0x05C2, + afii57804: 0x05C1, + afii57806: 0x05B9, + afii57807: 0x05BC, + afii57839: 0x05BD, + afii57841: 0x05BF, + afii57842: 0x05C0, + afii57929: 0x02BC, + afii61248: 0x2105, + afii61289: 0x2113, + afii61352: 0x2116, + afii61573: 0x202C, + afii61574: 0x202D, + afii61575: 0x202E, + afii61664: 0x200C, + afii63167: 0x066D, + afii64937: 0x02BD, + agrave: 0x00E0, + agujarati: 0x0A85, + agurmukhi: 0x0A05, + ahiragana: 0x3042, + ahookabove: 0x1EA3, + aibengali: 0x0990, + aibopomofo: 0x311E, + aideva: 0x0910, + aiecyrillic: 0x04D5, + aigujarati: 0x0A90, + aigurmukhi: 0x0A10, + aimatragurmukhi: 0x0A48, + ainarabic: 0x0639, + ainfinalarabic: 0xFECA, + aininitialarabic: 0xFECB, + ainmedialarabic: 0xFECC, + ainvertedbreve: 0x0203, + aivowelsignbengali: 0x09C8, + aivowelsigndeva: 0x0948, + aivowelsigngujarati: 0x0AC8, + akatakana: 0x30A2, + akatakanahalfwidth: 0xFF71, + akorean: 0x314F, + alef: 0x05D0, + alefarabic: 0x0627, + alefdageshhebrew: 0xFB30, + aleffinalarabic: 0xFE8E, + alefhamzaabovearabic: 0x0623, + alefhamzaabovefinalarabic: 0xFE84, + alefhamzabelowarabic: 0x0625, + alefhamzabelowfinalarabic: 0xFE88, + alefhebrew: 0x05D0, + aleflamedhebrew: 0xFB4F, + alefmaddaabovearabic: 0x0622, + alefmaddaabovefinalarabic: 0xFE82, + alefmaksuraarabic: 0x0649, + alefmaksurafinalarabic: 0xFEF0, + alefmaksurainitialarabic: 0xFEF3, + alefmaksuramedialarabic: 0xFEF4, + alefpatahhebrew: 0xFB2E, + alefqamatshebrew: 0xFB2F, + aleph: 0x2135, + allequal: 0x224C, + alpha: 0x03B1, + alphatonos: 0x03AC, + amacron: 0x0101, + amonospace: 0xFF41, + ampersand: 0x0026, + ampersandmonospace: 0xFF06, + ampersandsmall: 0xF726, + amsquare: 0x33C2, + anbopomofo: 0x3122, + angbopomofo: 0x3124, + angkhankhuthai: 0x0E5A, + angle: 0x2220, + anglebracketleft: 0x3008, + anglebracketleftvertical: 0xFE3F, + anglebracketright: 0x3009, + anglebracketrightvertical: 0xFE40, + angleleft: 0x2329, + angleright: 0x232A, + angstrom: 0x212B, + anoteleia: 0x0387, + anudattadeva: 0x0952, + anusvarabengali: 0x0982, + anusvaradeva: 0x0902, + anusvaragujarati: 0x0A82, + aogonek: 0x0105, + apaatosquare: 0x3300, + aparen: 0x249C, + apostrophearmenian: 0x055A, + apostrophemod: 0x02BC, + apple: 0xF8FF, + approaches: 0x2250, + approxequal: 0x2248, + approxequalorimage: 0x2252, + approximatelyequal: 0x2245, + araeaekorean: 0x318E, + araeakorean: 0x318D, + arc: 0x2312, + arighthalfring: 0x1E9A, + aring: 0x00E5, + aringacute: 0x01FB, + aringbelow: 0x1E01, + arrowboth: 0x2194, + arrowdashdown: 0x21E3, + arrowdashleft: 0x21E0, + arrowdashright: 0x21E2, + arrowdashup: 0x21E1, + arrowdblboth: 0x21D4, + arrowdbldown: 0x21D3, + arrowdblleft: 0x21D0, + arrowdblright: 0x21D2, + arrowdblup: 0x21D1, + arrowdown: 0x2193, + arrowdownleft: 0x2199, + arrowdownright: 0x2198, + arrowdownwhite: 0x21E9, + arrowheaddownmod: 0x02C5, + arrowheadleftmod: 0x02C2, + arrowheadrightmod: 0x02C3, + arrowheadupmod: 0x02C4, + arrowhorizex: 0xF8E7, + arrowleft: 0x2190, + arrowleftdbl: 0x21D0, + arrowleftdblstroke: 0x21CD, + arrowleftoverright: 0x21C6, + arrowleftwhite: 0x21E6, + arrowright: 0x2192, + arrowrightdblstroke: 0x21CF, + arrowrightheavy: 0x279E, + arrowrightoverleft: 0x21C4, + arrowrightwhite: 0x21E8, + arrowtableft: 0x21E4, + arrowtabright: 0x21E5, + arrowup: 0x2191, + arrowupdn: 0x2195, + arrowupdnbse: 0x21A8, + arrowupdownbase: 0x21A8, + arrowupleft: 0x2196, + arrowupleftofdown: 0x21C5, + arrowupright: 0x2197, + arrowupwhite: 0x21E7, + arrowvertex: 0xF8E6, + asciicircum: 0x005E, + asciicircummonospace: 0xFF3E, + asciitilde: 0x007E, + asciitildemonospace: 0xFF5E, + ascript: 0x0251, + ascriptturned: 0x0252, + asmallhiragana: 0x3041, + asmallkatakana: 0x30A1, + asmallkatakanahalfwidth: 0xFF67, + asterisk: 0x002A, + asteriskaltonearabic: 0x066D, + asteriskarabic: 0x066D, + asteriskmath: 0x2217, + asteriskmonospace: 0xFF0A, + asterisksmall: 0xFE61, + asterism: 0x2042, + asuperior: 0xF6E9, + asymptoticallyequal: 0x2243, + at: 0x0040, + atilde: 0x00E3, + atmonospace: 0xFF20, + atsmall: 0xFE6B, + aturned: 0x0250, + aubengali: 0x0994, + aubopomofo: 0x3120, + audeva: 0x0914, + augujarati: 0x0A94, + augurmukhi: 0x0A14, + aulengthmarkbengali: 0x09D7, + aumatragurmukhi: 0x0A4C, + auvowelsignbengali: 0x09CC, + auvowelsigndeva: 0x094C, + auvowelsigngujarati: 0x0ACC, + avagrahadeva: 0x093D, + aybarmenian: 0x0561, + ayin: 0x05E2, + ayinaltonehebrew: 0xFB20, + ayinhebrew: 0x05E2, + b: 0x0062, + babengali: 0x09AC, + backslash: 0x005C, + backslashmonospace: 0xFF3C, + badeva: 0x092C, + bagujarati: 0x0AAC, + bagurmukhi: 0x0A2C, + bahiragana: 0x3070, + bahtthai: 0x0E3F, + bakatakana: 0x30D0, + bar: 0x007C, + barmonospace: 0xFF5C, + bbopomofo: 0x3105, + bcircle: 0x24D1, + bdotaccent: 0x1E03, + bdotbelow: 0x1E05, + beamedsixteenthnotes: 0x266C, + because: 0x2235, + becyrillic: 0x0431, + beharabic: 0x0628, + behfinalarabic: 0xFE90, + behinitialarabic: 0xFE91, + behiragana: 0x3079, + behmedialarabic: 0xFE92, + behmeeminitialarabic: 0xFC9F, + behmeemisolatedarabic: 0xFC08, + behnoonfinalarabic: 0xFC6D, + bekatakana: 0x30D9, + benarmenian: 0x0562, + bet: 0x05D1, + beta: 0x03B2, + betasymbolgreek: 0x03D0, + betdagesh: 0xFB31, + betdageshhebrew: 0xFB31, + bethebrew: 0x05D1, + betrafehebrew: 0xFB4C, + bhabengali: 0x09AD, + bhadeva: 0x092D, + bhagujarati: 0x0AAD, + bhagurmukhi: 0x0A2D, + bhook: 0x0253, + bihiragana: 0x3073, + bikatakana: 0x30D3, + bilabialclick: 0x0298, + bindigurmukhi: 0x0A02, + birusquare: 0x3331, + blackcircle: 0x25CF, + blackdiamond: 0x25C6, + blackdownpointingtriangle: 0x25BC, + blackleftpointingpointer: 0x25C4, + blackleftpointingtriangle: 0x25C0, + blacklenticularbracketleft: 0x3010, + blacklenticularbracketleftvertical: 0xFE3B, + blacklenticularbracketright: 0x3011, + blacklenticularbracketrightvertical: 0xFE3C, + blacklowerlefttriangle: 0x25E3, + blacklowerrighttriangle: 0x25E2, + blackrectangle: 0x25AC, + blackrightpointingpointer: 0x25BA, + blackrightpointingtriangle: 0x25B6, + blacksmallsquare: 0x25AA, + blacksmilingface: 0x263B, + blacksquare: 0x25A0, + blackstar: 0x2605, + blackupperlefttriangle: 0x25E4, + blackupperrighttriangle: 0x25E5, + blackuppointingsmalltriangle: 0x25B4, + blackuppointingtriangle: 0x25B2, + blank: 0x2423, + blinebelow: 0x1E07, + block: 0x2588, + bmonospace: 0xFF42, + bobaimaithai: 0x0E1A, + bohiragana: 0x307C, + bokatakana: 0x30DC, + bparen: 0x249D, + bqsquare: 0x33C3, + braceex: 0xF8F4, + braceleft: 0x007B, + braceleftbt: 0xF8F3, + braceleftmid: 0xF8F2, + braceleftmonospace: 0xFF5B, + braceleftsmall: 0xFE5B, + bracelefttp: 0xF8F1, + braceleftvertical: 0xFE37, + braceright: 0x007D, + bracerightbt: 0xF8FE, + bracerightmid: 0xF8FD, + bracerightmonospace: 0xFF5D, + bracerightsmall: 0xFE5C, + bracerighttp: 0xF8FC, + bracerightvertical: 0xFE38, + bracketleft: 0x005B, + bracketleftbt: 0xF8F0, + bracketleftex: 0xF8EF, + bracketleftmonospace: 0xFF3B, + bracketlefttp: 0xF8EE, + bracketright: 0x005D, + bracketrightbt: 0xF8FB, + bracketrightex: 0xF8FA, + bracketrightmonospace: 0xFF3D, + bracketrighttp: 0xF8F9, + breve: 0x02D8, + brevebelowcmb: 0x032E, + brevecmb: 0x0306, + breveinvertedbelowcmb: 0x032F, + breveinvertedcmb: 0x0311, + breveinverteddoublecmb: 0x0361, + bridgebelowcmb: 0x032A, + bridgeinvertedbelowcmb: 0x033A, + brokenbar: 0x00A6, + bstroke: 0x0180, + bsuperior: 0xF6EA, + btopbar: 0x0183, + buhiragana: 0x3076, + bukatakana: 0x30D6, + bullet: 0x2022, + bulletinverse: 0x25D8, + bulletoperator: 0x2219, + bullseye: 0x25CE, + c: 0x0063, + caarmenian: 0x056E, + cabengali: 0x099A, + cacute: 0x0107, + cadeva: 0x091A, + cagujarati: 0x0A9A, + cagurmukhi: 0x0A1A, + calsquare: 0x3388, + candrabindubengali: 0x0981, + candrabinducmb: 0x0310, + candrabindudeva: 0x0901, + candrabindugujarati: 0x0A81, + capslock: 0x21EA, + careof: 0x2105, + caron: 0x02C7, + caronbelowcmb: 0x032C, + caroncmb: 0x030C, + carriagereturn: 0x21B5, + cbopomofo: 0x3118, + ccaron: 0x010D, + ccedilla: 0x00E7, + ccedillaacute: 0x1E09, + ccircle: 0x24D2, + ccircumflex: 0x0109, + ccurl: 0x0255, + cdot: 0x010B, + cdotaccent: 0x010B, + cdsquare: 0x33C5, + cedilla: 0x00B8, + cedillacmb: 0x0327, + cent: 0x00A2, + centigrade: 0x2103, + centinferior: 0xF6DF, + centmonospace: 0xFFE0, + centoldstyle: 0xF7A2, + centsuperior: 0xF6E0, + chaarmenian: 0x0579, + chabengali: 0x099B, + chadeva: 0x091B, + chagujarati: 0x0A9B, + chagurmukhi: 0x0A1B, + chbopomofo: 0x3114, + cheabkhasiancyrillic: 0x04BD, + checkmark: 0x2713, + checyrillic: 0x0447, + chedescenderabkhasiancyrillic: 0x04BF, + chedescendercyrillic: 0x04B7, + chedieresiscyrillic: 0x04F5, + cheharmenian: 0x0573, + chekhakassiancyrillic: 0x04CC, + cheverticalstrokecyrillic: 0x04B9, + chi: 0x03C7, + chieuchacirclekorean: 0x3277, + chieuchaparenkorean: 0x3217, + chieuchcirclekorean: 0x3269, + chieuchkorean: 0x314A, + chieuchparenkorean: 0x3209, + chochangthai: 0x0E0A, + chochanthai: 0x0E08, + chochingthai: 0x0E09, + chochoethai: 0x0E0C, + chook: 0x0188, + cieucacirclekorean: 0x3276, + cieucaparenkorean: 0x3216, + cieuccirclekorean: 0x3268, + cieuckorean: 0x3148, + cieucparenkorean: 0x3208, + cieucuparenkorean: 0x321C, + circle: 0x25CB, + circlemultiply: 0x2297, + circleot: 0x2299, + circleplus: 0x2295, + circlepostalmark: 0x3036, + circlewithlefthalfblack: 0x25D0, + circlewithrighthalfblack: 0x25D1, + circumflex: 0x02C6, + circumflexbelowcmb: 0x032D, + circumflexcmb: 0x0302, + clear: 0x2327, + clickalveolar: 0x01C2, + clickdental: 0x01C0, + clicklateral: 0x01C1, + clickretroflex: 0x01C3, + club: 0x2663, + clubsuitblack: 0x2663, + clubsuitwhite: 0x2667, + cmcubedsquare: 0x33A4, + cmonospace: 0xFF43, + cmsquaredsquare: 0x33A0, + coarmenian: 0x0581, + colon: 0x003A, + colonmonetary: 0x20A1, + colonmonospace: 0xFF1A, + colonsign: 0x20A1, + colonsmall: 0xFE55, + colontriangularhalfmod: 0x02D1, + colontriangularmod: 0x02D0, + comma: 0x002C, + commaabovecmb: 0x0313, + commaaboverightcmb: 0x0315, + commaaccent: 0xF6C3, + commaarabic: 0x060C, + commaarmenian: 0x055D, + commainferior: 0xF6E1, + commamonospace: 0xFF0C, + commareversedabovecmb: 0x0314, + commareversedmod: 0x02BD, + commasmall: 0xFE50, + commasuperior: 0xF6E2, + commaturnedabovecmb: 0x0312, + commaturnedmod: 0x02BB, + compass: 0x263C, + congruent: 0x2245, + contourintegral: 0x222E, + control: 0x2303, + controlACK: 0x0006, + controlBEL: 0x0007, + controlBS: 0x0008, + controlCAN: 0x0018, + controlCR: 0x000D, + controlDC1: 0x0011, + controlDC2: 0x0012, + controlDC3: 0x0013, + controlDC4: 0x0014, + controlDEL: 0x007F, + controlDLE: 0x0010, + controlEM: 0x0019, + controlENQ: 0x0005, + controlEOT: 0x0004, + controlESC: 0x001B, + controlETB: 0x0017, + controlETX: 0x0003, + controlFF: 0x000C, + controlFS: 0x001C, + controlGS: 0x001D, + controlHT: 0x0009, + controlLF: 0x000A, + controlNAK: 0x0015, + controlRS: 0x001E, + controlSI: 0x000F, + controlSO: 0x000E, + controlSOT: 0x0002, + controlSTX: 0x0001, + controlSUB: 0x001A, + controlSYN: 0x0016, + controlUS: 0x001F, + controlVT: 0x000B, + copyright: 0x00A9, + copyrightsans: 0xF8E9, + copyrightserif: 0xF6D9, + cornerbracketleft: 0x300C, + cornerbracketlefthalfwidth: 0xFF62, + cornerbracketleftvertical: 0xFE41, + cornerbracketright: 0x300D, + cornerbracketrighthalfwidth: 0xFF63, + cornerbracketrightvertical: 0xFE42, + corporationsquare: 0x337F, + cosquare: 0x33C7, + coverkgsquare: 0x33C6, + cparen: 0x249E, + cruzeiro: 0x20A2, + cstretched: 0x0297, + curlyand: 0x22CF, + curlyor: 0x22CE, + currency: 0x00A4, + cyrBreve: 0xF6D1, + cyrFlex: 0xF6D2, + cyrbreve: 0xF6D4, + cyrflex: 0xF6D5, + d: 0x0064, + daarmenian: 0x0564, + dabengali: 0x09A6, + dadarabic: 0x0636, + dadeva: 0x0926, + dadfinalarabic: 0xFEBE, + dadinitialarabic: 0xFEBF, + dadmedialarabic: 0xFEC0, + dagesh: 0x05BC, + dageshhebrew: 0x05BC, + dagger: 0x2020, + daggerdbl: 0x2021, + dagujarati: 0x0AA6, + dagurmukhi: 0x0A26, + dahiragana: 0x3060, + dakatakana: 0x30C0, + dalarabic: 0x062F, + dalet: 0x05D3, + daletdagesh: 0xFB33, + daletdageshhebrew: 0xFB33, dalethatafpatah: "05D3 05B2", dalethatafpatahhebrew: "05D3 05B2", dalethatafsegol: "05D3 05B1", dalethatafsegolhebrew: "05D3 05B1", - dalethebrew: "05D3", + dalethebrew: 0x05D3, dalethiriq: "05D3 05B4", dalethiriqhebrew: "05D3 05B4", daletholam: "05D3 05B9", @@ -1521,1641 +1521,1641 @@ var GlyphsUnicode = { daletshevahebrew: "05D3 05B0", dalettsere: "05D3 05B5", dalettserehebrew: "05D3 05B5", - dalfinalarabic: "FEAA", - dammaarabic: "064F", - dammalowarabic: "064F", - dammatanaltonearabic: "064C", - dammatanarabic: "064C", - danda: "0964", - dargahebrew: "05A7", - dargalefthebrew: "05A7", - dasiapneumatacyrilliccmb: "0485", - dblGrave: "F6D3", - dblanglebracketleft: "300A", - dblanglebracketleftvertical: "FE3D", - dblanglebracketright: "300B", - dblanglebracketrightvertical: "FE3E", - dblarchinvertedbelowcmb: "032B", - dblarrowleft: "21D4", - dblarrowright: "21D2", - dbldanda: "0965", - dblgrave: "F6D6", - dblgravecmb: "030F", - dblintegral: "222C", - dbllowline: "2017", - dbllowlinecmb: "0333", - dbloverlinecmb: "033F", - dblprimemod: "02BA", - dblverticalbar: "2016", - dblverticallineabovecmb: "030E", - dbopomofo: "3109", - dbsquare: "33C8", - dcaron: "010F", - dcedilla: "1E11", - dcircle: "24D3", - dcircumflexbelow: "1E13", - dcroat: "0111", - ddabengali: "09A1", - ddadeva: "0921", - ddagujarati: "0AA1", - ddagurmukhi: "0A21", - ddalarabic: "0688", - ddalfinalarabic: "FB89", - dddhadeva: "095C", - ddhabengali: "09A2", - ddhadeva: "0922", - ddhagujarati: "0AA2", - ddhagurmukhi: "0A22", - ddotaccent: "1E0B", - ddotbelow: "1E0D", - decimalseparatorarabic: "066B", - decimalseparatorpersian: "066B", - decyrillic: "0434", - degree: "00B0", - dehihebrew: "05AD", - dehiragana: "3067", - deicoptic: "03EF", - dekatakana: "30C7", - deleteleft: "232B", - deleteright: "2326", - delta: "03B4", - deltaturned: "018D", - denominatorminusonenumeratorbengali: "09F8", - dezh: "02A4", - dhabengali: "09A7", - dhadeva: "0927", - dhagujarati: "0AA7", - dhagurmukhi: "0A27", - dhook: "0257", - dialytikatonos: "0385", - dialytikatonoscmb: "0344", - diamond: "2666", - diamondsuitwhite: "2662", - dieresis: "00A8", - dieresisacute: "F6D7", - dieresisbelowcmb: "0324", - dieresiscmb: "0308", - dieresisgrave: "F6D8", - dieresistonos: "0385", - dihiragana: "3062", - dikatakana: "30C2", - dittomark: "3003", - divide: "00F7", - divides: "2223", - divisionslash: "2215", - djecyrillic: "0452", - dkshade: "2593", - dlinebelow: "1E0F", - dlsquare: "3397", - dmacron: "0111", - dmonospace: "FF44", - dnblock: "2584", - dochadathai: "0E0E", - dodekthai: "0E14", - dohiragana: "3069", - dokatakana: "30C9", - dollar: "0024", - dollarinferior: "F6E3", - dollarmonospace: "FF04", - dollaroldstyle: "F724", - dollarsmall: "FE69", - dollarsuperior: "F6E4", - dong: "20AB", - dorusquare: "3326", - dotaccent: "02D9", - dotaccentcmb: "0307", - dotbelowcmb: "0323", - dotbelowcomb: "0323", - dotkatakana: "30FB", - dotlessi: "0131", - dotlessj: "F6BE", - dotlessjstrokehook: "0284", - dotmath: "22C5", - dottedcircle: "25CC", - doubleyodpatah: "FB1F", - doubleyodpatahhebrew: "FB1F", - downtackbelowcmb: "031E", - downtackmod: "02D5", - dparen: "249F", - dsuperior: "F6EB", - dtail: "0256", - dtopbar: "018C", - duhiragana: "3065", - dukatakana: "30C5", - dz: "01F3", - dzaltone: "02A3", - dzcaron: "01C6", - dzcurl: "02A5", - dzeabkhasiancyrillic: "04E1", - dzecyrillic: "0455", - dzhecyrillic: "045F", - e: "0065", - eacute: "00E9", - earth: "2641", - ebengali: "098F", - ebopomofo: "311C", - ebreve: "0115", - ecandradeva: "090D", - ecandragujarati: "0A8D", - ecandravowelsigndeva: "0945", - ecandravowelsigngujarati: "0AC5", - ecaron: "011B", - ecedillabreve: "1E1D", - echarmenian: "0565", - echyiwnarmenian: "0587", - ecircle: "24D4", - ecircumflex: "00EA", - ecircumflexacute: "1EBF", - ecircumflexbelow: "1E19", - ecircumflexdotbelow: "1EC7", - ecircumflexgrave: "1EC1", - ecircumflexhookabove: "1EC3", - ecircumflextilde: "1EC5", - ecyrillic: "0454", - edblgrave: "0205", - edeva: "090F", - edieresis: "00EB", - edot: "0117", - edotaccent: "0117", - edotbelow: "1EB9", - eegurmukhi: "0A0F", - eematragurmukhi: "0A47", - efcyrillic: "0444", - egrave: "00E8", - egujarati: "0A8F", - eharmenian: "0567", - ehbopomofo: "311D", - ehiragana: "3048", - ehookabove: "1EBB", - eibopomofo: "311F", - eight: "0038", - eightarabic: "0668", - eightbengali: "09EE", - eightcircle: "2467", - eightcircleinversesansserif: "2791", - eightdeva: "096E", - eighteencircle: "2471", - eighteenparen: "2485", - eighteenperiod: "2499", - eightgujarati: "0AEE", - eightgurmukhi: "0A6E", - eighthackarabic: "0668", - eighthangzhou: "3028", - eighthnotebeamed: "266B", - eightideographicparen: "3227", - eightinferior: "2088", - eightmonospace: "FF18", - eightoldstyle: "F738", - eightparen: "247B", - eightperiod: "248F", - eightpersian: "06F8", - eightroman: "2177", - eightsuperior: "2078", - eightthai: "0E58", - einvertedbreve: "0207", - eiotifiedcyrillic: "0465", - ekatakana: "30A8", - ekatakanahalfwidth: "FF74", - ekonkargurmukhi: "0A74", - ekorean: "3154", - elcyrillic: "043B", - element: "2208", - elevencircle: "246A", - elevenparen: "247E", - elevenperiod: "2492", - elevenroman: "217A", - ellipsis: "2026", - ellipsisvertical: "22EE", - emacron: "0113", - emacronacute: "1E17", - emacrongrave: "1E15", - emcyrillic: "043C", - emdash: "2014", - emdashvertical: "FE31", - emonospace: "FF45", - emphasismarkarmenian: "055B", - emptyset: "2205", - enbopomofo: "3123", - encyrillic: "043D", - endash: "2013", - endashvertical: "FE32", - endescendercyrillic: "04A3", - eng: "014B", - engbopomofo: "3125", - enghecyrillic: "04A5", - enhookcyrillic: "04C8", - enspace: "2002", - eogonek: "0119", - eokorean: "3153", - eopen: "025B", - eopenclosed: "029A", - eopenreversed: "025C", - eopenreversedclosed: "025E", - eopenreversedhook: "025D", - eparen: "24A0", - epsilon: "03B5", - epsilontonos: "03AD", - equal: "003D", - equalmonospace: "FF1D", - equalsmall: "FE66", - equalsuperior: "207C", - equivalence: "2261", - erbopomofo: "3126", - ercyrillic: "0440", - ereversed: "0258", - ereversedcyrillic: "044D", - escyrillic: "0441", - esdescendercyrillic: "04AB", - esh: "0283", - eshcurl: "0286", - eshortdeva: "090E", - eshortvowelsigndeva: "0946", - eshreversedloop: "01AA", - eshsquatreversed: "0285", - esmallhiragana: "3047", - esmallkatakana: "30A7", - esmallkatakanahalfwidth: "FF6A", - estimated: "212E", - esuperior: "F6EC", - eta: "03B7", - etarmenian: "0568", - etatonos: "03AE", - eth: "00F0", - etilde: "1EBD", - etildebelow: "1E1B", - etnahtafoukhhebrew: "0591", - etnahtafoukhlefthebrew: "0591", - etnahtahebrew: "0591", - etnahtalefthebrew: "0591", - eturned: "01DD", - eukorean: "3161", - euro: "20AC", - evowelsignbengali: "09C7", - evowelsigndeva: "0947", - evowelsigngujarati: "0AC7", - exclam: "0021", - exclamarmenian: "055C", - exclamdbl: "203C", - exclamdown: "00A1", - exclamdownsmall: "F7A1", - exclammonospace: "FF01", - exclamsmall: "F721", - existential: "2203", - ezh: "0292", - ezhcaron: "01EF", - ezhcurl: "0293", - ezhreversed: "01B9", - ezhtail: "01BA", - f: "0066", - fadeva: "095E", - fagurmukhi: "0A5E", - fahrenheit: "2109", - fathaarabic: "064E", - fathalowarabic: "064E", - fathatanarabic: "064B", - fbopomofo: "3108", - fcircle: "24D5", - fdotaccent: "1E1F", - feharabic: "0641", - feharmenian: "0586", - fehfinalarabic: "FED2", - fehinitialarabic: "FED3", - fehmedialarabic: "FED4", - feicoptic: "03E5", - female: "2640", - ff: "FB00", - ffi: "FB03", - ffl: "FB04", - fi: "FB01", - fifteencircle: "246E", - fifteenparen: "2482", - fifteenperiod: "2496", - figuredash: "2012", - filledbox: "25A0", - filledrect: "25AC", - finalkaf: "05DA", - finalkafdagesh: "FB3A", - finalkafdageshhebrew: "FB3A", - finalkafhebrew: "05DA", + dalfinalarabic: 0xFEAA, + dammaarabic: 0x064F, + dammalowarabic: 0x064F, + dammatanaltonearabic: 0x064C, + dammatanarabic: 0x064C, + danda: 0x0964, + dargahebrew: 0x05A7, + dargalefthebrew: 0x05A7, + dasiapneumatacyrilliccmb: 0x0485, + dblGrave: 0xF6D3, + dblanglebracketleft: 0x300A, + dblanglebracketleftvertical: 0xFE3D, + dblanglebracketright: 0x300B, + dblanglebracketrightvertical: 0xFE3E, + dblarchinvertedbelowcmb: 0x032B, + dblarrowleft: 0x21D4, + dblarrowright: 0x21D2, + dbldanda: 0x0965, + dblgrave: 0xF6D6, + dblgravecmb: 0x030F, + dblintegral: 0x222C, + dbllowline: 0x2017, + dbllowlinecmb: 0x0333, + dbloverlinecmb: 0x033F, + dblprimemod: 0x02BA, + dblverticalbar: 0x2016, + dblverticallineabovecmb: 0x030E, + dbopomofo: 0x3109, + dbsquare: 0x33C8, + dcaron: 0x010F, + dcedilla: 0x1E11, + dcircle: 0x24D3, + dcircumflexbelow: 0x1E13, + dcroat: 0x0111, + ddabengali: 0x09A1, + ddadeva: 0x0921, + ddagujarati: 0x0AA1, + ddagurmukhi: 0x0A21, + ddalarabic: 0x0688, + ddalfinalarabic: 0xFB89, + dddhadeva: 0x095C, + ddhabengali: 0x09A2, + ddhadeva: 0x0922, + ddhagujarati: 0x0AA2, + ddhagurmukhi: 0x0A22, + ddotaccent: 0x1E0B, + ddotbelow: 0x1E0D, + decimalseparatorarabic: 0x066B, + decimalseparatorpersian: 0x066B, + decyrillic: 0x0434, + degree: 0x00B0, + dehihebrew: 0x05AD, + dehiragana: 0x3067, + deicoptic: 0x03EF, + dekatakana: 0x30C7, + deleteleft: 0x232B, + deleteright: 0x2326, + delta: 0x03B4, + deltaturned: 0x018D, + denominatorminusonenumeratorbengali: 0x09F8, + dezh: 0x02A4, + dhabengali: 0x09A7, + dhadeva: 0x0927, + dhagujarati: 0x0AA7, + dhagurmukhi: 0x0A27, + dhook: 0x0257, + dialytikatonos: 0x0385, + dialytikatonoscmb: 0x0344, + diamond: 0x2666, + diamondsuitwhite: 0x2662, + dieresis: 0x00A8, + dieresisacute: 0xF6D7, + dieresisbelowcmb: 0x0324, + dieresiscmb: 0x0308, + dieresisgrave: 0xF6D8, + dieresistonos: 0x0385, + dihiragana: 0x3062, + dikatakana: 0x30C2, + dittomark: 0x3003, + divide: 0x00F7, + divides: 0x2223, + divisionslash: 0x2215, + djecyrillic: 0x0452, + dkshade: 0x2593, + dlinebelow: 0x1E0F, + dlsquare: 0x3397, + dmacron: 0x0111, + dmonospace: 0xFF44, + dnblock: 0x2584, + dochadathai: 0x0E0E, + dodekthai: 0x0E14, + dohiragana: 0x3069, + dokatakana: 0x30C9, + dollar: 0x0024, + dollarinferior: 0xF6E3, + dollarmonospace: 0xFF04, + dollaroldstyle: 0xF724, + dollarsmall: 0xFE69, + dollarsuperior: 0xF6E4, + dong: 0x20AB, + dorusquare: 0x3326, + dotaccent: 0x02D9, + dotaccentcmb: 0x0307, + dotbelowcmb: 0x0323, + dotbelowcomb: 0x0323, + dotkatakana: 0x30FB, + dotlessi: 0x0131, + dotlessj: 0xF6BE, + dotlessjstrokehook: 0x0284, + dotmath: 0x22C5, + dottedcircle: 0x25CC, + doubleyodpatah: 0xFB1F, + doubleyodpatahhebrew: 0xFB1F, + downtackbelowcmb: 0x031E, + downtackmod: 0x02D5, + dparen: 0x249F, + dsuperior: 0xF6EB, + dtail: 0x0256, + dtopbar: 0x018C, + duhiragana: 0x3065, + dukatakana: 0x30C5, + dz: 0x01F3, + dzaltone: 0x02A3, + dzcaron: 0x01C6, + dzcurl: 0x02A5, + dzeabkhasiancyrillic: 0x04E1, + dzecyrillic: 0x0455, + dzhecyrillic: 0x045F, + e: 0x0065, + eacute: 0x00E9, + earth: 0x2641, + ebengali: 0x098F, + ebopomofo: 0x311C, + ebreve: 0x0115, + ecandradeva: 0x090D, + ecandragujarati: 0x0A8D, + ecandravowelsigndeva: 0x0945, + ecandravowelsigngujarati: 0x0AC5, + ecaron: 0x011B, + ecedillabreve: 0x1E1D, + echarmenian: 0x0565, + echyiwnarmenian: 0x0587, + ecircle: 0x24D4, + ecircumflex: 0x00EA, + ecircumflexacute: 0x1EBF, + ecircumflexbelow: 0x1E19, + ecircumflexdotbelow: 0x1EC7, + ecircumflexgrave: 0x1EC1, + ecircumflexhookabove: 0x1EC3, + ecircumflextilde: 0x1EC5, + ecyrillic: 0x0454, + edblgrave: 0x0205, + edeva: 0x090F, + edieresis: 0x00EB, + edot: 0x0117, + edotaccent: 0x0117, + edotbelow: 0x1EB9, + eegurmukhi: 0x0A0F, + eematragurmukhi: 0x0A47, + efcyrillic: 0x0444, + egrave: 0x00E8, + egujarati: 0x0A8F, + eharmenian: 0x0567, + ehbopomofo: 0x311D, + ehiragana: 0x3048, + ehookabove: 0x1EBB, + eibopomofo: 0x311F, + eight: 0x0038, + eightarabic: 0x0668, + eightbengali: 0x09EE, + eightcircle: 0x2467, + eightcircleinversesansserif: 0x2791, + eightdeva: 0x096E, + eighteencircle: 0x2471, + eighteenparen: 0x2485, + eighteenperiod: 0x2499, + eightgujarati: 0x0AEE, + eightgurmukhi: 0x0A6E, + eighthackarabic: 0x0668, + eighthangzhou: 0x3028, + eighthnotebeamed: 0x266B, + eightideographicparen: 0x3227, + eightinferior: 0x2088, + eightmonospace: 0xFF18, + eightoldstyle: 0xF738, + eightparen: 0x247B, + eightperiod: 0x248F, + eightpersian: 0x06F8, + eightroman: 0x2177, + eightsuperior: 0x2078, + eightthai: 0x0E58, + einvertedbreve: 0x0207, + eiotifiedcyrillic: 0x0465, + ekatakana: 0x30A8, + ekatakanahalfwidth: 0xFF74, + ekonkargurmukhi: 0x0A74, + ekorean: 0x3154, + elcyrillic: 0x043B, + element: 0x2208, + elevencircle: 0x246A, + elevenparen: 0x247E, + elevenperiod: 0x2492, + elevenroman: 0x217A, + ellipsis: 0x2026, + ellipsisvertical: 0x22EE, + emacron: 0x0113, + emacronacute: 0x1E17, + emacrongrave: 0x1E15, + emcyrillic: 0x043C, + emdash: 0x2014, + emdashvertical: 0xFE31, + emonospace: 0xFF45, + emphasismarkarmenian: 0x055B, + emptyset: 0x2205, + enbopomofo: 0x3123, + encyrillic: 0x043D, + endash: 0x2013, + endashvertical: 0xFE32, + endescendercyrillic: 0x04A3, + eng: 0x014B, + engbopomofo: 0x3125, + enghecyrillic: 0x04A5, + enhookcyrillic: 0x04C8, + enspace: 0x2002, + eogonek: 0x0119, + eokorean: 0x3153, + eopen: 0x025B, + eopenclosed: 0x029A, + eopenreversed: 0x025C, + eopenreversedclosed: 0x025E, + eopenreversedhook: 0x025D, + eparen: 0x24A0, + epsilon: 0x03B5, + epsilontonos: 0x03AD, + equal: 0x003D, + equalmonospace: 0xFF1D, + equalsmall: 0xFE66, + equalsuperior: 0x207C, + equivalence: 0x2261, + erbopomofo: 0x3126, + ercyrillic: 0x0440, + ereversed: 0x0258, + ereversedcyrillic: 0x044D, + escyrillic: 0x0441, + esdescendercyrillic: 0x04AB, + esh: 0x0283, + eshcurl: 0x0286, + eshortdeva: 0x090E, + eshortvowelsigndeva: 0x0946, + eshreversedloop: 0x01AA, + eshsquatreversed: 0x0285, + esmallhiragana: 0x3047, + esmallkatakana: 0x30A7, + esmallkatakanahalfwidth: 0xFF6A, + estimated: 0x212E, + esuperior: 0xF6EC, + eta: 0x03B7, + etarmenian: 0x0568, + etatonos: 0x03AE, + eth: 0x00F0, + etilde: 0x1EBD, + etildebelow: 0x1E1B, + etnahtafoukhhebrew: 0x0591, + etnahtafoukhlefthebrew: 0x0591, + etnahtahebrew: 0x0591, + etnahtalefthebrew: 0x0591, + eturned: 0x01DD, + eukorean: 0x3161, + euro: 0x20AC, + evowelsignbengali: 0x09C7, + evowelsigndeva: 0x0947, + evowelsigngujarati: 0x0AC7, + exclam: 0x0021, + exclamarmenian: 0x055C, + exclamdbl: 0x203C, + exclamdown: 0x00A1, + exclamdownsmall: 0xF7A1, + exclammonospace: 0xFF01, + exclamsmall: 0xF721, + existential: 0x2203, + ezh: 0x0292, + ezhcaron: 0x01EF, + ezhcurl: 0x0293, + ezhreversed: 0x01B9, + ezhtail: 0x01BA, + f: 0x0066, + fadeva: 0x095E, + fagurmukhi: 0x0A5E, + fahrenheit: 0x2109, + fathaarabic: 0x064E, + fathalowarabic: 0x064E, + fathatanarabic: 0x064B, + fbopomofo: 0x3108, + fcircle: 0x24D5, + fdotaccent: 0x1E1F, + feharabic: 0x0641, + feharmenian: 0x0586, + fehfinalarabic: 0xFED2, + fehinitialarabic: 0xFED3, + fehmedialarabic: 0xFED4, + feicoptic: 0x03E5, + female: 0x2640, + ff: 0xFB00, + ffi: 0xFB03, + ffl: 0xFB04, + fi: 0xFB01, + fifteencircle: 0x246E, + fifteenparen: 0x2482, + fifteenperiod: 0x2496, + figuredash: 0x2012, + filledbox: 0x25A0, + filledrect: 0x25AC, + finalkaf: 0x05DA, + finalkafdagesh: 0xFB3A, + finalkafdageshhebrew: 0xFB3A, + finalkafhebrew: 0x05DA, finalkafqamats: "05DA 05B8", finalkafqamatshebrew: "05DA 05B8", finalkafsheva: "05DA 05B0", finalkafshevahebrew: "05DA 05B0", - finalmem: "05DD", - finalmemhebrew: "05DD", - finalnun: "05DF", - finalnunhebrew: "05DF", - finalpe: "05E3", - finalpehebrew: "05E3", - finaltsadi: "05E5", - finaltsadihebrew: "05E5", - firsttonechinese: "02C9", - fisheye: "25C9", - fitacyrillic: "0473", - five: "0035", - fivearabic: "0665", - fivebengali: "09EB", - fivecircle: "2464", - fivecircleinversesansserif: "278E", - fivedeva: "096B", - fiveeighths: "215D", - fivegujarati: "0AEB", - fivegurmukhi: "0A6B", - fivehackarabic: "0665", - fivehangzhou: "3025", - fiveideographicparen: "3224", - fiveinferior: "2085", - fivemonospace: "FF15", - fiveoldstyle: "F735", - fiveparen: "2478", - fiveperiod: "248C", - fivepersian: "06F5", - fiveroman: "2174", - fivesuperior: "2075", - fivethai: "0E55", - fl: "FB02", - florin: "0192", - fmonospace: "FF46", - fmsquare: "3399", - fofanthai: "0E1F", - fofathai: "0E1D", - fongmanthai: "0E4F", - forall: "2200", - four: "0034", - fourarabic: "0664", - fourbengali: "09EA", - fourcircle: "2463", - fourcircleinversesansserif: "278D", - fourdeva: "096A", - fourgujarati: "0AEA", - fourgurmukhi: "0A6A", - fourhackarabic: "0664", - fourhangzhou: "3024", - fourideographicparen: "3223", - fourinferior: "2084", - fourmonospace: "FF14", - fournumeratorbengali: "09F7", - fouroldstyle: "F734", - fourparen: "2477", - fourperiod: "248B", - fourpersian: "06F4", - fourroman: "2173", - foursuperior: "2074", - fourteencircle: "246D", - fourteenparen: "2481", - fourteenperiod: "2495", - fourthai: "0E54", - fourthtonechinese: "02CB", - fparen: "24A1", - fraction: "2044", - franc: "20A3", - g: "0067", - gabengali: "0997", - gacute: "01F5", - gadeva: "0917", - gafarabic: "06AF", - gaffinalarabic: "FB93", - gafinitialarabic: "FB94", - gafmedialarabic: "FB95", - gagujarati: "0A97", - gagurmukhi: "0A17", - gahiragana: "304C", - gakatakana: "30AC", - gamma: "03B3", - gammalatinsmall: "0263", - gammasuperior: "02E0", - gangiacoptic: "03EB", - gbopomofo: "310D", - gbreve: "011F", - gcaron: "01E7", - gcedilla: "0123", - gcircle: "24D6", - gcircumflex: "011D", - gcommaaccent: "0123", - gdot: "0121", - gdotaccent: "0121", - gecyrillic: "0433", - gehiragana: "3052", - gekatakana: "30B2", - geometricallyequal: "2251", - gereshaccenthebrew: "059C", - gereshhebrew: "05F3", - gereshmuqdamhebrew: "059D", - germandbls: "00DF", - gershayimaccenthebrew: "059E", - gershayimhebrew: "05F4", - getamark: "3013", - ghabengali: "0998", - ghadarmenian: "0572", - ghadeva: "0918", - ghagujarati: "0A98", - ghagurmukhi: "0A18", - ghainarabic: "063A", - ghainfinalarabic: "FECE", - ghaininitialarabic: "FECF", - ghainmedialarabic: "FED0", - ghemiddlehookcyrillic: "0495", - ghestrokecyrillic: "0493", - gheupturncyrillic: "0491", - ghhadeva: "095A", - ghhagurmukhi: "0A5A", - ghook: "0260", - ghzsquare: "3393", - gihiragana: "304E", - gikatakana: "30AE", - gimarmenian: "0563", - gimel: "05D2", - gimeldagesh: "FB32", - gimeldageshhebrew: "FB32", - gimelhebrew: "05D2", - gjecyrillic: "0453", - glottalinvertedstroke: "01BE", - glottalstop: "0294", - glottalstopinverted: "0296", - glottalstopmod: "02C0", - glottalstopreversed: "0295", - glottalstopreversedmod: "02C1", - glottalstopreversedsuperior: "02E4", - glottalstopstroke: "02A1", - glottalstopstrokereversed: "02A2", - gmacron: "1E21", - gmonospace: "FF47", - gohiragana: "3054", - gokatakana: "30B4", - gparen: "24A2", - gpasquare: "33AC", - gradient: "2207", - grave: "0060", - gravebelowcmb: "0316", - gravecmb: "0300", - gravecomb: "0300", - gravedeva: "0953", - gravelowmod: "02CE", - gravemonospace: "FF40", - gravetonecmb: "0340", - greater: "003E", - greaterequal: "2265", - greaterequalorless: "22DB", - greatermonospace: "FF1E", - greaterorequivalent: "2273", - greaterorless: "2277", - greateroverequal: "2267", - greatersmall: "FE65", - gscript: "0261", - gstroke: "01E5", - guhiragana: "3050", - guillemotleft: "00AB", - guillemotright: "00BB", - guilsinglleft: "2039", - guilsinglright: "203A", - gukatakana: "30B0", - guramusquare: "3318", - gysquare: "33C9", - h: "0068", - haabkhasiancyrillic: "04A9", - haaltonearabic: "06C1", - habengali: "09B9", - hadescendercyrillic: "04B3", - hadeva: "0939", - hagujarati: "0AB9", - hagurmukhi: "0A39", - haharabic: "062D", - hahfinalarabic: "FEA2", - hahinitialarabic: "FEA3", - hahiragana: "306F", - hahmedialarabic: "FEA4", - haitusquare: "332A", - hakatakana: "30CF", - hakatakanahalfwidth: "FF8A", - halantgurmukhi: "0A4D", - hamzaarabic: "0621", + finalmem: 0x05DD, + finalmemhebrew: 0x05DD, + finalnun: 0x05DF, + finalnunhebrew: 0x05DF, + finalpe: 0x05E3, + finalpehebrew: 0x05E3, + finaltsadi: 0x05E5, + finaltsadihebrew: 0x05E5, + firsttonechinese: 0x02C9, + fisheye: 0x25C9, + fitacyrillic: 0x0473, + five: 0x0035, + fivearabic: 0x0665, + fivebengali: 0x09EB, + fivecircle: 0x2464, + fivecircleinversesansserif: 0x278E, + fivedeva: 0x096B, + fiveeighths: 0x215D, + fivegujarati: 0x0AEB, + fivegurmukhi: 0x0A6B, + fivehackarabic: 0x0665, + fivehangzhou: 0x3025, + fiveideographicparen: 0x3224, + fiveinferior: 0x2085, + fivemonospace: 0xFF15, + fiveoldstyle: 0xF735, + fiveparen: 0x2478, + fiveperiod: 0x248C, + fivepersian: 0x06F5, + fiveroman: 0x2174, + fivesuperior: 0x2075, + fivethai: 0x0E55, + fl: 0xFB02, + florin: 0x0192, + fmonospace: 0xFF46, + fmsquare: 0x3399, + fofanthai: 0x0E1F, + fofathai: 0x0E1D, + fongmanthai: 0x0E4F, + forall: 0x2200, + four: 0x0034, + fourarabic: 0x0664, + fourbengali: 0x09EA, + fourcircle: 0x2463, + fourcircleinversesansserif: 0x278D, + fourdeva: 0x096A, + fourgujarati: 0x0AEA, + fourgurmukhi: 0x0A6A, + fourhackarabic: 0x0664, + fourhangzhou: 0x3024, + fourideographicparen: 0x3223, + fourinferior: 0x2084, + fourmonospace: 0xFF14, + fournumeratorbengali: 0x09F7, + fouroldstyle: 0xF734, + fourparen: 0x2477, + fourperiod: 0x248B, + fourpersian: 0x06F4, + fourroman: 0x2173, + foursuperior: 0x2074, + fourteencircle: 0x246D, + fourteenparen: 0x2481, + fourteenperiod: 0x2495, + fourthai: 0x0E54, + fourthtonechinese: 0x02CB, + fparen: 0x24A1, + fraction: 0x2044, + franc: 0x20A3, + g: 0x0067, + gabengali: 0x0997, + gacute: 0x01F5, + gadeva: 0x0917, + gafarabic: 0x06AF, + gaffinalarabic: 0xFB93, + gafinitialarabic: 0xFB94, + gafmedialarabic: 0xFB95, + gagujarati: 0x0A97, + gagurmukhi: 0x0A17, + gahiragana: 0x304C, + gakatakana: 0x30AC, + gamma: 0x03B3, + gammalatinsmall: 0x0263, + gammasuperior: 0x02E0, + gangiacoptic: 0x03EB, + gbopomofo: 0x310D, + gbreve: 0x011F, + gcaron: 0x01E7, + gcedilla: 0x0123, + gcircle: 0x24D6, + gcircumflex: 0x011D, + gcommaaccent: 0x0123, + gdot: 0x0121, + gdotaccent: 0x0121, + gecyrillic: 0x0433, + gehiragana: 0x3052, + gekatakana: 0x30B2, + geometricallyequal: 0x2251, + gereshaccenthebrew: 0x059C, + gereshhebrew: 0x05F3, + gereshmuqdamhebrew: 0x059D, + germandbls: 0x00DF, + gershayimaccenthebrew: 0x059E, + gershayimhebrew: 0x05F4, + getamark: 0x3013, + ghabengali: 0x0998, + ghadarmenian: 0x0572, + ghadeva: 0x0918, + ghagujarati: 0x0A98, + ghagurmukhi: 0x0A18, + ghainarabic: 0x063A, + ghainfinalarabic: 0xFECE, + ghaininitialarabic: 0xFECF, + ghainmedialarabic: 0xFED0, + ghemiddlehookcyrillic: 0x0495, + ghestrokecyrillic: 0x0493, + gheupturncyrillic: 0x0491, + ghhadeva: 0x095A, + ghhagurmukhi: 0x0A5A, + ghook: 0x0260, + ghzsquare: 0x3393, + gihiragana: 0x304E, + gikatakana: 0x30AE, + gimarmenian: 0x0563, + gimel: 0x05D2, + gimeldagesh: 0xFB32, + gimeldageshhebrew: 0xFB32, + gimelhebrew: 0x05D2, + gjecyrillic: 0x0453, + glottalinvertedstroke: 0x01BE, + glottalstop: 0x0294, + glottalstopinverted: 0x0296, + glottalstopmod: 0x02C0, + glottalstopreversed: 0x0295, + glottalstopreversedmod: 0x02C1, + glottalstopreversedsuperior: 0x02E4, + glottalstopstroke: 0x02A1, + glottalstopstrokereversed: 0x02A2, + gmacron: 0x1E21, + gmonospace: 0xFF47, + gohiragana: 0x3054, + gokatakana: 0x30B4, + gparen: 0x24A2, + gpasquare: 0x33AC, + gradient: 0x2207, + grave: 0x0060, + gravebelowcmb: 0x0316, + gravecmb: 0x0300, + gravecomb: 0x0300, + gravedeva: 0x0953, + gravelowmod: 0x02CE, + gravemonospace: 0xFF40, + gravetonecmb: 0x0340, + greater: 0x003E, + greaterequal: 0x2265, + greaterequalorless: 0x22DB, + greatermonospace: 0xFF1E, + greaterorequivalent: 0x2273, + greaterorless: 0x2277, + greateroverequal: 0x2267, + greatersmall: 0xFE65, + gscript: 0x0261, + gstroke: 0x01E5, + guhiragana: 0x3050, + guillemotleft: 0x00AB, + guillemotright: 0x00BB, + guilsinglleft: 0x2039, + guilsinglright: 0x203A, + gukatakana: 0x30B0, + guramusquare: 0x3318, + gysquare: 0x33C9, + h: 0x0068, + haabkhasiancyrillic: 0x04A9, + haaltonearabic: 0x06C1, + habengali: 0x09B9, + hadescendercyrillic: 0x04B3, + hadeva: 0x0939, + hagujarati: 0x0AB9, + hagurmukhi: 0x0A39, + haharabic: 0x062D, + hahfinalarabic: 0xFEA2, + hahinitialarabic: 0xFEA3, + hahiragana: 0x306F, + hahmedialarabic: 0xFEA4, + haitusquare: 0x332A, + hakatakana: 0x30CF, + hakatakanahalfwidth: 0xFF8A, + halantgurmukhi: 0x0A4D, + hamzaarabic: 0x0621, hamzadammaarabic: "0621 064F", hamzadammatanarabic: "0621 064C", hamzafathaarabic: "0621 064E", hamzafathatanarabic: "0621 064B", - hamzalowarabic: "0621", + hamzalowarabic: 0x0621, hamzalowkasraarabic: "0621 0650", hamzalowkasratanarabic: "0621 064D", hamzasukunarabic: "0621 0652", - hangulfiller: "3164", - hardsigncyrillic: "044A", - harpoonleftbarbup: "21BC", - harpoonrightbarbup: "21C0", - hasquare: "33CA", - hatafpatah: "05B2", - hatafpatah16: "05B2", - hatafpatah23: "05B2", - hatafpatah2f: "05B2", - hatafpatahhebrew: "05B2", - hatafpatahnarrowhebrew: "05B2", - hatafpatahquarterhebrew: "05B2", - hatafpatahwidehebrew: "05B2", - hatafqamats: "05B3", - hatafqamats1b: "05B3", - hatafqamats28: "05B3", - hatafqamats34: "05B3", - hatafqamatshebrew: "05B3", - hatafqamatsnarrowhebrew: "05B3", - hatafqamatsquarterhebrew: "05B3", - hatafqamatswidehebrew: "05B3", - hatafsegol: "05B1", - hatafsegol17: "05B1", - hatafsegol24: "05B1", - hatafsegol30: "05B1", - hatafsegolhebrew: "05B1", - hatafsegolnarrowhebrew: "05B1", - hatafsegolquarterhebrew: "05B1", - hatafsegolwidehebrew: "05B1", - hbar: "0127", - hbopomofo: "310F", - hbrevebelow: "1E2B", - hcedilla: "1E29", - hcircle: "24D7", - hcircumflex: "0125", - hdieresis: "1E27", - hdotaccent: "1E23", - hdotbelow: "1E25", - he: "05D4", - heart: "2665", - heartsuitblack: "2665", - heartsuitwhite: "2661", - hedagesh: "FB34", - hedageshhebrew: "FB34", - hehaltonearabic: "06C1", - heharabic: "0647", - hehebrew: "05D4", - hehfinalaltonearabic: "FBA7", - hehfinalalttwoarabic: "FEEA", - hehfinalarabic: "FEEA", - hehhamzaabovefinalarabic: "FBA5", - hehhamzaaboveisolatedarabic: "FBA4", - hehinitialaltonearabic: "FBA8", - hehinitialarabic: "FEEB", - hehiragana: "3078", - hehmedialaltonearabic: "FBA9", - hehmedialarabic: "FEEC", - heiseierasquare: "337B", - hekatakana: "30D8", - hekatakanahalfwidth: "FF8D", - hekutaarusquare: "3336", - henghook: "0267", - herutusquare: "3339", - het: "05D7", - hethebrew: "05D7", - hhook: "0266", - hhooksuperior: "02B1", - hieuhacirclekorean: "327B", - hieuhaparenkorean: "321B", - hieuhcirclekorean: "326D", - hieuhkorean: "314E", - hieuhparenkorean: "320D", - hihiragana: "3072", - hikatakana: "30D2", - hikatakanahalfwidth: "FF8B", - hiriq: "05B4", - hiriq14: "05B4", - hiriq21: "05B4", - hiriq2d: "05B4", - hiriqhebrew: "05B4", - hiriqnarrowhebrew: "05B4", - hiriqquarterhebrew: "05B4", - hiriqwidehebrew: "05B4", - hlinebelow: "1E96", - hmonospace: "FF48", - hoarmenian: "0570", - hohipthai: "0E2B", - hohiragana: "307B", - hokatakana: "30DB", - hokatakanahalfwidth: "FF8E", - holam: "05B9", - holam19: "05B9", - holam26: "05B9", - holam32: "05B9", - holamhebrew: "05B9", - holamnarrowhebrew: "05B9", - holamquarterhebrew: "05B9", - holamwidehebrew: "05B9", - honokhukthai: "0E2E", - hookabovecomb: "0309", - hookcmb: "0309", - hookpalatalizedbelowcmb: "0321", - hookretroflexbelowcmb: "0322", - hoonsquare: "3342", - horicoptic: "03E9", - horizontalbar: "2015", - horncmb: "031B", - hotsprings: "2668", - house: "2302", - hparen: "24A3", - hsuperior: "02B0", - hturned: "0265", - huhiragana: "3075", - huiitosquare: "3333", - hukatakana: "30D5", - hukatakanahalfwidth: "FF8C", - hungarumlaut: "02DD", - hungarumlautcmb: "030B", - hv: "0195", - hyphen: "002D", - hypheninferior: "F6E5", - hyphenmonospace: "FF0D", - hyphensmall: "FE63", - hyphensuperior: "F6E6", - hyphentwo: "2010", - i: "0069", - iacute: "00ED", - iacyrillic: "044F", - ibengali: "0987", - ibopomofo: "3127", - ibreve: "012D", - icaron: "01D0", - icircle: "24D8", - icircumflex: "00EE", - icyrillic: "0456", - idblgrave: "0209", - ideographearthcircle: "328F", - ideographfirecircle: "328B", - ideographicallianceparen: "323F", - ideographiccallparen: "323A", - ideographiccentrecircle: "32A5", - ideographicclose: "3006", - ideographiccomma: "3001", - ideographiccommaleft: "FF64", - ideographiccongratulationparen: "3237", - ideographiccorrectcircle: "32A3", - ideographicearthparen: "322F", - ideographicenterpriseparen: "323D", - ideographicexcellentcircle: "329D", - ideographicfestivalparen: "3240", - ideographicfinancialcircle: "3296", - ideographicfinancialparen: "3236", - ideographicfireparen: "322B", - ideographichaveparen: "3232", - ideographichighcircle: "32A4", - ideographiciterationmark: "3005", - ideographiclaborcircle: "3298", - ideographiclaborparen: "3238", - ideographicleftcircle: "32A7", - ideographiclowcircle: "32A6", - ideographicmedicinecircle: "32A9", - ideographicmetalparen: "322E", - ideographicmoonparen: "322A", - ideographicnameparen: "3234", - ideographicperiod: "3002", - ideographicprintcircle: "329E", - ideographicreachparen: "3243", - ideographicrepresentparen: "3239", - ideographicresourceparen: "323E", - ideographicrightcircle: "32A8", - ideographicsecretcircle: "3299", - ideographicselfparen: "3242", - ideographicsocietyparen: "3233", - ideographicspace: "3000", - ideographicspecialparen: "3235", - ideographicstockparen: "3231", - ideographicstudyparen: "323B", - ideographicsunparen: "3230", - ideographicsuperviseparen: "323C", - ideographicwaterparen: "322C", - ideographicwoodparen: "322D", - ideographiczero: "3007", - ideographmetalcircle: "328E", - ideographmooncircle: "328A", - ideographnamecircle: "3294", - ideographsuncircle: "3290", - ideographwatercircle: "328C", - ideographwoodcircle: "328D", - ideva: "0907", - idieresis: "00EF", - idieresisacute: "1E2F", - idieresiscyrillic: "04E5", - idotbelow: "1ECB", - iebrevecyrillic: "04D7", - iecyrillic: "0435", - ieungacirclekorean: "3275", - ieungaparenkorean: "3215", - ieungcirclekorean: "3267", - ieungkorean: "3147", - ieungparenkorean: "3207", - igrave: "00EC", - igujarati: "0A87", - igurmukhi: "0A07", - ihiragana: "3044", - ihookabove: "1EC9", - iibengali: "0988", - iicyrillic: "0438", - iideva: "0908", - iigujarati: "0A88", - iigurmukhi: "0A08", - iimatragurmukhi: "0A40", - iinvertedbreve: "020B", - iishortcyrillic: "0439", - iivowelsignbengali: "09C0", - iivowelsigndeva: "0940", - iivowelsigngujarati: "0AC0", - ij: "0133", - ikatakana: "30A4", - ikatakanahalfwidth: "FF72", - ikorean: "3163", - ilde: "02DC", - iluyhebrew: "05AC", - imacron: "012B", - imacroncyrillic: "04E3", - imageorapproximatelyequal: "2253", - imatragurmukhi: "0A3F", - imonospace: "FF49", - increment: "2206", - infinity: "221E", - iniarmenian: "056B", - integral: "222B", - integralbottom: "2321", - integralbt: "2321", - integralex: "F8F5", - integraltop: "2320", - integraltp: "2320", - intersection: "2229", - intisquare: "3305", - invbullet: "25D8", - invcircle: "25D9", - invsmileface: "263B", - iocyrillic: "0451", - iogonek: "012F", - iota: "03B9", - iotadieresis: "03CA", - iotadieresistonos: "0390", - iotalatin: "0269", - iotatonos: "03AF", - iparen: "24A4", - irigurmukhi: "0A72", - ismallhiragana: "3043", - ismallkatakana: "30A3", - ismallkatakanahalfwidth: "FF68", - issharbengali: "09FA", - istroke: "0268", - isuperior: "F6ED", - iterationhiragana: "309D", - iterationkatakana: "30FD", - itilde: "0129", - itildebelow: "1E2D", - iubopomofo: "3129", - iucyrillic: "044E", - ivowelsignbengali: "09BF", - ivowelsigndeva: "093F", - ivowelsigngujarati: "0ABF", - izhitsacyrillic: "0475", - izhitsadblgravecyrillic: "0477", - j: "006A", - jaarmenian: "0571", - jabengali: "099C", - jadeva: "091C", - jagujarati: "0A9C", - jagurmukhi: "0A1C", - jbopomofo: "3110", - jcaron: "01F0", - jcircle: "24D9", - jcircumflex: "0135", - jcrossedtail: "029D", - jdotlessstroke: "025F", - jecyrillic: "0458", - jeemarabic: "062C", - jeemfinalarabic: "FE9E", - jeeminitialarabic: "FE9F", - jeemmedialarabic: "FEA0", - jeharabic: "0698", - jehfinalarabic: "FB8B", - jhabengali: "099D", - jhadeva: "091D", - jhagujarati: "0A9D", - jhagurmukhi: "0A1D", - jheharmenian: "057B", - jis: "3004", - jmonospace: "FF4A", - jparen: "24A5", - jsuperior: "02B2", - k: "006B", - kabashkircyrillic: "04A1", - kabengali: "0995", - kacute: "1E31", - kacyrillic: "043A", - kadescendercyrillic: "049B", - kadeva: "0915", - kaf: "05DB", - kafarabic: "0643", - kafdagesh: "FB3B", - kafdageshhebrew: "FB3B", - kaffinalarabic: "FEDA", - kafhebrew: "05DB", - kafinitialarabic: "FEDB", - kafmedialarabic: "FEDC", - kafrafehebrew: "FB4D", - kagujarati: "0A95", - kagurmukhi: "0A15", - kahiragana: "304B", - kahookcyrillic: "04C4", - kakatakana: "30AB", - kakatakanahalfwidth: "FF76", - kappa: "03BA", - kappasymbolgreek: "03F0", - kapyeounmieumkorean: "3171", - kapyeounphieuphkorean: "3184", - kapyeounpieupkorean: "3178", - kapyeounssangpieupkorean: "3179", - karoriisquare: "330D", - kashidaautoarabic: "0640", - kashidaautonosidebearingarabic: "0640", - kasmallkatakana: "30F5", - kasquare: "3384", - kasraarabic: "0650", - kasratanarabic: "064D", - kastrokecyrillic: "049F", - katahiraprolongmarkhalfwidth: "FF70", - kaverticalstrokecyrillic: "049D", - kbopomofo: "310E", - kcalsquare: "3389", - kcaron: "01E9", - kcedilla: "0137", - kcircle: "24DA", - kcommaaccent: "0137", - kdotbelow: "1E33", - keharmenian: "0584", - kehiragana: "3051", - kekatakana: "30B1", - kekatakanahalfwidth: "FF79", - kenarmenian: "056F", - kesmallkatakana: "30F6", - kgreenlandic: "0138", - khabengali: "0996", - khacyrillic: "0445", - khadeva: "0916", - khagujarati: "0A96", - khagurmukhi: "0A16", - khaharabic: "062E", - khahfinalarabic: "FEA6", - khahinitialarabic: "FEA7", - khahmedialarabic: "FEA8", - kheicoptic: "03E7", - khhadeva: "0959", - khhagurmukhi: "0A59", - khieukhacirclekorean: "3278", - khieukhaparenkorean: "3218", - khieukhcirclekorean: "326A", - khieukhkorean: "314B", - khieukhparenkorean: "320A", - khokhaithai: "0E02", - khokhonthai: "0E05", - khokhuatthai: "0E03", - khokhwaithai: "0E04", - khomutthai: "0E5B", - khook: "0199", - khorakhangthai: "0E06", - khzsquare: "3391", - kihiragana: "304D", - kikatakana: "30AD", - kikatakanahalfwidth: "FF77", - kiroguramusquare: "3315", - kiromeetorusquare: "3316", - kirosquare: "3314", - kiyeokacirclekorean: "326E", - kiyeokaparenkorean: "320E", - kiyeokcirclekorean: "3260", - kiyeokkorean: "3131", - kiyeokparenkorean: "3200", - kiyeoksioskorean: "3133", - kjecyrillic: "045C", - klinebelow: "1E35", - klsquare: "3398", - kmcubedsquare: "33A6", - kmonospace: "FF4B", - kmsquaredsquare: "33A2", - kohiragana: "3053", - kohmsquare: "33C0", - kokaithai: "0E01", - kokatakana: "30B3", - kokatakanahalfwidth: "FF7A", - kooposquare: "331E", - koppacyrillic: "0481", - koreanstandardsymbol: "327F", - koroniscmb: "0343", - kparen: "24A6", - kpasquare: "33AA", - ksicyrillic: "046F", - ktsquare: "33CF", - kturned: "029E", - kuhiragana: "304F", - kukatakana: "30AF", - kukatakanahalfwidth: "FF78", - kvsquare: "33B8", - kwsquare: "33BE", - l: "006C", - labengali: "09B2", - lacute: "013A", - ladeva: "0932", - lagujarati: "0AB2", - lagurmukhi: "0A32", - lakkhangyaothai: "0E45", - lamaleffinalarabic: "FEFC", - lamalefhamzaabovefinalarabic: "FEF8", - lamalefhamzaaboveisolatedarabic: "FEF7", - lamalefhamzabelowfinalarabic: "FEFA", - lamalefhamzabelowisolatedarabic: "FEF9", - lamalefisolatedarabic: "FEFB", - lamalefmaddaabovefinalarabic: "FEF6", - lamalefmaddaaboveisolatedarabic: "FEF5", - lamarabic: "0644", - lambda: "03BB", - lambdastroke: "019B", - lamed: "05DC", - lameddagesh: "FB3C", - lameddageshhebrew: "FB3C", - lamedhebrew: "05DC", + hangulfiller: 0x3164, + hardsigncyrillic: 0x044A, + harpoonleftbarbup: 0x21BC, + harpoonrightbarbup: 0x21C0, + hasquare: 0x33CA, + hatafpatah: 0x05B2, + hatafpatah16: 0x05B2, + hatafpatah23: 0x05B2, + hatafpatah2f: 0x05B2, + hatafpatahhebrew: 0x05B2, + hatafpatahnarrowhebrew: 0x05B2, + hatafpatahquarterhebrew: 0x05B2, + hatafpatahwidehebrew: 0x05B2, + hatafqamats: 0x05B3, + hatafqamats1b: 0x05B3, + hatafqamats28: 0x05B3, + hatafqamats34: 0x05B3, + hatafqamatshebrew: 0x05B3, + hatafqamatsnarrowhebrew: 0x05B3, + hatafqamatsquarterhebrew: 0x05B3, + hatafqamatswidehebrew: 0x05B3, + hatafsegol: 0x05B1, + hatafsegol17: 0x05B1, + hatafsegol24: 0x05B1, + hatafsegol30: 0x05B1, + hatafsegolhebrew: 0x05B1, + hatafsegolnarrowhebrew: 0x05B1, + hatafsegolquarterhebrew: 0x05B1, + hatafsegolwidehebrew: 0x05B1, + hbar: 0x0127, + hbopomofo: 0x310F, + hbrevebelow: 0x1E2B, + hcedilla: 0x1E29, + hcircle: 0x24D7, + hcircumflex: 0x0125, + hdieresis: 0x1E27, + hdotaccent: 0x1E23, + hdotbelow: 0x1E25, + he: 0x05D4, + heart: 0x2665, + heartsuitblack: 0x2665, + heartsuitwhite: 0x2661, + hedagesh: 0xFB34, + hedageshhebrew: 0xFB34, + hehaltonearabic: 0x06C1, + heharabic: 0x0647, + hehebrew: 0x05D4, + hehfinalaltonearabic: 0xFBA7, + hehfinalalttwoarabic: 0xFEEA, + hehfinalarabic: 0xFEEA, + hehhamzaabovefinalarabic: 0xFBA5, + hehhamzaaboveisolatedarabic: 0xFBA4, + hehinitialaltonearabic: 0xFBA8, + hehinitialarabic: 0xFEEB, + hehiragana: 0x3078, + hehmedialaltonearabic: 0xFBA9, + hehmedialarabic: 0xFEEC, + heiseierasquare: 0x337B, + hekatakana: 0x30D8, + hekatakanahalfwidth: 0xFF8D, + hekutaarusquare: 0x3336, + henghook: 0x0267, + herutusquare: 0x3339, + het: 0x05D7, + hethebrew: 0x05D7, + hhook: 0x0266, + hhooksuperior: 0x02B1, + hieuhacirclekorean: 0x327B, + hieuhaparenkorean: 0x321B, + hieuhcirclekorean: 0x326D, + hieuhkorean: 0x314E, + hieuhparenkorean: 0x320D, + hihiragana: 0x3072, + hikatakana: 0x30D2, + hikatakanahalfwidth: 0xFF8B, + hiriq: 0x05B4, + hiriq14: 0x05B4, + hiriq21: 0x05B4, + hiriq2d: 0x05B4, + hiriqhebrew: 0x05B4, + hiriqnarrowhebrew: 0x05B4, + hiriqquarterhebrew: 0x05B4, + hiriqwidehebrew: 0x05B4, + hlinebelow: 0x1E96, + hmonospace: 0xFF48, + hoarmenian: 0x0570, + hohipthai: 0x0E2B, + hohiragana: 0x307B, + hokatakana: 0x30DB, + hokatakanahalfwidth: 0xFF8E, + holam: 0x05B9, + holam19: 0x05B9, + holam26: 0x05B9, + holam32: 0x05B9, + holamhebrew: 0x05B9, + holamnarrowhebrew: 0x05B9, + holamquarterhebrew: 0x05B9, + holamwidehebrew: 0x05B9, + honokhukthai: 0x0E2E, + hookabovecomb: 0x0309, + hookcmb: 0x0309, + hookpalatalizedbelowcmb: 0x0321, + hookretroflexbelowcmb: 0x0322, + hoonsquare: 0x3342, + horicoptic: 0x03E9, + horizontalbar: 0x2015, + horncmb: 0x031B, + hotsprings: 0x2668, + house: 0x2302, + hparen: 0x24A3, + hsuperior: 0x02B0, + hturned: 0x0265, + huhiragana: 0x3075, + huiitosquare: 0x3333, + hukatakana: 0x30D5, + hukatakanahalfwidth: 0xFF8C, + hungarumlaut: 0x02DD, + hungarumlautcmb: 0x030B, + hv: 0x0195, + hyphen: 0x002D, + hypheninferior: 0xF6E5, + hyphenmonospace: 0xFF0D, + hyphensmall: 0xFE63, + hyphensuperior: 0xF6E6, + hyphentwo: 0x2010, + i: 0x0069, + iacute: 0x00ED, + iacyrillic: 0x044F, + ibengali: 0x0987, + ibopomofo: 0x3127, + ibreve: 0x012D, + icaron: 0x01D0, + icircle: 0x24D8, + icircumflex: 0x00EE, + icyrillic: 0x0456, + idblgrave: 0x0209, + ideographearthcircle: 0x328F, + ideographfirecircle: 0x328B, + ideographicallianceparen: 0x323F, + ideographiccallparen: 0x323A, + ideographiccentrecircle: 0x32A5, + ideographicclose: 0x3006, + ideographiccomma: 0x3001, + ideographiccommaleft: 0xFF64, + ideographiccongratulationparen: 0x3237, + ideographiccorrectcircle: 0x32A3, + ideographicearthparen: 0x322F, + ideographicenterpriseparen: 0x323D, + ideographicexcellentcircle: 0x329D, + ideographicfestivalparen: 0x3240, + ideographicfinancialcircle: 0x3296, + ideographicfinancialparen: 0x3236, + ideographicfireparen: 0x322B, + ideographichaveparen: 0x3232, + ideographichighcircle: 0x32A4, + ideographiciterationmark: 0x3005, + ideographiclaborcircle: 0x3298, + ideographiclaborparen: 0x3238, + ideographicleftcircle: 0x32A7, + ideographiclowcircle: 0x32A6, + ideographicmedicinecircle: 0x32A9, + ideographicmetalparen: 0x322E, + ideographicmoonparen: 0x322A, + ideographicnameparen: 0x3234, + ideographicperiod: 0x3002, + ideographicprintcircle: 0x329E, + ideographicreachparen: 0x3243, + ideographicrepresentparen: 0x3239, + ideographicresourceparen: 0x323E, + ideographicrightcircle: 0x32A8, + ideographicsecretcircle: 0x3299, + ideographicselfparen: 0x3242, + ideographicsocietyparen: 0x3233, + ideographicspace: 0x3000, + ideographicspecialparen: 0x3235, + ideographicstockparen: 0x3231, + ideographicstudyparen: 0x323B, + ideographicsunparen: 0x3230, + ideographicsuperviseparen: 0x323C, + ideographicwaterparen: 0x322C, + ideographicwoodparen: 0x322D, + ideographiczero: 0x3007, + ideographmetalcircle: 0x328E, + ideographmooncircle: 0x328A, + ideographnamecircle: 0x3294, + ideographsuncircle: 0x3290, + ideographwatercircle: 0x328C, + ideographwoodcircle: 0x328D, + ideva: 0x0907, + idieresis: 0x00EF, + idieresisacute: 0x1E2F, + idieresiscyrillic: 0x04E5, + idotbelow: 0x1ECB, + iebrevecyrillic: 0x04D7, + iecyrillic: 0x0435, + ieungacirclekorean: 0x3275, + ieungaparenkorean: 0x3215, + ieungcirclekorean: 0x3267, + ieungkorean: 0x3147, + ieungparenkorean: 0x3207, + igrave: 0x00EC, + igujarati: 0x0A87, + igurmukhi: 0x0A07, + ihiragana: 0x3044, + ihookabove: 0x1EC9, + iibengali: 0x0988, + iicyrillic: 0x0438, + iideva: 0x0908, + iigujarati: 0x0A88, + iigurmukhi: 0x0A08, + iimatragurmukhi: 0x0A40, + iinvertedbreve: 0x020B, + iishortcyrillic: 0x0439, + iivowelsignbengali: 0x09C0, + iivowelsigndeva: 0x0940, + iivowelsigngujarati: 0x0AC0, + ij: 0x0133, + ikatakana: 0x30A4, + ikatakanahalfwidth: 0xFF72, + ikorean: 0x3163, + ilde: 0x02DC, + iluyhebrew: 0x05AC, + imacron: 0x012B, + imacroncyrillic: 0x04E3, + imageorapproximatelyequal: 0x2253, + imatragurmukhi: 0x0A3F, + imonospace: 0xFF49, + increment: 0x2206, + infinity: 0x221E, + iniarmenian: 0x056B, + integral: 0x222B, + integralbottom: 0x2321, + integralbt: 0x2321, + integralex: 0xF8F5, + integraltop: 0x2320, + integraltp: 0x2320, + intersection: 0x2229, + intisquare: 0x3305, + invbullet: 0x25D8, + invcircle: 0x25D9, + invsmileface: 0x263B, + iocyrillic: 0x0451, + iogonek: 0x012F, + iota: 0x03B9, + iotadieresis: 0x03CA, + iotadieresistonos: 0x0390, + iotalatin: 0x0269, + iotatonos: 0x03AF, + iparen: 0x24A4, + irigurmukhi: 0x0A72, + ismallhiragana: 0x3043, + ismallkatakana: 0x30A3, + ismallkatakanahalfwidth: 0xFF68, + issharbengali: 0x09FA, + istroke: 0x0268, + isuperior: 0xF6ED, + iterationhiragana: 0x309D, + iterationkatakana: 0x30FD, + itilde: 0x0129, + itildebelow: 0x1E2D, + iubopomofo: 0x3129, + iucyrillic: 0x044E, + ivowelsignbengali: 0x09BF, + ivowelsigndeva: 0x093F, + ivowelsigngujarati: 0x0ABF, + izhitsacyrillic: 0x0475, + izhitsadblgravecyrillic: 0x0477, + j: 0x006A, + jaarmenian: 0x0571, + jabengali: 0x099C, + jadeva: 0x091C, + jagujarati: 0x0A9C, + jagurmukhi: 0x0A1C, + jbopomofo: 0x3110, + jcaron: 0x01F0, + jcircle: 0x24D9, + jcircumflex: 0x0135, + jcrossedtail: 0x029D, + jdotlessstroke: 0x025F, + jecyrillic: 0x0458, + jeemarabic: 0x062C, + jeemfinalarabic: 0xFE9E, + jeeminitialarabic: 0xFE9F, + jeemmedialarabic: 0xFEA0, + jeharabic: 0x0698, + jehfinalarabic: 0xFB8B, + jhabengali: 0x099D, + jhadeva: 0x091D, + jhagujarati: 0x0A9D, + jhagurmukhi: 0x0A1D, + jheharmenian: 0x057B, + jis: 0x3004, + jmonospace: 0xFF4A, + jparen: 0x24A5, + jsuperior: 0x02B2, + k: 0x006B, + kabashkircyrillic: 0x04A1, + kabengali: 0x0995, + kacute: 0x1E31, + kacyrillic: 0x043A, + kadescendercyrillic: 0x049B, + kadeva: 0x0915, + kaf: 0x05DB, + kafarabic: 0x0643, + kafdagesh: 0xFB3B, + kafdageshhebrew: 0xFB3B, + kaffinalarabic: 0xFEDA, + kafhebrew: 0x05DB, + kafinitialarabic: 0xFEDB, + kafmedialarabic: 0xFEDC, + kafrafehebrew: 0xFB4D, + kagujarati: 0x0A95, + kagurmukhi: 0x0A15, + kahiragana: 0x304B, + kahookcyrillic: 0x04C4, + kakatakana: 0x30AB, + kakatakanahalfwidth: 0xFF76, + kappa: 0x03BA, + kappasymbolgreek: 0x03F0, + kapyeounmieumkorean: 0x3171, + kapyeounphieuphkorean: 0x3184, + kapyeounpieupkorean: 0x3178, + kapyeounssangpieupkorean: 0x3179, + karoriisquare: 0x330D, + kashidaautoarabic: 0x0640, + kashidaautonosidebearingarabic: 0x0640, + kasmallkatakana: 0x30F5, + kasquare: 0x3384, + kasraarabic: 0x0650, + kasratanarabic: 0x064D, + kastrokecyrillic: 0x049F, + katahiraprolongmarkhalfwidth: 0xFF70, + kaverticalstrokecyrillic: 0x049D, + kbopomofo: 0x310E, + kcalsquare: 0x3389, + kcaron: 0x01E9, + kcedilla: 0x0137, + kcircle: 0x24DA, + kcommaaccent: 0x0137, + kdotbelow: 0x1E33, + keharmenian: 0x0584, + kehiragana: 0x3051, + kekatakana: 0x30B1, + kekatakanahalfwidth: 0xFF79, + kenarmenian: 0x056F, + kesmallkatakana: 0x30F6, + kgreenlandic: 0x0138, + khabengali: 0x0996, + khacyrillic: 0x0445, + khadeva: 0x0916, + khagujarati: 0x0A96, + khagurmukhi: 0x0A16, + khaharabic: 0x062E, + khahfinalarabic: 0xFEA6, + khahinitialarabic: 0xFEA7, + khahmedialarabic: 0xFEA8, + kheicoptic: 0x03E7, + khhadeva: 0x0959, + khhagurmukhi: 0x0A59, + khieukhacirclekorean: 0x3278, + khieukhaparenkorean: 0x3218, + khieukhcirclekorean: 0x326A, + khieukhkorean: 0x314B, + khieukhparenkorean: 0x320A, + khokhaithai: 0x0E02, + khokhonthai: 0x0E05, + khokhuatthai: 0x0E03, + khokhwaithai: 0x0E04, + khomutthai: 0x0E5B, + khook: 0x0199, + khorakhangthai: 0x0E06, + khzsquare: 0x3391, + kihiragana: 0x304D, + kikatakana: 0x30AD, + kikatakanahalfwidth: 0xFF77, + kiroguramusquare: 0x3315, + kiromeetorusquare: 0x3316, + kirosquare: 0x3314, + kiyeokacirclekorean: 0x326E, + kiyeokaparenkorean: 0x320E, + kiyeokcirclekorean: 0x3260, + kiyeokkorean: 0x3131, + kiyeokparenkorean: 0x3200, + kiyeoksioskorean: 0x3133, + kjecyrillic: 0x045C, + klinebelow: 0x1E35, + klsquare: 0x3398, + kmcubedsquare: 0x33A6, + kmonospace: 0xFF4B, + kmsquaredsquare: 0x33A2, + kohiragana: 0x3053, + kohmsquare: 0x33C0, + kokaithai: 0x0E01, + kokatakana: 0x30B3, + kokatakanahalfwidth: 0xFF7A, + kooposquare: 0x331E, + koppacyrillic: 0x0481, + koreanstandardsymbol: 0x327F, + koroniscmb: 0x0343, + kparen: 0x24A6, + kpasquare: 0x33AA, + ksicyrillic: 0x046F, + ktsquare: 0x33CF, + kturned: 0x029E, + kuhiragana: 0x304F, + kukatakana: 0x30AF, + kukatakanahalfwidth: 0xFF78, + kvsquare: 0x33B8, + kwsquare: 0x33BE, + l: 0x006C, + labengali: 0x09B2, + lacute: 0x013A, + ladeva: 0x0932, + lagujarati: 0x0AB2, + lagurmukhi: 0x0A32, + lakkhangyaothai: 0x0E45, + lamaleffinalarabic: 0xFEFC, + lamalefhamzaabovefinalarabic: 0xFEF8, + lamalefhamzaaboveisolatedarabic: 0xFEF7, + lamalefhamzabelowfinalarabic: 0xFEFA, + lamalefhamzabelowisolatedarabic: 0xFEF9, + lamalefisolatedarabic: 0xFEFB, + lamalefmaddaabovefinalarabic: 0xFEF6, + lamalefmaddaaboveisolatedarabic: 0xFEF5, + lamarabic: 0x0644, + lambda: 0x03BB, + lambdastroke: 0x019B, + lamed: 0x05DC, + lameddagesh: 0xFB3C, + lameddageshhebrew: 0xFB3C, + lamedhebrew: 0x05DC, lamedholam: "05DC 05B9", lamedholamdagesh: "05DC 05B9 05BC", lamedholamdageshhebrew: "05DC 05B9 05BC", lamedholamhebrew: "05DC 05B9", - lamfinalarabic: "FEDE", - lamhahinitialarabic: "FCCA", - laminitialarabic: "FEDF", - lamjeeminitialarabic: "FCC9", - lamkhahinitialarabic: "FCCB", - lamlamhehisolatedarabic: "FDF2", - lammedialarabic: "FEE0", - lammeemhahinitialarabic: "FD88", - lammeeminitialarabic: "FCCC", + lamfinalarabic: 0xFEDE, + lamhahinitialarabic: 0xFCCA, + laminitialarabic: 0xFEDF, + lamjeeminitialarabic: 0xFCC9, + lamkhahinitialarabic: 0xFCCB, + lamlamhehisolatedarabic: 0xFDF2, + lammedialarabic: 0xFEE0, + lammeemhahinitialarabic: 0xFD88, + lammeeminitialarabic: 0xFCCC, lammeemjeeminitialarabic: "FEDF FEE4 FEA0", lammeemkhahinitialarabic: "FEDF FEE4 FEA8", - largecircle: "25EF", - lbar: "019A", - lbelt: "026C", - lbopomofo: "310C", - lcaron: "013E", - lcedilla: "013C", - lcircle: "24DB", - lcircumflexbelow: "1E3D", - lcommaaccent: "013C", - ldot: "0140", - ldotaccent: "0140", - ldotbelow: "1E37", - ldotbelowmacron: "1E39", - leftangleabovecmb: "031A", - lefttackbelowcmb: "0318", - less: "003C", - lessequal: "2264", - lessequalorgreater: "22DA", - lessmonospace: "FF1C", - lessorequivalent: "2272", - lessorgreater: "2276", - lessoverequal: "2266", - lesssmall: "FE64", - lezh: "026E", - lfblock: "258C", - lhookretroflex: "026D", - lira: "20A4", - liwnarmenian: "056C", - lj: "01C9", - ljecyrillic: "0459", - ll: "F6C0", - lladeva: "0933", - llagujarati: "0AB3", - llinebelow: "1E3B", - llladeva: "0934", - llvocalicbengali: "09E1", - llvocalicdeva: "0961", - llvocalicvowelsignbengali: "09E3", - llvocalicvowelsigndeva: "0963", - lmiddletilde: "026B", - lmonospace: "FF4C", - lmsquare: "33D0", - lochulathai: "0E2C", - logicaland: "2227", - logicalnot: "00AC", - logicalnotreversed: "2310", - logicalor: "2228", - lolingthai: "0E25", - longs: "017F", - lowlinecenterline: "FE4E", - lowlinecmb: "0332", - lowlinedashed: "FE4D", - lozenge: "25CA", - lparen: "24A7", - lslash: "0142", - lsquare: "2113", - lsuperior: "F6EE", - ltshade: "2591", - luthai: "0E26", - lvocalicbengali: "098C", - lvocalicdeva: "090C", - lvocalicvowelsignbengali: "09E2", - lvocalicvowelsigndeva: "0962", - lxsquare: "33D3", - m: "006D", - mabengali: "09AE", - macron: "00AF", - macronbelowcmb: "0331", - macroncmb: "0304", - macronlowmod: "02CD", - macronmonospace: "FFE3", - macute: "1E3F", - madeva: "092E", - magujarati: "0AAE", - magurmukhi: "0A2E", - mahapakhhebrew: "05A4", - mahapakhlefthebrew: "05A4", - mahiragana: "307E", - maichattawalowleftthai: "F895", - maichattawalowrightthai: "F894", - maichattawathai: "0E4B", - maichattawaupperleftthai: "F893", - maieklowleftthai: "F88C", - maieklowrightthai: "F88B", - maiekthai: "0E48", - maiekupperleftthai: "F88A", - maihanakatleftthai: "F884", - maihanakatthai: "0E31", - maitaikhuleftthai: "F889", - maitaikhuthai: "0E47", - maitholowleftthai: "F88F", - maitholowrightthai: "F88E", - maithothai: "0E49", - maithoupperleftthai: "F88D", - maitrilowleftthai: "F892", - maitrilowrightthai: "F891", - maitrithai: "0E4A", - maitriupperleftthai: "F890", - maiyamokthai: "0E46", - makatakana: "30DE", - makatakanahalfwidth: "FF8F", - male: "2642", - mansyonsquare: "3347", - maqafhebrew: "05BE", - mars: "2642", - masoracirclehebrew: "05AF", - masquare: "3383", - mbopomofo: "3107", - mbsquare: "33D4", - mcircle: "24DC", - mcubedsquare: "33A5", - mdotaccent: "1E41", - mdotbelow: "1E43", - meemarabic: "0645", - meemfinalarabic: "FEE2", - meeminitialarabic: "FEE3", - meemmedialarabic: "FEE4", - meemmeeminitialarabic: "FCD1", - meemmeemisolatedarabic: "FC48", - meetorusquare: "334D", - mehiragana: "3081", - meizierasquare: "337E", - mekatakana: "30E1", - mekatakanahalfwidth: "FF92", - mem: "05DE", - memdagesh: "FB3E", - memdageshhebrew: "FB3E", - memhebrew: "05DE", - menarmenian: "0574", - merkhahebrew: "05A5", - merkhakefulahebrew: "05A6", - merkhakefulalefthebrew: "05A6", - merkhalefthebrew: "05A5", - mhook: "0271", - mhzsquare: "3392", - middledotkatakanahalfwidth: "FF65", - middot: "00B7", - mieumacirclekorean: "3272", - mieumaparenkorean: "3212", - mieumcirclekorean: "3264", - mieumkorean: "3141", - mieumpansioskorean: "3170", - mieumparenkorean: "3204", - mieumpieupkorean: "316E", - mieumsioskorean: "316F", - mihiragana: "307F", - mikatakana: "30DF", - mikatakanahalfwidth: "FF90", - minus: "2212", - minusbelowcmb: "0320", - minuscircle: "2296", - minusmod: "02D7", - minusplus: "2213", - minute: "2032", - miribaarusquare: "334A", - mirisquare: "3349", - mlonglegturned: "0270", - mlsquare: "3396", - mmcubedsquare: "33A3", - mmonospace: "FF4D", - mmsquaredsquare: "339F", - mohiragana: "3082", - mohmsquare: "33C1", - mokatakana: "30E2", - mokatakanahalfwidth: "FF93", - molsquare: "33D6", - momathai: "0E21", - moverssquare: "33A7", - moverssquaredsquare: "33A8", - mparen: "24A8", - mpasquare: "33AB", - mssquare: "33B3", - msuperior: "F6EF", - mturned: "026F", - mu: "00B5", - mu1: "00B5", - muasquare: "3382", - muchgreater: "226B", - muchless: "226A", - mufsquare: "338C", - mugreek: "03BC", - mugsquare: "338D", - muhiragana: "3080", - mukatakana: "30E0", - mukatakanahalfwidth: "FF91", - mulsquare: "3395", - multiply: "00D7", - mumsquare: "339B", - munahhebrew: "05A3", - munahlefthebrew: "05A3", - musicalnote: "266A", - musicalnotedbl: "266B", - musicflatsign: "266D", - musicsharpsign: "266F", - mussquare: "33B2", - muvsquare: "33B6", - muwsquare: "33BC", - mvmegasquare: "33B9", - mvsquare: "33B7", - mwmegasquare: "33BF", - mwsquare: "33BD", - n: "006E", - nabengali: "09A8", - nabla: "2207", - nacute: "0144", - nadeva: "0928", - nagujarati: "0AA8", - nagurmukhi: "0A28", - nahiragana: "306A", - nakatakana: "30CA", - nakatakanahalfwidth: "FF85", - napostrophe: "0149", - nasquare: "3381", - nbopomofo: "310B", - nbspace: "00A0", - ncaron: "0148", - ncedilla: "0146", - ncircle: "24DD", - ncircumflexbelow: "1E4B", - ncommaaccent: "0146", - ndotaccent: "1E45", - ndotbelow: "1E47", - nehiragana: "306D", - nekatakana: "30CD", - nekatakanahalfwidth: "FF88", - newsheqelsign: "20AA", - nfsquare: "338B", - ngabengali: "0999", - ngadeva: "0919", - ngagujarati: "0A99", - ngagurmukhi: "0A19", - ngonguthai: "0E07", - nhiragana: "3093", - nhookleft: "0272", - nhookretroflex: "0273", - nieunacirclekorean: "326F", - nieunaparenkorean: "320F", - nieuncieuckorean: "3135", - nieuncirclekorean: "3261", - nieunhieuhkorean: "3136", - nieunkorean: "3134", - nieunpansioskorean: "3168", - nieunparenkorean: "3201", - nieunsioskorean: "3167", - nieuntikeutkorean: "3166", - nihiragana: "306B", - nikatakana: "30CB", - nikatakanahalfwidth: "FF86", - nikhahitleftthai: "F899", - nikhahitthai: "0E4D", - nine: "0039", - ninearabic: "0669", - ninebengali: "09EF", - ninecircle: "2468", - ninecircleinversesansserif: "2792", - ninedeva: "096F", - ninegujarati: "0AEF", - ninegurmukhi: "0A6F", - ninehackarabic: "0669", - ninehangzhou: "3029", - nineideographicparen: "3228", - nineinferior: "2089", - ninemonospace: "FF19", - nineoldstyle: "F739", - nineparen: "247C", - nineperiod: "2490", - ninepersian: "06F9", - nineroman: "2178", - ninesuperior: "2079", - nineteencircle: "2472", - nineteenparen: "2486", - nineteenperiod: "249A", - ninethai: "0E59", - nj: "01CC", - njecyrillic: "045A", - nkatakana: "30F3", - nkatakanahalfwidth: "FF9D", - nlegrightlong: "019E", - nlinebelow: "1E49", - nmonospace: "FF4E", - nmsquare: "339A", - nnabengali: "09A3", - nnadeva: "0923", - nnagujarati: "0AA3", - nnagurmukhi: "0A23", - nnnadeva: "0929", - nohiragana: "306E", - nokatakana: "30CE", - nokatakanahalfwidth: "FF89", - nonbreakingspace: "00A0", - nonenthai: "0E13", - nonuthai: "0E19", - noonarabic: "0646", - noonfinalarabic: "FEE6", - noonghunnaarabic: "06BA", - noonghunnafinalarabic: "FB9F", + largecircle: 0x25EF, + lbar: 0x019A, + lbelt: 0x026C, + lbopomofo: 0x310C, + lcaron: 0x013E, + lcedilla: 0x013C, + lcircle: 0x24DB, + lcircumflexbelow: 0x1E3D, + lcommaaccent: 0x013C, + ldot: 0x0140, + ldotaccent: 0x0140, + ldotbelow: 0x1E37, + ldotbelowmacron: 0x1E39, + leftangleabovecmb: 0x031A, + lefttackbelowcmb: 0x0318, + less: 0x003C, + lessequal: 0x2264, + lessequalorgreater: 0x22DA, + lessmonospace: 0xFF1C, + lessorequivalent: 0x2272, + lessorgreater: 0x2276, + lessoverequal: 0x2266, + lesssmall: 0xFE64, + lezh: 0x026E, + lfblock: 0x258C, + lhookretroflex: 0x026D, + lira: 0x20A4, + liwnarmenian: 0x056C, + lj: 0x01C9, + ljecyrillic: 0x0459, + ll: 0xF6C0, + lladeva: 0x0933, + llagujarati: 0x0AB3, + llinebelow: 0x1E3B, + llladeva: 0x0934, + llvocalicbengali: 0x09E1, + llvocalicdeva: 0x0961, + llvocalicvowelsignbengali: 0x09E3, + llvocalicvowelsigndeva: 0x0963, + lmiddletilde: 0x026B, + lmonospace: 0xFF4C, + lmsquare: 0x33D0, + lochulathai: 0x0E2C, + logicaland: 0x2227, + logicalnot: 0x00AC, + logicalnotreversed: 0x2310, + logicalor: 0x2228, + lolingthai: 0x0E25, + longs: 0x017F, + lowlinecenterline: 0xFE4E, + lowlinecmb: 0x0332, + lowlinedashed: 0xFE4D, + lozenge: 0x25CA, + lparen: 0x24A7, + lslash: 0x0142, + lsquare: 0x2113, + lsuperior: 0xF6EE, + ltshade: 0x2591, + luthai: 0x0E26, + lvocalicbengali: 0x098C, + lvocalicdeva: 0x090C, + lvocalicvowelsignbengali: 0x09E2, + lvocalicvowelsigndeva: 0x0962, + lxsquare: 0x33D3, + m: 0x006D, + mabengali: 0x09AE, + macron: 0x00AF, + macronbelowcmb: 0x0331, + macroncmb: 0x0304, + macronlowmod: 0x02CD, + macronmonospace: 0xFFE3, + macute: 0x1E3F, + madeva: 0x092E, + magujarati: 0x0AAE, + magurmukhi: 0x0A2E, + mahapakhhebrew: 0x05A4, + mahapakhlefthebrew: 0x05A4, + mahiragana: 0x307E, + maichattawalowleftthai: 0xF895, + maichattawalowrightthai: 0xF894, + maichattawathai: 0x0E4B, + maichattawaupperleftthai: 0xF893, + maieklowleftthai: 0xF88C, + maieklowrightthai: 0xF88B, + maiekthai: 0x0E48, + maiekupperleftthai: 0xF88A, + maihanakatleftthai: 0xF884, + maihanakatthai: 0x0E31, + maitaikhuleftthai: 0xF889, + maitaikhuthai: 0x0E47, + maitholowleftthai: 0xF88F, + maitholowrightthai: 0xF88E, + maithothai: 0x0E49, + maithoupperleftthai: 0xF88D, + maitrilowleftthai: 0xF892, + maitrilowrightthai: 0xF891, + maitrithai: 0x0E4A, + maitriupperleftthai: 0xF890, + maiyamokthai: 0x0E46, + makatakana: 0x30DE, + makatakanahalfwidth: 0xFF8F, + male: 0x2642, + mansyonsquare: 0x3347, + maqafhebrew: 0x05BE, + mars: 0x2642, + masoracirclehebrew: 0x05AF, + masquare: 0x3383, + mbopomofo: 0x3107, + mbsquare: 0x33D4, + mcircle: 0x24DC, + mcubedsquare: 0x33A5, + mdotaccent: 0x1E41, + mdotbelow: 0x1E43, + meemarabic: 0x0645, + meemfinalarabic: 0xFEE2, + meeminitialarabic: 0xFEE3, + meemmedialarabic: 0xFEE4, + meemmeeminitialarabic: 0xFCD1, + meemmeemisolatedarabic: 0xFC48, + meetorusquare: 0x334D, + mehiragana: 0x3081, + meizierasquare: 0x337E, + mekatakana: 0x30E1, + mekatakanahalfwidth: 0xFF92, + mem: 0x05DE, + memdagesh: 0xFB3E, + memdageshhebrew: 0xFB3E, + memhebrew: 0x05DE, + menarmenian: 0x0574, + merkhahebrew: 0x05A5, + merkhakefulahebrew: 0x05A6, + merkhakefulalefthebrew: 0x05A6, + merkhalefthebrew: 0x05A5, + mhook: 0x0271, + mhzsquare: 0x3392, + middledotkatakanahalfwidth: 0xFF65, + middot: 0x00B7, + mieumacirclekorean: 0x3272, + mieumaparenkorean: 0x3212, + mieumcirclekorean: 0x3264, + mieumkorean: 0x3141, + mieumpansioskorean: 0x3170, + mieumparenkorean: 0x3204, + mieumpieupkorean: 0x316E, + mieumsioskorean: 0x316F, + mihiragana: 0x307F, + mikatakana: 0x30DF, + mikatakanahalfwidth: 0xFF90, + minus: 0x2212, + minusbelowcmb: 0x0320, + minuscircle: 0x2296, + minusmod: 0x02D7, + minusplus: 0x2213, + minute: 0x2032, + miribaarusquare: 0x334A, + mirisquare: 0x3349, + mlonglegturned: 0x0270, + mlsquare: 0x3396, + mmcubedsquare: 0x33A3, + mmonospace: 0xFF4D, + mmsquaredsquare: 0x339F, + mohiragana: 0x3082, + mohmsquare: 0x33C1, + mokatakana: 0x30E2, + mokatakanahalfwidth: 0xFF93, + molsquare: 0x33D6, + momathai: 0x0E21, + moverssquare: 0x33A7, + moverssquaredsquare: 0x33A8, + mparen: 0x24A8, + mpasquare: 0x33AB, + mssquare: 0x33B3, + msuperior: 0xF6EF, + mturned: 0x026F, + mu: 0x00B5, + mu1: 0x00B5, + muasquare: 0x3382, + muchgreater: 0x226B, + muchless: 0x226A, + mufsquare: 0x338C, + mugreek: 0x03BC, + mugsquare: 0x338D, + muhiragana: 0x3080, + mukatakana: 0x30E0, + mukatakanahalfwidth: 0xFF91, + mulsquare: 0x3395, + multiply: 0x00D7, + mumsquare: 0x339B, + munahhebrew: 0x05A3, + munahlefthebrew: 0x05A3, + musicalnote: 0x266A, + musicalnotedbl: 0x266B, + musicflatsign: 0x266D, + musicsharpsign: 0x266F, + mussquare: 0x33B2, + muvsquare: 0x33B6, + muwsquare: 0x33BC, + mvmegasquare: 0x33B9, + mvsquare: 0x33B7, + mwmegasquare: 0x33BF, + mwsquare: 0x33BD, + n: 0x006E, + nabengali: 0x09A8, + nabla: 0x2207, + nacute: 0x0144, + nadeva: 0x0928, + nagujarati: 0x0AA8, + nagurmukhi: 0x0A28, + nahiragana: 0x306A, + nakatakana: 0x30CA, + nakatakanahalfwidth: 0xFF85, + napostrophe: 0x0149, + nasquare: 0x3381, + nbopomofo: 0x310B, + nbspace: 0x00A0, + ncaron: 0x0148, + ncedilla: 0x0146, + ncircle: 0x24DD, + ncircumflexbelow: 0x1E4B, + ncommaaccent: 0x0146, + ndotaccent: 0x1E45, + ndotbelow: 0x1E47, + nehiragana: 0x306D, + nekatakana: 0x30CD, + nekatakanahalfwidth: 0xFF88, + newsheqelsign: 0x20AA, + nfsquare: 0x338B, + ngabengali: 0x0999, + ngadeva: 0x0919, + ngagujarati: 0x0A99, + ngagurmukhi: 0x0A19, + ngonguthai: 0x0E07, + nhiragana: 0x3093, + nhookleft: 0x0272, + nhookretroflex: 0x0273, + nieunacirclekorean: 0x326F, + nieunaparenkorean: 0x320F, + nieuncieuckorean: 0x3135, + nieuncirclekorean: 0x3261, + nieunhieuhkorean: 0x3136, + nieunkorean: 0x3134, + nieunpansioskorean: 0x3168, + nieunparenkorean: 0x3201, + nieunsioskorean: 0x3167, + nieuntikeutkorean: 0x3166, + nihiragana: 0x306B, + nikatakana: 0x30CB, + nikatakanahalfwidth: 0xFF86, + nikhahitleftthai: 0xF899, + nikhahitthai: 0x0E4D, + nine: 0x0039, + ninearabic: 0x0669, + ninebengali: 0x09EF, + ninecircle: 0x2468, + ninecircleinversesansserif: 0x2792, + ninedeva: 0x096F, + ninegujarati: 0x0AEF, + ninegurmukhi: 0x0A6F, + ninehackarabic: 0x0669, + ninehangzhou: 0x3029, + nineideographicparen: 0x3228, + nineinferior: 0x2089, + ninemonospace: 0xFF19, + nineoldstyle: 0xF739, + nineparen: 0x247C, + nineperiod: 0x2490, + ninepersian: 0x06F9, + nineroman: 0x2178, + ninesuperior: 0x2079, + nineteencircle: 0x2472, + nineteenparen: 0x2486, + nineteenperiod: 0x249A, + ninethai: 0x0E59, + nj: 0x01CC, + njecyrillic: 0x045A, + nkatakana: 0x30F3, + nkatakanahalfwidth: 0xFF9D, + nlegrightlong: 0x019E, + nlinebelow: 0x1E49, + nmonospace: 0xFF4E, + nmsquare: 0x339A, + nnabengali: 0x09A3, + nnadeva: 0x0923, + nnagujarati: 0x0AA3, + nnagurmukhi: 0x0A23, + nnnadeva: 0x0929, + nohiragana: 0x306E, + nokatakana: 0x30CE, + nokatakanahalfwidth: 0xFF89, + nonbreakingspace: 0x00A0, + nonenthai: 0x0E13, + nonuthai: 0x0E19, + noonarabic: 0x0646, + noonfinalarabic: 0xFEE6, + noonghunnaarabic: 0x06BA, + noonghunnafinalarabic: 0xFB9F, noonhehinitialarabic: "FEE7 FEEC", - nooninitialarabic: "FEE7", - noonjeeminitialarabic: "FCD2", - noonjeemisolatedarabic: "FC4B", - noonmedialarabic: "FEE8", - noonmeeminitialarabic: "FCD5", - noonmeemisolatedarabic: "FC4E", - noonnoonfinalarabic: "FC8D", - notcontains: "220C", - notelement: "2209", - notelementof: "2209", - notequal: "2260", - notgreater: "226F", - notgreaternorequal: "2271", - notgreaternorless: "2279", - notidentical: "2262", - notless: "226E", - notlessnorequal: "2270", - notparallel: "2226", - notprecedes: "2280", - notsubset: "2284", - notsucceeds: "2281", - notsuperset: "2285", - nowarmenian: "0576", - nparen: "24A9", - nssquare: "33B1", - nsuperior: "207F", - ntilde: "00F1", - nu: "03BD", - nuhiragana: "306C", - nukatakana: "30CC", - nukatakanahalfwidth: "FF87", - nuktabengali: "09BC", - nuktadeva: "093C", - nuktagujarati: "0ABC", - nuktagurmukhi: "0A3C", - numbersign: "0023", - numbersignmonospace: "FF03", - numbersignsmall: "FE5F", - numeralsigngreek: "0374", - numeralsignlowergreek: "0375", - numero: "2116", - nun: "05E0", - nundagesh: "FB40", - nundageshhebrew: "FB40", - nunhebrew: "05E0", - nvsquare: "33B5", - nwsquare: "33BB", - nyabengali: "099E", - nyadeva: "091E", - nyagujarati: "0A9E", - nyagurmukhi: "0A1E", - o: "006F", - oacute: "00F3", - oangthai: "0E2D", - obarred: "0275", - obarredcyrillic: "04E9", - obarreddieresiscyrillic: "04EB", - obengali: "0993", - obopomofo: "311B", - obreve: "014F", - ocandradeva: "0911", - ocandragujarati: "0A91", - ocandravowelsigndeva: "0949", - ocandravowelsigngujarati: "0AC9", - ocaron: "01D2", - ocircle: "24DE", - ocircumflex: "00F4", - ocircumflexacute: "1ED1", - ocircumflexdotbelow: "1ED9", - ocircumflexgrave: "1ED3", - ocircumflexhookabove: "1ED5", - ocircumflextilde: "1ED7", - ocyrillic: "043E", - odblacute: "0151", - odblgrave: "020D", - odeva: "0913", - odieresis: "00F6", - odieresiscyrillic: "04E7", - odotbelow: "1ECD", - oe: "0153", - oekorean: "315A", - ogonek: "02DB", - ogonekcmb: "0328", - ograve: "00F2", - ogujarati: "0A93", - oharmenian: "0585", - ohiragana: "304A", - ohookabove: "1ECF", - ohorn: "01A1", - ohornacute: "1EDB", - ohorndotbelow: "1EE3", - ohorngrave: "1EDD", - ohornhookabove: "1EDF", - ohorntilde: "1EE1", - ohungarumlaut: "0151", - oi: "01A3", - oinvertedbreve: "020F", - okatakana: "30AA", - okatakanahalfwidth: "FF75", - okorean: "3157", - olehebrew: "05AB", - omacron: "014D", - omacronacute: "1E53", - omacrongrave: "1E51", - omdeva: "0950", - omega: "03C9", - omega1: "03D6", - omegacyrillic: "0461", - omegalatinclosed: "0277", - omegaroundcyrillic: "047B", - omegatitlocyrillic: "047D", - omegatonos: "03CE", - omgujarati: "0AD0", - omicron: "03BF", - omicrontonos: "03CC", - omonospace: "FF4F", - one: "0031", - onearabic: "0661", - onebengali: "09E7", - onecircle: "2460", - onecircleinversesansserif: "278A", - onedeva: "0967", - onedotenleader: "2024", - oneeighth: "215B", - onefitted: "F6DC", - onegujarati: "0AE7", - onegurmukhi: "0A67", - onehackarabic: "0661", - onehalf: "00BD", - onehangzhou: "3021", - oneideographicparen: "3220", - oneinferior: "2081", - onemonospace: "FF11", - onenumeratorbengali: "09F4", - oneoldstyle: "F731", - oneparen: "2474", - oneperiod: "2488", - onepersian: "06F1", - onequarter: "00BC", - oneroman: "2170", - onesuperior: "00B9", - onethai: "0E51", - onethird: "2153", - oogonek: "01EB", - oogonekmacron: "01ED", - oogurmukhi: "0A13", - oomatragurmukhi: "0A4B", - oopen: "0254", - oparen: "24AA", - openbullet: "25E6", - option: "2325", - ordfeminine: "00AA", - ordmasculine: "00BA", - orthogonal: "221F", - oshortdeva: "0912", - oshortvowelsigndeva: "094A", - oslash: "00F8", - oslashacute: "01FF", - osmallhiragana: "3049", - osmallkatakana: "30A9", - osmallkatakanahalfwidth: "FF6B", - ostrokeacute: "01FF", - osuperior: "F6F0", - otcyrillic: "047F", - otilde: "00F5", - otildeacute: "1E4D", - otildedieresis: "1E4F", - oubopomofo: "3121", - overline: "203E", - overlinecenterline: "FE4A", - overlinecmb: "0305", - overlinedashed: "FE49", - overlinedblwavy: "FE4C", - overlinewavy: "FE4B", - overscore: "00AF", - ovowelsignbengali: "09CB", - ovowelsigndeva: "094B", - ovowelsigngujarati: "0ACB", - p: "0070", - paampssquare: "3380", - paasentosquare: "332B", - pabengali: "09AA", - pacute: "1E55", - padeva: "092A", - pagedown: "21DF", - pageup: "21DE", - pagujarati: "0AAA", - pagurmukhi: "0A2A", - pahiragana: "3071", - paiyannoithai: "0E2F", - pakatakana: "30D1", - palatalizationcyrilliccmb: "0484", - palochkacyrillic: "04C0", - pansioskorean: "317F", - paragraph: "00B6", - parallel: "2225", - parenleft: "0028", - parenleftaltonearabic: "FD3E", - parenleftbt: "F8ED", - parenleftex: "F8EC", - parenleftinferior: "208D", - parenleftmonospace: "FF08", - parenleftsmall: "FE59", - parenleftsuperior: "207D", - parenlefttp: "F8EB", - parenleftvertical: "FE35", - parenright: "0029", - parenrightaltonearabic: "FD3F", - parenrightbt: "F8F8", - parenrightex: "F8F7", - parenrightinferior: "208E", - parenrightmonospace: "FF09", - parenrightsmall: "FE5A", - parenrightsuperior: "207E", - parenrighttp: "F8F6", - parenrightvertical: "FE36", - partialdiff: "2202", - paseqhebrew: "05C0", - pashtahebrew: "0599", - pasquare: "33A9", - patah: "05B7", - patah11: "05B7", - patah1d: "05B7", - patah2a: "05B7", - patahhebrew: "05B7", - patahnarrowhebrew: "05B7", - patahquarterhebrew: "05B7", - patahwidehebrew: "05B7", - pazerhebrew: "05A1", - pbopomofo: "3106", - pcircle: "24DF", - pdotaccent: "1E57", - pe: "05E4", - pecyrillic: "043F", - pedagesh: "FB44", - pedageshhebrew: "FB44", - peezisquare: "333B", - pefinaldageshhebrew: "FB43", - peharabic: "067E", - peharmenian: "057A", - pehebrew: "05E4", - pehfinalarabic: "FB57", - pehinitialarabic: "FB58", - pehiragana: "307A", - pehmedialarabic: "FB59", - pekatakana: "30DA", - pemiddlehookcyrillic: "04A7", - perafehebrew: "FB4E", - percent: "0025", - percentarabic: "066A", - percentmonospace: "FF05", - percentsmall: "FE6A", - period: "002E", - periodarmenian: "0589", - periodcentered: "00B7", - periodhalfwidth: "FF61", - periodinferior: "F6E7", - periodmonospace: "FF0E", - periodsmall: "FE52", - periodsuperior: "F6E8", - perispomenigreekcmb: "0342", - perpendicular: "22A5", - perthousand: "2030", - peseta: "20A7", - pfsquare: "338A", - phabengali: "09AB", - phadeva: "092B", - phagujarati: "0AAB", - phagurmukhi: "0A2B", - phi: "03C6", - phi1: "03D5", - phieuphacirclekorean: "327A", - phieuphaparenkorean: "321A", - phieuphcirclekorean: "326C", - phieuphkorean: "314D", - phieuphparenkorean: "320C", - philatin: "0278", - phinthuthai: "0E3A", - phisymbolgreek: "03D5", - phook: "01A5", - phophanthai: "0E1E", - phophungthai: "0E1C", - phosamphaothai: "0E20", - pi: "03C0", - pieupacirclekorean: "3273", - pieupaparenkorean: "3213", - pieupcieuckorean: "3176", - pieupcirclekorean: "3265", - pieupkiyeokkorean: "3172", - pieupkorean: "3142", - pieupparenkorean: "3205", - pieupsioskiyeokkorean: "3174", - pieupsioskorean: "3144", - pieupsiostikeutkorean: "3175", - pieupthieuthkorean: "3177", - pieuptikeutkorean: "3173", - pihiragana: "3074", - pikatakana: "30D4", - pisymbolgreek: "03D6", - piwrarmenian: "0583", - plus: "002B", - plusbelowcmb: "031F", - pluscircle: "2295", - plusminus: "00B1", - plusmod: "02D6", - plusmonospace: "FF0B", - plussmall: "FE62", - plussuperior: "207A", - pmonospace: "FF50", - pmsquare: "33D8", - pohiragana: "307D", - pointingindexdownwhite: "261F", - pointingindexleftwhite: "261C", - pointingindexrightwhite: "261E", - pointingindexupwhite: "261D", - pokatakana: "30DD", - poplathai: "0E1B", - postalmark: "3012", - postalmarkface: "3020", - pparen: "24AB", - precedes: "227A", - prescription: "211E", - primemod: "02B9", - primereversed: "2035", - product: "220F", - projective: "2305", - prolongedkana: "30FC", - propellor: "2318", - propersubset: "2282", - propersuperset: "2283", - proportion: "2237", - proportional: "221D", - psi: "03C8", - psicyrillic: "0471", - psilipneumatacyrilliccmb: "0486", - pssquare: "33B0", - puhiragana: "3077", - pukatakana: "30D7", - pvsquare: "33B4", - pwsquare: "33BA", - q: "0071", - qadeva: "0958", - qadmahebrew: "05A8", - qafarabic: "0642", - qaffinalarabic: "FED6", - qafinitialarabic: "FED7", - qafmedialarabic: "FED8", - qamats: "05B8", - qamats10: "05B8", - qamats1a: "05B8", - qamats1c: "05B8", - qamats27: "05B8", - qamats29: "05B8", - qamats33: "05B8", - qamatsde: "05B8", - qamatshebrew: "05B8", - qamatsnarrowhebrew: "05B8", - qamatsqatanhebrew: "05B8", - qamatsqatannarrowhebrew: "05B8", - qamatsqatanquarterhebrew: "05B8", - qamatsqatanwidehebrew: "05B8", - qamatsquarterhebrew: "05B8", - qamatswidehebrew: "05B8", - qarneyparahebrew: "059F", - qbopomofo: "3111", - qcircle: "24E0", - qhook: "02A0", - qmonospace: "FF51", - qof: "05E7", - qofdagesh: "FB47", - qofdageshhebrew: "FB47", + nooninitialarabic: 0xFEE7, + noonjeeminitialarabic: 0xFCD2, + noonjeemisolatedarabic: 0xFC4B, + noonmedialarabic: 0xFEE8, + noonmeeminitialarabic: 0xFCD5, + noonmeemisolatedarabic: 0xFC4E, + noonnoonfinalarabic: 0xFC8D, + notcontains: 0x220C, + notelement: 0x2209, + notelementof: 0x2209, + notequal: 0x2260, + notgreater: 0x226F, + notgreaternorequal: 0x2271, + notgreaternorless: 0x2279, + notidentical: 0x2262, + notless: 0x226E, + notlessnorequal: 0x2270, + notparallel: 0x2226, + notprecedes: 0x2280, + notsubset: 0x2284, + notsucceeds: 0x2281, + notsuperset: 0x2285, + nowarmenian: 0x0576, + nparen: 0x24A9, + nssquare: 0x33B1, + nsuperior: 0x207F, + ntilde: 0x00F1, + nu: 0x03BD, + nuhiragana: 0x306C, + nukatakana: 0x30CC, + nukatakanahalfwidth: 0xFF87, + nuktabengali: 0x09BC, + nuktadeva: 0x093C, + nuktagujarati: 0x0ABC, + nuktagurmukhi: 0x0A3C, + numbersign: 0x0023, + numbersignmonospace: 0xFF03, + numbersignsmall: 0xFE5F, + numeralsigngreek: 0x0374, + numeralsignlowergreek: 0x0375, + numero: 0x2116, + nun: 0x05E0, + nundagesh: 0xFB40, + nundageshhebrew: 0xFB40, + nunhebrew: 0x05E0, + nvsquare: 0x33B5, + nwsquare: 0x33BB, + nyabengali: 0x099E, + nyadeva: 0x091E, + nyagujarati: 0x0A9E, + nyagurmukhi: 0x0A1E, + o: 0x006F, + oacute: 0x00F3, + oangthai: 0x0E2D, + obarred: 0x0275, + obarredcyrillic: 0x04E9, + obarreddieresiscyrillic: 0x04EB, + obengali: 0x0993, + obopomofo: 0x311B, + obreve: 0x014F, + ocandradeva: 0x0911, + ocandragujarati: 0x0A91, + ocandravowelsigndeva: 0x0949, + ocandravowelsigngujarati: 0x0AC9, + ocaron: 0x01D2, + ocircle: 0x24DE, + ocircumflex: 0x00F4, + ocircumflexacute: 0x1ED1, + ocircumflexdotbelow: 0x1ED9, + ocircumflexgrave: 0x1ED3, + ocircumflexhookabove: 0x1ED5, + ocircumflextilde: 0x1ED7, + ocyrillic: 0x043E, + odblacute: 0x0151, + odblgrave: 0x020D, + odeva: 0x0913, + odieresis: 0x00F6, + odieresiscyrillic: 0x04E7, + odotbelow: 0x1ECD, + oe: 0x0153, + oekorean: 0x315A, + ogonek: 0x02DB, + ogonekcmb: 0x0328, + ograve: 0x00F2, + ogujarati: 0x0A93, + oharmenian: 0x0585, + ohiragana: 0x304A, + ohookabove: 0x1ECF, + ohorn: 0x01A1, + ohornacute: 0x1EDB, + ohorndotbelow: 0x1EE3, + ohorngrave: 0x1EDD, + ohornhookabove: 0x1EDF, + ohorntilde: 0x1EE1, + ohungarumlaut: 0x0151, + oi: 0x01A3, + oinvertedbreve: 0x020F, + okatakana: 0x30AA, + okatakanahalfwidth: 0xFF75, + okorean: 0x3157, + olehebrew: 0x05AB, + omacron: 0x014D, + omacronacute: 0x1E53, + omacrongrave: 0x1E51, + omdeva: 0x0950, + omega: 0x03C9, + omega1: 0x03D6, + omegacyrillic: 0x0461, + omegalatinclosed: 0x0277, + omegaroundcyrillic: 0x047B, + omegatitlocyrillic: 0x047D, + omegatonos: 0x03CE, + omgujarati: 0x0AD0, + omicron: 0x03BF, + omicrontonos: 0x03CC, + omonospace: 0xFF4F, + one: 0x0031, + onearabic: 0x0661, + onebengali: 0x09E7, + onecircle: 0x2460, + onecircleinversesansserif: 0x278A, + onedeva: 0x0967, + onedotenleader: 0x2024, + oneeighth: 0x215B, + onefitted: 0xF6DC, + onegujarati: 0x0AE7, + onegurmukhi: 0x0A67, + onehackarabic: 0x0661, + onehalf: 0x00BD, + onehangzhou: 0x3021, + oneideographicparen: 0x3220, + oneinferior: 0x2081, + onemonospace: 0xFF11, + onenumeratorbengali: 0x09F4, + oneoldstyle: 0xF731, + oneparen: 0x2474, + oneperiod: 0x2488, + onepersian: 0x06F1, + onequarter: 0x00BC, + oneroman: 0x2170, + onesuperior: 0x00B9, + onethai: 0x0E51, + onethird: 0x2153, + oogonek: 0x01EB, + oogonekmacron: 0x01ED, + oogurmukhi: 0x0A13, + oomatragurmukhi: 0x0A4B, + oopen: 0x0254, + oparen: 0x24AA, + openbullet: 0x25E6, + option: 0x2325, + ordfeminine: 0x00AA, + ordmasculine: 0x00BA, + orthogonal: 0x221F, + oshortdeva: 0x0912, + oshortvowelsigndeva: 0x094A, + oslash: 0x00F8, + oslashacute: 0x01FF, + osmallhiragana: 0x3049, + osmallkatakana: 0x30A9, + osmallkatakanahalfwidth: 0xFF6B, + ostrokeacute: 0x01FF, + osuperior: 0xF6F0, + otcyrillic: 0x047F, + otilde: 0x00F5, + otildeacute: 0x1E4D, + otildedieresis: 0x1E4F, + oubopomofo: 0x3121, + overline: 0x203E, + overlinecenterline: 0xFE4A, + overlinecmb: 0x0305, + overlinedashed: 0xFE49, + overlinedblwavy: 0xFE4C, + overlinewavy: 0xFE4B, + overscore: 0x00AF, + ovowelsignbengali: 0x09CB, + ovowelsigndeva: 0x094B, + ovowelsigngujarati: 0x0ACB, + p: 0x0070, + paampssquare: 0x3380, + paasentosquare: 0x332B, + pabengali: 0x09AA, + pacute: 0x1E55, + padeva: 0x092A, + pagedown: 0x21DF, + pageup: 0x21DE, + pagujarati: 0x0AAA, + pagurmukhi: 0x0A2A, + pahiragana: 0x3071, + paiyannoithai: 0x0E2F, + pakatakana: 0x30D1, + palatalizationcyrilliccmb: 0x0484, + palochkacyrillic: 0x04C0, + pansioskorean: 0x317F, + paragraph: 0x00B6, + parallel: 0x2225, + parenleft: 0x0028, + parenleftaltonearabic: 0xFD3E, + parenleftbt: 0xF8ED, + parenleftex: 0xF8EC, + parenleftinferior: 0x208D, + parenleftmonospace: 0xFF08, + parenleftsmall: 0xFE59, + parenleftsuperior: 0x207D, + parenlefttp: 0xF8EB, + parenleftvertical: 0xFE35, + parenright: 0x0029, + parenrightaltonearabic: 0xFD3F, + parenrightbt: 0xF8F8, + parenrightex: 0xF8F7, + parenrightinferior: 0x208E, + parenrightmonospace: 0xFF09, + parenrightsmall: 0xFE5A, + parenrightsuperior: 0x207E, + parenrighttp: 0xF8F6, + parenrightvertical: 0xFE36, + partialdiff: 0x2202, + paseqhebrew: 0x05C0, + pashtahebrew: 0x0599, + pasquare: 0x33A9, + patah: 0x05B7, + patah11: 0x05B7, + patah1d: 0x05B7, + patah2a: 0x05B7, + patahhebrew: 0x05B7, + patahnarrowhebrew: 0x05B7, + patahquarterhebrew: 0x05B7, + patahwidehebrew: 0x05B7, + pazerhebrew: 0x05A1, + pbopomofo: 0x3106, + pcircle: 0x24DF, + pdotaccent: 0x1E57, + pe: 0x05E4, + pecyrillic: 0x043F, + pedagesh: 0xFB44, + pedageshhebrew: 0xFB44, + peezisquare: 0x333B, + pefinaldageshhebrew: 0xFB43, + peharabic: 0x067E, + peharmenian: 0x057A, + pehebrew: 0x05E4, + pehfinalarabic: 0xFB57, + pehinitialarabic: 0xFB58, + pehiragana: 0x307A, + pehmedialarabic: 0xFB59, + pekatakana: 0x30DA, + pemiddlehookcyrillic: 0x04A7, + perafehebrew: 0xFB4E, + percent: 0x0025, + percentarabic: 0x066A, + percentmonospace: 0xFF05, + percentsmall: 0xFE6A, + period: 0x002E, + periodarmenian: 0x0589, + periodcentered: 0x00B7, + periodhalfwidth: 0xFF61, + periodinferior: 0xF6E7, + periodmonospace: 0xFF0E, + periodsmall: 0xFE52, + periodsuperior: 0xF6E8, + perispomenigreekcmb: 0x0342, + perpendicular: 0x22A5, + perthousand: 0x2030, + peseta: 0x20A7, + pfsquare: 0x338A, + phabengali: 0x09AB, + phadeva: 0x092B, + phagujarati: 0x0AAB, + phagurmukhi: 0x0A2B, + phi: 0x03C6, + phi1: 0x03D5, + phieuphacirclekorean: 0x327A, + phieuphaparenkorean: 0x321A, + phieuphcirclekorean: 0x326C, + phieuphkorean: 0x314D, + phieuphparenkorean: 0x320C, + philatin: 0x0278, + phinthuthai: 0x0E3A, + phisymbolgreek: 0x03D5, + phook: 0x01A5, + phophanthai: 0x0E1E, + phophungthai: 0x0E1C, + phosamphaothai: 0x0E20, + pi: 0x03C0, + pieupacirclekorean: 0x3273, + pieupaparenkorean: 0x3213, + pieupcieuckorean: 0x3176, + pieupcirclekorean: 0x3265, + pieupkiyeokkorean: 0x3172, + pieupkorean: 0x3142, + pieupparenkorean: 0x3205, + pieupsioskiyeokkorean: 0x3174, + pieupsioskorean: 0x3144, + pieupsiostikeutkorean: 0x3175, + pieupthieuthkorean: 0x3177, + pieuptikeutkorean: 0x3173, + pihiragana: 0x3074, + pikatakana: 0x30D4, + pisymbolgreek: 0x03D6, + piwrarmenian: 0x0583, + plus: 0x002B, + plusbelowcmb: 0x031F, + pluscircle: 0x2295, + plusminus: 0x00B1, + plusmod: 0x02D6, + plusmonospace: 0xFF0B, + plussmall: 0xFE62, + plussuperior: 0x207A, + pmonospace: 0xFF50, + pmsquare: 0x33D8, + pohiragana: 0x307D, + pointingindexdownwhite: 0x261F, + pointingindexleftwhite: 0x261C, + pointingindexrightwhite: 0x261E, + pointingindexupwhite: 0x261D, + pokatakana: 0x30DD, + poplathai: 0x0E1B, + postalmark: 0x3012, + postalmarkface: 0x3020, + pparen: 0x24AB, + precedes: 0x227A, + prescription: 0x211E, + primemod: 0x02B9, + primereversed: 0x2035, + product: 0x220F, + projective: 0x2305, + prolongedkana: 0x30FC, + propellor: 0x2318, + propersubset: 0x2282, + propersuperset: 0x2283, + proportion: 0x2237, + proportional: 0x221D, + psi: 0x03C8, + psicyrillic: 0x0471, + psilipneumatacyrilliccmb: 0x0486, + pssquare: 0x33B0, + puhiragana: 0x3077, + pukatakana: 0x30D7, + pvsquare: 0x33B4, + pwsquare: 0x33BA, + q: 0x0071, + qadeva: 0x0958, + qadmahebrew: 0x05A8, + qafarabic: 0x0642, + qaffinalarabic: 0xFED6, + qafinitialarabic: 0xFED7, + qafmedialarabic: 0xFED8, + qamats: 0x05B8, + qamats10: 0x05B8, + qamats1a: 0x05B8, + qamats1c: 0x05B8, + qamats27: 0x05B8, + qamats29: 0x05B8, + qamats33: 0x05B8, + qamatsde: 0x05B8, + qamatshebrew: 0x05B8, + qamatsnarrowhebrew: 0x05B8, + qamatsqatanhebrew: 0x05B8, + qamatsqatannarrowhebrew: 0x05B8, + qamatsqatanquarterhebrew: 0x05B8, + qamatsqatanwidehebrew: 0x05B8, + qamatsquarterhebrew: 0x05B8, + qamatswidehebrew: 0x05B8, + qarneyparahebrew: 0x059F, + qbopomofo: 0x3111, + qcircle: 0x24E0, + qhook: 0x02A0, + qmonospace: 0xFF51, + qof: 0x05E7, + qofdagesh: 0xFB47, + qofdageshhebrew: 0xFB47, qofhatafpatah: "05E7 05B2", qofhatafpatahhebrew: "05E7 05B2", qofhatafsegol: "05E7 05B1", qofhatafsegolhebrew: "05E7 05B1", - qofhebrew: "05E7", + qofhebrew: 0x05E7, qofhiriq: "05E7 05B4", qofhiriqhebrew: "05E7 05B4", qofholam: "05E7 05B9", @@ -3172,89 +3172,89 @@ var GlyphsUnicode = { qofshevahebrew: "05E7 05B0", qoftsere: "05E7 05B5", qoftserehebrew: "05E7 05B5", - qparen: "24AC", - quarternote: "2669", - qubuts: "05BB", - qubuts18: "05BB", - qubuts25: "05BB", - qubuts31: "05BB", - qubutshebrew: "05BB", - qubutsnarrowhebrew: "05BB", - qubutsquarterhebrew: "05BB", - qubutswidehebrew: "05BB", - question: "003F", - questionarabic: "061F", - questionarmenian: "055E", - questiondown: "00BF", - questiondownsmall: "F7BF", - questiongreek: "037E", - questionmonospace: "FF1F", - questionsmall: "F73F", - quotedbl: "0022", - quotedblbase: "201E", - quotedblleft: "201C", - quotedblmonospace: "FF02", - quotedblprime: "301E", - quotedblprimereversed: "301D", - quotedblright: "201D", - quoteleft: "2018", - quoteleftreversed: "201B", - quotereversed: "201B", - quoteright: "2019", - quoterightn: "0149", - quotesinglbase: "201A", - quotesingle: "0027", - quotesinglemonospace: "FF07", - r: "0072", - raarmenian: "057C", - rabengali: "09B0", - racute: "0155", - radeva: "0930", - radical: "221A", - radicalex: "F8E5", - radoverssquare: "33AE", - radoverssquaredsquare: "33AF", - radsquare: "33AD", - rafe: "05BF", - rafehebrew: "05BF", - ragujarati: "0AB0", - ragurmukhi: "0A30", - rahiragana: "3089", - rakatakana: "30E9", - rakatakanahalfwidth: "FF97", - ralowerdiagonalbengali: "09F1", - ramiddlediagonalbengali: "09F0", - ramshorn: "0264", - ratio: "2236", - rbopomofo: "3116", - rcaron: "0159", - rcedilla: "0157", - rcircle: "24E1", - rcommaaccent: "0157", - rdblgrave: "0211", - rdotaccent: "1E59", - rdotbelow: "1E5B", - rdotbelowmacron: "1E5D", - referencemark: "203B", - reflexsubset: "2286", - reflexsuperset: "2287", - registered: "00AE", - registersans: "F8E8", - registerserif: "F6DA", - reharabic: "0631", - reharmenian: "0580", - rehfinalarabic: "FEAE", - rehiragana: "308C", + qparen: 0x24AC, + quarternote: 0x2669, + qubuts: 0x05BB, + qubuts18: 0x05BB, + qubuts25: 0x05BB, + qubuts31: 0x05BB, + qubutshebrew: 0x05BB, + qubutsnarrowhebrew: 0x05BB, + qubutsquarterhebrew: 0x05BB, + qubutswidehebrew: 0x05BB, + question: 0x003F, + questionarabic: 0x061F, + questionarmenian: 0x055E, + questiondown: 0x00BF, + questiondownsmall: 0xF7BF, + questiongreek: 0x037E, + questionmonospace: 0xFF1F, + questionsmall: 0xF73F, + quotedbl: 0x0022, + quotedblbase: 0x201E, + quotedblleft: 0x201C, + quotedblmonospace: 0xFF02, + quotedblprime: 0x301E, + quotedblprimereversed: 0x301D, + quotedblright: 0x201D, + quoteleft: 0x2018, + quoteleftreversed: 0x201B, + quotereversed: 0x201B, + quoteright: 0x2019, + quoterightn: 0x0149, + quotesinglbase: 0x201A, + quotesingle: 0x0027, + quotesinglemonospace: 0xFF07, + r: 0x0072, + raarmenian: 0x057C, + rabengali: 0x09B0, + racute: 0x0155, + radeva: 0x0930, + radical: 0x221A, + radicalex: 0xF8E5, + radoverssquare: 0x33AE, + radoverssquaredsquare: 0x33AF, + radsquare: 0x33AD, + rafe: 0x05BF, + rafehebrew: 0x05BF, + ragujarati: 0x0AB0, + ragurmukhi: 0x0A30, + rahiragana: 0x3089, + rakatakana: 0x30E9, + rakatakanahalfwidth: 0xFF97, + ralowerdiagonalbengali: 0x09F1, + ramiddlediagonalbengali: 0x09F0, + ramshorn: 0x0264, + ratio: 0x2236, + rbopomofo: 0x3116, + rcaron: 0x0159, + rcedilla: 0x0157, + rcircle: 0x24E1, + rcommaaccent: 0x0157, + rdblgrave: 0x0211, + rdotaccent: 0x1E59, + rdotbelow: 0x1E5B, + rdotbelowmacron: 0x1E5D, + referencemark: 0x203B, + reflexsubset: 0x2286, + reflexsuperset: 0x2287, + registered: 0x00AE, + registersans: 0xF8E8, + registerserif: 0xF6DA, + reharabic: 0x0631, + reharmenian: 0x0580, + rehfinalarabic: 0xFEAE, + rehiragana: 0x308C, rehyehaleflamarabic: "0631 FEF3 FE8E 0644", - rekatakana: "30EC", - rekatakanahalfwidth: "FF9A", - resh: "05E8", - reshdageshhebrew: "FB48", + rekatakana: 0x30EC, + rekatakanahalfwidth: 0xFF9A, + resh: 0x05E8, + reshdageshhebrew: 0xFB48, reshhatafpatah: "05E8 05B2", reshhatafpatahhebrew: "05E8 05B2", reshhatafsegol: "05E8 05B1", reshhatafsegolhebrew: "05E8 05B1", - reshhebrew: "05E8", + reshhebrew: 0x05E8, reshhiriq: "05E8 05B4", reshhiriqhebrew: "05E8 05B4", reshholam: "05E8 05B9", @@ -3271,1019 +3271,1019 @@ var GlyphsUnicode = { reshshevahebrew: "05E8 05B0", reshtsere: "05E8 05B5", reshtserehebrew: "05E8 05B5", - reversedtilde: "223D", - reviahebrew: "0597", - reviamugrashhebrew: "0597", - revlogicalnot: "2310", - rfishhook: "027E", - rfishhookreversed: "027F", - rhabengali: "09DD", - rhadeva: "095D", - rho: "03C1", - rhook: "027D", - rhookturned: "027B", - rhookturnedsuperior: "02B5", - rhosymbolgreek: "03F1", - rhotichookmod: "02DE", - rieulacirclekorean: "3271", - rieulaparenkorean: "3211", - rieulcirclekorean: "3263", - rieulhieuhkorean: "3140", - rieulkiyeokkorean: "313A", - rieulkiyeoksioskorean: "3169", - rieulkorean: "3139", - rieulmieumkorean: "313B", - rieulpansioskorean: "316C", - rieulparenkorean: "3203", - rieulphieuphkorean: "313F", - rieulpieupkorean: "313C", - rieulpieupsioskorean: "316B", - rieulsioskorean: "313D", - rieulthieuthkorean: "313E", - rieultikeutkorean: "316A", - rieulyeorinhieuhkorean: "316D", - rightangle: "221F", - righttackbelowcmb: "0319", - righttriangle: "22BF", - rihiragana: "308A", - rikatakana: "30EA", - rikatakanahalfwidth: "FF98", - ring: "02DA", - ringbelowcmb: "0325", - ringcmb: "030A", - ringhalfleft: "02BF", - ringhalfleftarmenian: "0559", - ringhalfleftbelowcmb: "031C", - ringhalfleftcentered: "02D3", - ringhalfright: "02BE", - ringhalfrightbelowcmb: "0339", - ringhalfrightcentered: "02D2", - rinvertedbreve: "0213", - rittorusquare: "3351", - rlinebelow: "1E5F", - rlongleg: "027C", - rlonglegturned: "027A", - rmonospace: "FF52", - rohiragana: "308D", - rokatakana: "30ED", - rokatakanahalfwidth: "FF9B", - roruathai: "0E23", - rparen: "24AD", - rrabengali: "09DC", - rradeva: "0931", - rragurmukhi: "0A5C", - rreharabic: "0691", - rrehfinalarabic: "FB8D", - rrvocalicbengali: "09E0", - rrvocalicdeva: "0960", - rrvocalicgujarati: "0AE0", - rrvocalicvowelsignbengali: "09C4", - rrvocalicvowelsigndeva: "0944", - rrvocalicvowelsigngujarati: "0AC4", - rsuperior: "F6F1", - rtblock: "2590", - rturned: "0279", - rturnedsuperior: "02B4", - ruhiragana: "308B", - rukatakana: "30EB", - rukatakanahalfwidth: "FF99", - rupeemarkbengali: "09F2", - rupeesignbengali: "09F3", - rupiah: "F6DD", - ruthai: "0E24", - rvocalicbengali: "098B", - rvocalicdeva: "090B", - rvocalicgujarati: "0A8B", - rvocalicvowelsignbengali: "09C3", - rvocalicvowelsigndeva: "0943", - rvocalicvowelsigngujarati: "0AC3", - s: "0073", - sabengali: "09B8", - sacute: "015B", - sacutedotaccent: "1E65", - sadarabic: "0635", - sadeva: "0938", - sadfinalarabic: "FEBA", - sadinitialarabic: "FEBB", - sadmedialarabic: "FEBC", - sagujarati: "0AB8", - sagurmukhi: "0A38", - sahiragana: "3055", - sakatakana: "30B5", - sakatakanahalfwidth: "FF7B", - sallallahoualayhewasallamarabic: "FDFA", - samekh: "05E1", - samekhdagesh: "FB41", - samekhdageshhebrew: "FB41", - samekhhebrew: "05E1", - saraaathai: "0E32", - saraaethai: "0E41", - saraaimaimalaithai: "0E44", - saraaimaimuanthai: "0E43", - saraamthai: "0E33", - saraathai: "0E30", - saraethai: "0E40", - saraiileftthai: "F886", - saraiithai: "0E35", - saraileftthai: "F885", - saraithai: "0E34", - saraothai: "0E42", - saraueeleftthai: "F888", - saraueethai: "0E37", - saraueleftthai: "F887", - sarauethai: "0E36", - sarauthai: "0E38", - sarauuthai: "0E39", - sbopomofo: "3119", - scaron: "0161", - scarondotaccent: "1E67", - scedilla: "015F", - schwa: "0259", - schwacyrillic: "04D9", - schwadieresiscyrillic: "04DB", - schwahook: "025A", - scircle: "24E2", - scircumflex: "015D", - scommaaccent: "0219", - sdotaccent: "1E61", - sdotbelow: "1E63", - sdotbelowdotaccent: "1E69", - seagullbelowcmb: "033C", - second: "2033", - secondtonechinese: "02CA", - section: "00A7", - seenarabic: "0633", - seenfinalarabic: "FEB2", - seeninitialarabic: "FEB3", - seenmedialarabic: "FEB4", - segol: "05B6", - segol13: "05B6", - segol1f: "05B6", - segol2c: "05B6", - segolhebrew: "05B6", - segolnarrowhebrew: "05B6", - segolquarterhebrew: "05B6", - segoltahebrew: "0592", - segolwidehebrew: "05B6", - seharmenian: "057D", - sehiragana: "305B", - sekatakana: "30BB", - sekatakanahalfwidth: "FF7E", - semicolon: "003B", - semicolonarabic: "061B", - semicolonmonospace: "FF1B", - semicolonsmall: "FE54", - semivoicedmarkkana: "309C", - semivoicedmarkkanahalfwidth: "FF9F", - sentisquare: "3322", - sentosquare: "3323", - seven: "0037", - sevenarabic: "0667", - sevenbengali: "09ED", - sevencircle: "2466", - sevencircleinversesansserif: "2790", - sevendeva: "096D", - seveneighths: "215E", - sevengujarati: "0AED", - sevengurmukhi: "0A6D", - sevenhackarabic: "0667", - sevenhangzhou: "3027", - sevenideographicparen: "3226", - seveninferior: "2087", - sevenmonospace: "FF17", - sevenoldstyle: "F737", - sevenparen: "247A", - sevenperiod: "248E", - sevenpersian: "06F7", - sevenroman: "2176", - sevensuperior: "2077", - seventeencircle: "2470", - seventeenparen: "2484", - seventeenperiod: "2498", - seventhai: "0E57", - sfthyphen: "00AD", - shaarmenian: "0577", - shabengali: "09B6", - shacyrillic: "0448", - shaddaarabic: "0651", - shaddadammaarabic: "FC61", - shaddadammatanarabic: "FC5E", - shaddafathaarabic: "FC60", + reversedtilde: 0x223D, + reviahebrew: 0x0597, + reviamugrashhebrew: 0x0597, + revlogicalnot: 0x2310, + rfishhook: 0x027E, + rfishhookreversed: 0x027F, + rhabengali: 0x09DD, + rhadeva: 0x095D, + rho: 0x03C1, + rhook: 0x027D, + rhookturned: 0x027B, + rhookturnedsuperior: 0x02B5, + rhosymbolgreek: 0x03F1, + rhotichookmod: 0x02DE, + rieulacirclekorean: 0x3271, + rieulaparenkorean: 0x3211, + rieulcirclekorean: 0x3263, + rieulhieuhkorean: 0x3140, + rieulkiyeokkorean: 0x313A, + rieulkiyeoksioskorean: 0x3169, + rieulkorean: 0x3139, + rieulmieumkorean: 0x313B, + rieulpansioskorean: 0x316C, + rieulparenkorean: 0x3203, + rieulphieuphkorean: 0x313F, + rieulpieupkorean: 0x313C, + rieulpieupsioskorean: 0x316B, + rieulsioskorean: 0x313D, + rieulthieuthkorean: 0x313E, + rieultikeutkorean: 0x316A, + rieulyeorinhieuhkorean: 0x316D, + rightangle: 0x221F, + righttackbelowcmb: 0x0319, + righttriangle: 0x22BF, + rihiragana: 0x308A, + rikatakana: 0x30EA, + rikatakanahalfwidth: 0xFF98, + ring: 0x02DA, + ringbelowcmb: 0x0325, + ringcmb: 0x030A, + ringhalfleft: 0x02BF, + ringhalfleftarmenian: 0x0559, + ringhalfleftbelowcmb: 0x031C, + ringhalfleftcentered: 0x02D3, + ringhalfright: 0x02BE, + ringhalfrightbelowcmb: 0x0339, + ringhalfrightcentered: 0x02D2, + rinvertedbreve: 0x0213, + rittorusquare: 0x3351, + rlinebelow: 0x1E5F, + rlongleg: 0x027C, + rlonglegturned: 0x027A, + rmonospace: 0xFF52, + rohiragana: 0x308D, + rokatakana: 0x30ED, + rokatakanahalfwidth: 0xFF9B, + roruathai: 0x0E23, + rparen: 0x24AD, + rrabengali: 0x09DC, + rradeva: 0x0931, + rragurmukhi: 0x0A5C, + rreharabic: 0x0691, + rrehfinalarabic: 0xFB8D, + rrvocalicbengali: 0x09E0, + rrvocalicdeva: 0x0960, + rrvocalicgujarati: 0x0AE0, + rrvocalicvowelsignbengali: 0x09C4, + rrvocalicvowelsigndeva: 0x0944, + rrvocalicvowelsigngujarati: 0x0AC4, + rsuperior: 0xF6F1, + rtblock: 0x2590, + rturned: 0x0279, + rturnedsuperior: 0x02B4, + ruhiragana: 0x308B, + rukatakana: 0x30EB, + rukatakanahalfwidth: 0xFF99, + rupeemarkbengali: 0x09F2, + rupeesignbengali: 0x09F3, + rupiah: 0xF6DD, + ruthai: 0x0E24, + rvocalicbengali: 0x098B, + rvocalicdeva: 0x090B, + rvocalicgujarati: 0x0A8B, + rvocalicvowelsignbengali: 0x09C3, + rvocalicvowelsigndeva: 0x0943, + rvocalicvowelsigngujarati: 0x0AC3, + s: 0x0073, + sabengali: 0x09B8, + sacute: 0x015B, + sacutedotaccent: 0x1E65, + sadarabic: 0x0635, + sadeva: 0x0938, + sadfinalarabic: 0xFEBA, + sadinitialarabic: 0xFEBB, + sadmedialarabic: 0xFEBC, + sagujarati: 0x0AB8, + sagurmukhi: 0x0A38, + sahiragana: 0x3055, + sakatakana: 0x30B5, + sakatakanahalfwidth: 0xFF7B, + sallallahoualayhewasallamarabic: 0xFDFA, + samekh: 0x05E1, + samekhdagesh: 0xFB41, + samekhdageshhebrew: 0xFB41, + samekhhebrew: 0x05E1, + saraaathai: 0x0E32, + saraaethai: 0x0E41, + saraaimaimalaithai: 0x0E44, + saraaimaimuanthai: 0x0E43, + saraamthai: 0x0E33, + saraathai: 0x0E30, + saraethai: 0x0E40, + saraiileftthai: 0xF886, + saraiithai: 0x0E35, + saraileftthai: 0xF885, + saraithai: 0x0E34, + saraothai: 0x0E42, + saraueeleftthai: 0xF888, + saraueethai: 0x0E37, + saraueleftthai: 0xF887, + sarauethai: 0x0E36, + sarauthai: 0x0E38, + sarauuthai: 0x0E39, + sbopomofo: 0x3119, + scaron: 0x0161, + scarondotaccent: 0x1E67, + scedilla: 0x015F, + schwa: 0x0259, + schwacyrillic: 0x04D9, + schwadieresiscyrillic: 0x04DB, + schwahook: 0x025A, + scircle: 0x24E2, + scircumflex: 0x015D, + scommaaccent: 0x0219, + sdotaccent: 0x1E61, + sdotbelow: 0x1E63, + sdotbelowdotaccent: 0x1E69, + seagullbelowcmb: 0x033C, + second: 0x2033, + secondtonechinese: 0x02CA, + section: 0x00A7, + seenarabic: 0x0633, + seenfinalarabic: 0xFEB2, + seeninitialarabic: 0xFEB3, + seenmedialarabic: 0xFEB4, + segol: 0x05B6, + segol13: 0x05B6, + segol1f: 0x05B6, + segol2c: 0x05B6, + segolhebrew: 0x05B6, + segolnarrowhebrew: 0x05B6, + segolquarterhebrew: 0x05B6, + segoltahebrew: 0x0592, + segolwidehebrew: 0x05B6, + seharmenian: 0x057D, + sehiragana: 0x305B, + sekatakana: 0x30BB, + sekatakanahalfwidth: 0xFF7E, + semicolon: 0x003B, + semicolonarabic: 0x061B, + semicolonmonospace: 0xFF1B, + semicolonsmall: 0xFE54, + semivoicedmarkkana: 0x309C, + semivoicedmarkkanahalfwidth: 0xFF9F, + sentisquare: 0x3322, + sentosquare: 0x3323, + seven: 0x0037, + sevenarabic: 0x0667, + sevenbengali: 0x09ED, + sevencircle: 0x2466, + sevencircleinversesansserif: 0x2790, + sevendeva: 0x096D, + seveneighths: 0x215E, + sevengujarati: 0x0AED, + sevengurmukhi: 0x0A6D, + sevenhackarabic: 0x0667, + sevenhangzhou: 0x3027, + sevenideographicparen: 0x3226, + seveninferior: 0x2087, + sevenmonospace: 0xFF17, + sevenoldstyle: 0xF737, + sevenparen: 0x247A, + sevenperiod: 0x248E, + sevenpersian: 0x06F7, + sevenroman: 0x2176, + sevensuperior: 0x2077, + seventeencircle: 0x2470, + seventeenparen: 0x2484, + seventeenperiod: 0x2498, + seventhai: 0x0E57, + sfthyphen: 0x00AD, + shaarmenian: 0x0577, + shabengali: 0x09B6, + shacyrillic: 0x0448, + shaddaarabic: 0x0651, + shaddadammaarabic: 0xFC61, + shaddadammatanarabic: 0xFC5E, + shaddafathaarabic: 0xFC60, shaddafathatanarabic: "0651 064B", - shaddakasraarabic: "FC62", - shaddakasratanarabic: "FC5F", - shade: "2592", - shadedark: "2593", - shadelight: "2591", - shademedium: "2592", - shadeva: "0936", - shagujarati: "0AB6", - shagurmukhi: "0A36", - shalshelethebrew: "0593", - shbopomofo: "3115", - shchacyrillic: "0449", - sheenarabic: "0634", - sheenfinalarabic: "FEB6", - sheeninitialarabic: "FEB7", - sheenmedialarabic: "FEB8", - sheicoptic: "03E3", - sheqel: "20AA", - sheqelhebrew: "20AA", - sheva: "05B0", - sheva115: "05B0", - sheva15: "05B0", - sheva22: "05B0", - sheva2e: "05B0", - shevahebrew: "05B0", - shevanarrowhebrew: "05B0", - shevaquarterhebrew: "05B0", - shevawidehebrew: "05B0", - shhacyrillic: "04BB", - shimacoptic: "03ED", - shin: "05E9", - shindagesh: "FB49", - shindageshhebrew: "FB49", - shindageshshindot: "FB2C", - shindageshshindothebrew: "FB2C", - shindageshsindot: "FB2D", - shindageshsindothebrew: "FB2D", - shindothebrew: "05C1", - shinhebrew: "05E9", - shinshindot: "FB2A", - shinshindothebrew: "FB2A", - shinsindot: "FB2B", - shinsindothebrew: "FB2B", - shook: "0282", - sigma: "03C3", - sigma1: "03C2", - sigmafinal: "03C2", - sigmalunatesymbolgreek: "03F2", - sihiragana: "3057", - sikatakana: "30B7", - sikatakanahalfwidth: "FF7C", - siluqhebrew: "05BD", - siluqlefthebrew: "05BD", - similar: "223C", - sindothebrew: "05C2", - siosacirclekorean: "3274", - siosaparenkorean: "3214", - sioscieuckorean: "317E", - sioscirclekorean: "3266", - sioskiyeokkorean: "317A", - sioskorean: "3145", - siosnieunkorean: "317B", - siosparenkorean: "3206", - siospieupkorean: "317D", - siostikeutkorean: "317C", - six: "0036", - sixarabic: "0666", - sixbengali: "09EC", - sixcircle: "2465", - sixcircleinversesansserif: "278F", - sixdeva: "096C", - sixgujarati: "0AEC", - sixgurmukhi: "0A6C", - sixhackarabic: "0666", - sixhangzhou: "3026", - sixideographicparen: "3225", - sixinferior: "2086", - sixmonospace: "FF16", - sixoldstyle: "F736", - sixparen: "2479", - sixperiod: "248D", - sixpersian: "06F6", - sixroman: "2175", - sixsuperior: "2076", - sixteencircle: "246F", - sixteencurrencydenominatorbengali: "09F9", - sixteenparen: "2483", - sixteenperiod: "2497", - sixthai: "0E56", - slash: "002F", - slashmonospace: "FF0F", - slong: "017F", - slongdotaccent: "1E9B", - smileface: "263A", - smonospace: "FF53", - sofpasuqhebrew: "05C3", - softhyphen: "00AD", - softsigncyrillic: "044C", - sohiragana: "305D", - sokatakana: "30BD", - sokatakanahalfwidth: "FF7F", - soliduslongoverlaycmb: "0338", - solidusshortoverlaycmb: "0337", - sorusithai: "0E29", - sosalathai: "0E28", - sosothai: "0E0B", - sosuathai: "0E2A", - space: "0020", - spacehackarabic: "0020", - spade: "2660", - spadesuitblack: "2660", - spadesuitwhite: "2664", - sparen: "24AE", - squarebelowcmb: "033B", - squarecc: "33C4", - squarecm: "339D", - squarediagonalcrosshatchfill: "25A9", - squarehorizontalfill: "25A4", - squarekg: "338F", - squarekm: "339E", - squarekmcapital: "33CE", - squareln: "33D1", - squarelog: "33D2", - squaremg: "338E", - squaremil: "33D5", - squaremm: "339C", - squaremsquared: "33A1", - squareorthogonalcrosshatchfill: "25A6", - squareupperlefttolowerrightfill: "25A7", - squareupperrighttolowerleftfill: "25A8", - squareverticalfill: "25A5", - squarewhitewithsmallblack: "25A3", - srsquare: "33DB", - ssabengali: "09B7", - ssadeva: "0937", - ssagujarati: "0AB7", - ssangcieuckorean: "3149", - ssanghieuhkorean: "3185", - ssangieungkorean: "3180", - ssangkiyeokkorean: "3132", - ssangnieunkorean: "3165", - ssangpieupkorean: "3143", - ssangsioskorean: "3146", - ssangtikeutkorean: "3138", - ssuperior: "F6F2", - sterling: "00A3", - sterlingmonospace: "FFE1", - strokelongoverlaycmb: "0336", - strokeshortoverlaycmb: "0335", - subset: "2282", - subsetnotequal: "228A", - subsetorequal: "2286", - succeeds: "227B", - suchthat: "220B", - suhiragana: "3059", - sukatakana: "30B9", - sukatakanahalfwidth: "FF7D", - sukunarabic: "0652", - summation: "2211", - sun: "263C", - superset: "2283", - supersetnotequal: "228B", - supersetorequal: "2287", - svsquare: "33DC", - syouwaerasquare: "337C", - t: "0074", - tabengali: "09A4", - tackdown: "22A4", - tackleft: "22A3", - tadeva: "0924", - tagujarati: "0AA4", - tagurmukhi: "0A24", - taharabic: "0637", - tahfinalarabic: "FEC2", - tahinitialarabic: "FEC3", - tahiragana: "305F", - tahmedialarabic: "FEC4", - taisyouerasquare: "337D", - takatakana: "30BF", - takatakanahalfwidth: "FF80", - tatweelarabic: "0640", - tau: "03C4", - tav: "05EA", - tavdages: "FB4A", - tavdagesh: "FB4A", - tavdageshhebrew: "FB4A", - tavhebrew: "05EA", - tbar: "0167", - tbopomofo: "310A", - tcaron: "0165", - tccurl: "02A8", - tcedilla: "0163", - tcheharabic: "0686", - tchehfinalarabic: "FB7B", - tchehinitialarabic: "FB7C", - tchehmedialarabic: "FB7D", + shaddakasraarabic: 0xFC62, + shaddakasratanarabic: 0xFC5F, + shade: 0x2592, + shadedark: 0x2593, + shadelight: 0x2591, + shademedium: 0x2592, + shadeva: 0x0936, + shagujarati: 0x0AB6, + shagurmukhi: 0x0A36, + shalshelethebrew: 0x0593, + shbopomofo: 0x3115, + shchacyrillic: 0x0449, + sheenarabic: 0x0634, + sheenfinalarabic: 0xFEB6, + sheeninitialarabic: 0xFEB7, + sheenmedialarabic: 0xFEB8, + sheicoptic: 0x03E3, + sheqel: 0x20AA, + sheqelhebrew: 0x20AA, + sheva: 0x05B0, + sheva115: 0x05B0, + sheva15: 0x05B0, + sheva22: 0x05B0, + sheva2e: 0x05B0, + shevahebrew: 0x05B0, + shevanarrowhebrew: 0x05B0, + shevaquarterhebrew: 0x05B0, + shevawidehebrew: 0x05B0, + shhacyrillic: 0x04BB, + shimacoptic: 0x03ED, + shin: 0x05E9, + shindagesh: 0xFB49, + shindageshhebrew: 0xFB49, + shindageshshindot: 0xFB2C, + shindageshshindothebrew: 0xFB2C, + shindageshsindot: 0xFB2D, + shindageshsindothebrew: 0xFB2D, + shindothebrew: 0x05C1, + shinhebrew: 0x05E9, + shinshindot: 0xFB2A, + shinshindothebrew: 0xFB2A, + shinsindot: 0xFB2B, + shinsindothebrew: 0xFB2B, + shook: 0x0282, + sigma: 0x03C3, + sigma1: 0x03C2, + sigmafinal: 0x03C2, + sigmalunatesymbolgreek: 0x03F2, + sihiragana: 0x3057, + sikatakana: 0x30B7, + sikatakanahalfwidth: 0xFF7C, + siluqhebrew: 0x05BD, + siluqlefthebrew: 0x05BD, + similar: 0x223C, + sindothebrew: 0x05C2, + siosacirclekorean: 0x3274, + siosaparenkorean: 0x3214, + sioscieuckorean: 0x317E, + sioscirclekorean: 0x3266, + sioskiyeokkorean: 0x317A, + sioskorean: 0x3145, + siosnieunkorean: 0x317B, + siosparenkorean: 0x3206, + siospieupkorean: 0x317D, + siostikeutkorean: 0x317C, + six: 0x0036, + sixarabic: 0x0666, + sixbengali: 0x09EC, + sixcircle: 0x2465, + sixcircleinversesansserif: 0x278F, + sixdeva: 0x096C, + sixgujarati: 0x0AEC, + sixgurmukhi: 0x0A6C, + sixhackarabic: 0x0666, + sixhangzhou: 0x3026, + sixideographicparen: 0x3225, + sixinferior: 0x2086, + sixmonospace: 0xFF16, + sixoldstyle: 0xF736, + sixparen: 0x2479, + sixperiod: 0x248D, + sixpersian: 0x06F6, + sixroman: 0x2175, + sixsuperior: 0x2076, + sixteencircle: 0x246F, + sixteencurrencydenominatorbengali: 0x09F9, + sixteenparen: 0x2483, + sixteenperiod: 0x2497, + sixthai: 0x0E56, + slash: 0x002F, + slashmonospace: 0xFF0F, + slong: 0x017F, + slongdotaccent: 0x1E9B, + smileface: 0x263A, + smonospace: 0xFF53, + sofpasuqhebrew: 0x05C3, + softhyphen: 0x00AD, + softsigncyrillic: 0x044C, + sohiragana: 0x305D, + sokatakana: 0x30BD, + sokatakanahalfwidth: 0xFF7F, + soliduslongoverlaycmb: 0x0338, + solidusshortoverlaycmb: 0x0337, + sorusithai: 0x0E29, + sosalathai: 0x0E28, + sosothai: 0x0E0B, + sosuathai: 0x0E2A, + space: 0x0020, + spacehackarabic: 0x0020, + spade: 0x2660, + spadesuitblack: 0x2660, + spadesuitwhite: 0x2664, + sparen: 0x24AE, + squarebelowcmb: 0x033B, + squarecc: 0x33C4, + squarecm: 0x339D, + squarediagonalcrosshatchfill: 0x25A9, + squarehorizontalfill: 0x25A4, + squarekg: 0x338F, + squarekm: 0x339E, + squarekmcapital: 0x33CE, + squareln: 0x33D1, + squarelog: 0x33D2, + squaremg: 0x338E, + squaremil: 0x33D5, + squaremm: 0x339C, + squaremsquared: 0x33A1, + squareorthogonalcrosshatchfill: 0x25A6, + squareupperlefttolowerrightfill: 0x25A7, + squareupperrighttolowerleftfill: 0x25A8, + squareverticalfill: 0x25A5, + squarewhitewithsmallblack: 0x25A3, + srsquare: 0x33DB, + ssabengali: 0x09B7, + ssadeva: 0x0937, + ssagujarati: 0x0AB7, + ssangcieuckorean: 0x3149, + ssanghieuhkorean: 0x3185, + ssangieungkorean: 0x3180, + ssangkiyeokkorean: 0x3132, + ssangnieunkorean: 0x3165, + ssangpieupkorean: 0x3143, + ssangsioskorean: 0x3146, + ssangtikeutkorean: 0x3138, + ssuperior: 0xF6F2, + sterling: 0x00A3, + sterlingmonospace: 0xFFE1, + strokelongoverlaycmb: 0x0336, + strokeshortoverlaycmb: 0x0335, + subset: 0x2282, + subsetnotequal: 0x228A, + subsetorequal: 0x2286, + succeeds: 0x227B, + suchthat: 0x220B, + suhiragana: 0x3059, + sukatakana: 0x30B9, + sukatakanahalfwidth: 0xFF7D, + sukunarabic: 0x0652, + summation: 0x2211, + sun: 0x263C, + superset: 0x2283, + supersetnotequal: 0x228B, + supersetorequal: 0x2287, + svsquare: 0x33DC, + syouwaerasquare: 0x337C, + t: 0x0074, + tabengali: 0x09A4, + tackdown: 0x22A4, + tackleft: 0x22A3, + tadeva: 0x0924, + tagujarati: 0x0AA4, + tagurmukhi: 0x0A24, + taharabic: 0x0637, + tahfinalarabic: 0xFEC2, + tahinitialarabic: 0xFEC3, + tahiragana: 0x305F, + tahmedialarabic: 0xFEC4, + taisyouerasquare: 0x337D, + takatakana: 0x30BF, + takatakanahalfwidth: 0xFF80, + tatweelarabic: 0x0640, + tau: 0x03C4, + tav: 0x05EA, + tavdages: 0xFB4A, + tavdagesh: 0xFB4A, + tavdageshhebrew: 0xFB4A, + tavhebrew: 0x05EA, + tbar: 0x0167, + tbopomofo: 0x310A, + tcaron: 0x0165, + tccurl: 0x02A8, + tcedilla: 0x0163, + tcheharabic: 0x0686, + tchehfinalarabic: 0xFB7B, + tchehinitialarabic: 0xFB7C, + tchehmedialarabic: 0xFB7D, tchehmeeminitialarabic: "FB7C FEE4", - tcircle: "24E3", - tcircumflexbelow: "1E71", - tcommaaccent: "0163", - tdieresis: "1E97", - tdotaccent: "1E6B", - tdotbelow: "1E6D", - tecyrillic: "0442", - tedescendercyrillic: "04AD", - teharabic: "062A", - tehfinalarabic: "FE96", - tehhahinitialarabic: "FCA2", - tehhahisolatedarabic: "FC0C", - tehinitialarabic: "FE97", - tehiragana: "3066", - tehjeeminitialarabic: "FCA1", - tehjeemisolatedarabic: "FC0B", - tehmarbutaarabic: "0629", - tehmarbutafinalarabic: "FE94", - tehmedialarabic: "FE98", - tehmeeminitialarabic: "FCA4", - tehmeemisolatedarabic: "FC0E", - tehnoonfinalarabic: "FC73", - tekatakana: "30C6", - tekatakanahalfwidth: "FF83", - telephone: "2121", - telephoneblack: "260E", - telishagedolahebrew: "05A0", - telishaqetanahebrew: "05A9", - tencircle: "2469", - tenideographicparen: "3229", - tenparen: "247D", - tenperiod: "2491", - tenroman: "2179", - tesh: "02A7", - tet: "05D8", - tetdagesh: "FB38", - tetdageshhebrew: "FB38", - tethebrew: "05D8", - tetsecyrillic: "04B5", - tevirhebrew: "059B", - tevirlefthebrew: "059B", - thabengali: "09A5", - thadeva: "0925", - thagujarati: "0AA5", - thagurmukhi: "0A25", - thalarabic: "0630", - thalfinalarabic: "FEAC", - thanthakhatlowleftthai: "F898", - thanthakhatlowrightthai: "F897", - thanthakhatthai: "0E4C", - thanthakhatupperleftthai: "F896", - theharabic: "062B", - thehfinalarabic: "FE9A", - thehinitialarabic: "FE9B", - thehmedialarabic: "FE9C", - thereexists: "2203", - therefore: "2234", - theta: "03B8", - theta1: "03D1", - thetasymbolgreek: "03D1", - thieuthacirclekorean: "3279", - thieuthaparenkorean: "3219", - thieuthcirclekorean: "326B", - thieuthkorean: "314C", - thieuthparenkorean: "320B", - thirteencircle: "246C", - thirteenparen: "2480", - thirteenperiod: "2494", - thonangmonthothai: "0E11", - thook: "01AD", - thophuthaothai: "0E12", - thorn: "00FE", - thothahanthai: "0E17", - thothanthai: "0E10", - thothongthai: "0E18", - thothungthai: "0E16", - thousandcyrillic: "0482", - thousandsseparatorarabic: "066C", - thousandsseparatorpersian: "066C", - three: "0033", - threearabic: "0663", - threebengali: "09E9", - threecircle: "2462", - threecircleinversesansserif: "278C", - threedeva: "0969", - threeeighths: "215C", - threegujarati: "0AE9", - threegurmukhi: "0A69", - threehackarabic: "0663", - threehangzhou: "3023", - threeideographicparen: "3222", - threeinferior: "2083", - threemonospace: "FF13", - threenumeratorbengali: "09F6", - threeoldstyle: "F733", - threeparen: "2476", - threeperiod: "248A", - threepersian: "06F3", - threequarters: "00BE", - threequartersemdash: "F6DE", - threeroman: "2172", - threesuperior: "00B3", - threethai: "0E53", - thzsquare: "3394", - tihiragana: "3061", - tikatakana: "30C1", - tikatakanahalfwidth: "FF81", - tikeutacirclekorean: "3270", - tikeutaparenkorean: "3210", - tikeutcirclekorean: "3262", - tikeutkorean: "3137", - tikeutparenkorean: "3202", - tilde: "02DC", - tildebelowcmb: "0330", - tildecmb: "0303", - tildecomb: "0303", - tildedoublecmb: "0360", - tildeoperator: "223C", - tildeoverlaycmb: "0334", - tildeverticalcmb: "033E", - timescircle: "2297", - tipehahebrew: "0596", - tipehalefthebrew: "0596", - tippigurmukhi: "0A70", - titlocyrilliccmb: "0483", - tiwnarmenian: "057F", - tlinebelow: "1E6F", - tmonospace: "FF54", - toarmenian: "0569", - tohiragana: "3068", - tokatakana: "30C8", - tokatakanahalfwidth: "FF84", - tonebarextrahighmod: "02E5", - tonebarextralowmod: "02E9", - tonebarhighmod: "02E6", - tonebarlowmod: "02E8", - tonebarmidmod: "02E7", - tonefive: "01BD", - tonesix: "0185", - tonetwo: "01A8", - tonos: "0384", - tonsquare: "3327", - topatakthai: "0E0F", - tortoiseshellbracketleft: "3014", - tortoiseshellbracketleftsmall: "FE5D", - tortoiseshellbracketleftvertical: "FE39", - tortoiseshellbracketright: "3015", - tortoiseshellbracketrightsmall: "FE5E", - tortoiseshellbracketrightvertical: "FE3A", - totaothai: "0E15", - tpalatalhook: "01AB", - tparen: "24AF", - trademark: "2122", - trademarksans: "F8EA", - trademarkserif: "F6DB", - tretroflexhook: "0288", - triagdn: "25BC", - triaglf: "25C4", - triagrt: "25BA", - triagup: "25B2", - ts: "02A6", - tsadi: "05E6", - tsadidagesh: "FB46", - tsadidageshhebrew: "FB46", - tsadihebrew: "05E6", - tsecyrillic: "0446", - tsere: "05B5", - tsere12: "05B5", - tsere1e: "05B5", - tsere2b: "05B5", - tserehebrew: "05B5", - tserenarrowhebrew: "05B5", - tserequarterhebrew: "05B5", - tserewidehebrew: "05B5", - tshecyrillic: "045B", - tsuperior: "F6F3", - ttabengali: "099F", - ttadeva: "091F", - ttagujarati: "0A9F", - ttagurmukhi: "0A1F", - tteharabic: "0679", - ttehfinalarabic: "FB67", - ttehinitialarabic: "FB68", - ttehmedialarabic: "FB69", - tthabengali: "09A0", - tthadeva: "0920", - tthagujarati: "0AA0", - tthagurmukhi: "0A20", - tturned: "0287", - tuhiragana: "3064", - tukatakana: "30C4", - tukatakanahalfwidth: "FF82", - tusmallhiragana: "3063", - tusmallkatakana: "30C3", - tusmallkatakanahalfwidth: "FF6F", - twelvecircle: "246B", - twelveparen: "247F", - twelveperiod: "2493", - twelveroman: "217B", - twentycircle: "2473", - twentyhangzhou: "5344", - twentyparen: "2487", - twentyperiod: "249B", - two: "0032", - twoarabic: "0662", - twobengali: "09E8", - twocircle: "2461", - twocircleinversesansserif: "278B", - twodeva: "0968", - twodotenleader: "2025", - twodotleader: "2025", - twodotleadervertical: "FE30", - twogujarati: "0AE8", - twogurmukhi: "0A68", - twohackarabic: "0662", - twohangzhou: "3022", - twoideographicparen: "3221", - twoinferior: "2082", - twomonospace: "FF12", - twonumeratorbengali: "09F5", - twooldstyle: "F732", - twoparen: "2475", - twoperiod: "2489", - twopersian: "06F2", - tworoman: "2171", - twostroke: "01BB", - twosuperior: "00B2", - twothai: "0E52", - twothirds: "2154", - u: "0075", - uacute: "00FA", - ubar: "0289", - ubengali: "0989", - ubopomofo: "3128", - ubreve: "016D", - ucaron: "01D4", - ucircle: "24E4", - ucircumflex: "00FB", - ucircumflexbelow: "1E77", - ucyrillic: "0443", - udattadeva: "0951", - udblacute: "0171", - udblgrave: "0215", - udeva: "0909", - udieresis: "00FC", - udieresisacute: "01D8", - udieresisbelow: "1E73", - udieresiscaron: "01DA", - udieresiscyrillic: "04F1", - udieresisgrave: "01DC", - udieresismacron: "01D6", - udotbelow: "1EE5", - ugrave: "00F9", - ugujarati: "0A89", - ugurmukhi: "0A09", - uhiragana: "3046", - uhookabove: "1EE7", - uhorn: "01B0", - uhornacute: "1EE9", - uhorndotbelow: "1EF1", - uhorngrave: "1EEB", - uhornhookabove: "1EED", - uhorntilde: "1EEF", - uhungarumlaut: "0171", - uhungarumlautcyrillic: "04F3", - uinvertedbreve: "0217", - ukatakana: "30A6", - ukatakanahalfwidth: "FF73", - ukcyrillic: "0479", - ukorean: "315C", - umacron: "016B", - umacroncyrillic: "04EF", - umacrondieresis: "1E7B", - umatragurmukhi: "0A41", - umonospace: "FF55", - underscore: "005F", - underscoredbl: "2017", - underscoremonospace: "FF3F", - underscorevertical: "FE33", - underscorewavy: "FE4F", - union: "222A", - universal: "2200", - uogonek: "0173", - uparen: "24B0", - upblock: "2580", - upperdothebrew: "05C4", - upsilon: "03C5", - upsilondieresis: "03CB", - upsilondieresistonos: "03B0", - upsilonlatin: "028A", - upsilontonos: "03CD", - uptackbelowcmb: "031D", - uptackmod: "02D4", - uragurmukhi: "0A73", - uring: "016F", - ushortcyrillic: "045E", - usmallhiragana: "3045", - usmallkatakana: "30A5", - usmallkatakanahalfwidth: "FF69", - ustraightcyrillic: "04AF", - ustraightstrokecyrillic: "04B1", - utilde: "0169", - utildeacute: "1E79", - utildebelow: "1E75", - uubengali: "098A", - uudeva: "090A", - uugujarati: "0A8A", - uugurmukhi: "0A0A", - uumatragurmukhi: "0A42", - uuvowelsignbengali: "09C2", - uuvowelsigndeva: "0942", - uuvowelsigngujarati: "0AC2", - uvowelsignbengali: "09C1", - uvowelsigndeva: "0941", - uvowelsigngujarati: "0AC1", - v: "0076", - vadeva: "0935", - vagujarati: "0AB5", - vagurmukhi: "0A35", - vakatakana: "30F7", - vav: "05D5", - vavdagesh: "FB35", - vavdagesh65: "FB35", - vavdageshhebrew: "FB35", - vavhebrew: "05D5", - vavholam: "FB4B", - vavholamhebrew: "FB4B", - vavvavhebrew: "05F0", - vavyodhebrew: "05F1", - vcircle: "24E5", - vdotbelow: "1E7F", - vecyrillic: "0432", - veharabic: "06A4", - vehfinalarabic: "FB6B", - vehinitialarabic: "FB6C", - vehmedialarabic: "FB6D", - vekatakana: "30F9", - venus: "2640", - verticalbar: "007C", - verticallineabovecmb: "030D", - verticallinebelowcmb: "0329", - verticallinelowmod: "02CC", - verticallinemod: "02C8", - vewarmenian: "057E", - vhook: "028B", - vikatakana: "30F8", - viramabengali: "09CD", - viramadeva: "094D", - viramagujarati: "0ACD", - visargabengali: "0983", - visargadeva: "0903", - visargagujarati: "0A83", - vmonospace: "FF56", - voarmenian: "0578", - voicediterationhiragana: "309E", - voicediterationkatakana: "30FE", - voicedmarkkana: "309B", - voicedmarkkanahalfwidth: "FF9E", - vokatakana: "30FA", - vparen: "24B1", - vtilde: "1E7D", - vturned: "028C", - vuhiragana: "3094", - vukatakana: "30F4", - w: "0077", - wacute: "1E83", - waekorean: "3159", - wahiragana: "308F", - wakatakana: "30EF", - wakatakanahalfwidth: "FF9C", - wakorean: "3158", - wasmallhiragana: "308E", - wasmallkatakana: "30EE", - wattosquare: "3357", - wavedash: "301C", - wavyunderscorevertical: "FE34", - wawarabic: "0648", - wawfinalarabic: "FEEE", - wawhamzaabovearabic: "0624", - wawhamzaabovefinalarabic: "FE86", - wbsquare: "33DD", - wcircle: "24E6", - wcircumflex: "0175", - wdieresis: "1E85", - wdotaccent: "1E87", - wdotbelow: "1E89", - wehiragana: "3091", - weierstrass: "2118", - wekatakana: "30F1", - wekorean: "315E", - weokorean: "315D", - wgrave: "1E81", - whitebullet: "25E6", - whitecircle: "25CB", - whitecircleinverse: "25D9", - whitecornerbracketleft: "300E", - whitecornerbracketleftvertical: "FE43", - whitecornerbracketright: "300F", - whitecornerbracketrightvertical: "FE44", - whitediamond: "25C7", - whitediamondcontainingblacksmalldiamond: "25C8", - whitedownpointingsmalltriangle: "25BF", - whitedownpointingtriangle: "25BD", - whiteleftpointingsmalltriangle: "25C3", - whiteleftpointingtriangle: "25C1", - whitelenticularbracketleft: "3016", - whitelenticularbracketright: "3017", - whiterightpointingsmalltriangle: "25B9", - whiterightpointingtriangle: "25B7", - whitesmallsquare: "25AB", - whitesmilingface: "263A", - whitesquare: "25A1", - whitestar: "2606", - whitetelephone: "260F", - whitetortoiseshellbracketleft: "3018", - whitetortoiseshellbracketright: "3019", - whiteuppointingsmalltriangle: "25B5", - whiteuppointingtriangle: "25B3", - wihiragana: "3090", - wikatakana: "30F0", - wikorean: "315F", - wmonospace: "FF57", - wohiragana: "3092", - wokatakana: "30F2", - wokatakanahalfwidth: "FF66", - won: "20A9", - wonmonospace: "FFE6", - wowaenthai: "0E27", - wparen: "24B2", - wring: "1E98", - wsuperior: "02B7", - wturned: "028D", - wynn: "01BF", - x: "0078", - xabovecmb: "033D", - xbopomofo: "3112", - xcircle: "24E7", - xdieresis: "1E8D", - xdotaccent: "1E8B", - xeharmenian: "056D", - xi: "03BE", - xmonospace: "FF58", - xparen: "24B3", - xsuperior: "02E3", - y: "0079", - yaadosquare: "334E", - yabengali: "09AF", - yacute: "00FD", - yadeva: "092F", - yaekorean: "3152", - yagujarati: "0AAF", - yagurmukhi: "0A2F", - yahiragana: "3084", - yakatakana: "30E4", - yakatakanahalfwidth: "FF94", - yakorean: "3151", - yamakkanthai: "0E4E", - yasmallhiragana: "3083", - yasmallkatakana: "30E3", - yasmallkatakanahalfwidth: "FF6C", - yatcyrillic: "0463", - ycircle: "24E8", - ycircumflex: "0177", - ydieresis: "00FF", - ydotaccent: "1E8F", - ydotbelow: "1EF5", - yeharabic: "064A", - yehbarreearabic: "06D2", - yehbarreefinalarabic: "FBAF", - yehfinalarabic: "FEF2", - yehhamzaabovearabic: "0626", - yehhamzaabovefinalarabic: "FE8A", - yehhamzaaboveinitialarabic: "FE8B", - yehhamzaabovemedialarabic: "FE8C", - yehinitialarabic: "FEF3", - yehmedialarabic: "FEF4", - yehmeeminitialarabic: "FCDD", - yehmeemisolatedarabic: "FC58", - yehnoonfinalarabic: "FC94", - yehthreedotsbelowarabic: "06D1", - yekorean: "3156", - yen: "00A5", - yenmonospace: "FFE5", - yeokorean: "3155", - yeorinhieuhkorean: "3186", - yerahbenyomohebrew: "05AA", - yerahbenyomolefthebrew: "05AA", - yericyrillic: "044B", - yerudieresiscyrillic: "04F9", - yesieungkorean: "3181", - yesieungpansioskorean: "3183", - yesieungsioskorean: "3182", - yetivhebrew: "059A", - ygrave: "1EF3", - yhook: "01B4", - yhookabove: "1EF7", - yiarmenian: "0575", - yicyrillic: "0457", - yikorean: "3162", - yinyang: "262F", - yiwnarmenian: "0582", - ymonospace: "FF59", - yod: "05D9", - yoddagesh: "FB39", - yoddageshhebrew: "FB39", - yodhebrew: "05D9", - yodyodhebrew: "05F2", - yodyodpatahhebrew: "FB1F", - yohiragana: "3088", - yoikorean: "3189", - yokatakana: "30E8", - yokatakanahalfwidth: "FF96", - yokorean: "315B", - yosmallhiragana: "3087", - yosmallkatakana: "30E7", - yosmallkatakanahalfwidth: "FF6E", - yotgreek: "03F3", - yoyaekorean: "3188", - yoyakorean: "3187", - yoyakthai: "0E22", - yoyingthai: "0E0D", - yparen: "24B4", - ypogegrammeni: "037A", - ypogegrammenigreekcmb: "0345", - yr: "01A6", - yring: "1E99", - ysuperior: "02B8", - ytilde: "1EF9", - yturned: "028E", - yuhiragana: "3086", - yuikorean: "318C", - yukatakana: "30E6", - yukatakanahalfwidth: "FF95", - yukorean: "3160", - yusbigcyrillic: "046B", - yusbigiotifiedcyrillic: "046D", - yuslittlecyrillic: "0467", - yuslittleiotifiedcyrillic: "0469", - yusmallhiragana: "3085", - yusmallkatakana: "30E5", - yusmallkatakanahalfwidth: "FF6D", - yuyekorean: "318B", - yuyeokorean: "318A", - yyabengali: "09DF", - yyadeva: "095F", - z: "007A", - zaarmenian: "0566", - zacute: "017A", - zadeva: "095B", - zagurmukhi: "0A5B", - zaharabic: "0638", - zahfinalarabic: "FEC6", - zahinitialarabic: "FEC7", - zahiragana: "3056", - zahmedialarabic: "FEC8", - zainarabic: "0632", - zainfinalarabic: "FEB0", - zakatakana: "30B6", - zaqefgadolhebrew: "0595", - zaqefqatanhebrew: "0594", - zarqahebrew: "0598", - zayin: "05D6", - zayindagesh: "FB36", - zayindageshhebrew: "FB36", - zayinhebrew: "05D6", - zbopomofo: "3117", - zcaron: "017E", - zcircle: "24E9", - zcircumflex: "1E91", - zcurl: "0291", - zdot: "017C", - zdotaccent: "017C", - zdotbelow: "1E93", - zecyrillic: "0437", - zedescendercyrillic: "0499", - zedieresiscyrillic: "04DF", - zehiragana: "305C", - zekatakana: "30BC", - zero: "0030", - zeroarabic: "0660", - zerobengali: "09E6", - zerodeva: "0966", - zerogujarati: "0AE6", - zerogurmukhi: "0A66", - zerohackarabic: "0660", - zeroinferior: "2080", - zeromonospace: "FF10", - zerooldstyle: "F730", - zeropersian: "06F0", - zerosuperior: "2070", - zerothai: "0E50", - zerowidthjoiner: "FEFF", - zerowidthnonjoiner: "200C", - zerowidthspace: "200B", - zeta: "03B6", - zhbopomofo: "3113", - zhearmenian: "056A", - zhebrevecyrillic: "04C2", - zhecyrillic: "0436", - zhedescendercyrillic: "0497", - zhedieresiscyrillic: "04DD", - zihiragana: "3058", - zikatakana: "30B8", - zinorhebrew: "05AE", - zlinebelow: "1E95", - zmonospace: "FF5A", - zohiragana: "305E", - zokatakana: "30BE", - zparen: "24B5", - zretroflexhook: "0290", - zstroke: "01B6", - zuhiragana: "305A", - zukatakana: "30BA" + tcircle: 0x24E3, + tcircumflexbelow: 0x1E71, + tcommaaccent: 0x0163, + tdieresis: 0x1E97, + tdotaccent: 0x1E6B, + tdotbelow: 0x1E6D, + tecyrillic: 0x0442, + tedescendercyrillic: 0x04AD, + teharabic: 0x062A, + tehfinalarabic: 0xFE96, + tehhahinitialarabic: 0xFCA2, + tehhahisolatedarabic: 0xFC0C, + tehinitialarabic: 0xFE97, + tehiragana: 0x3066, + tehjeeminitialarabic: 0xFCA1, + tehjeemisolatedarabic: 0xFC0B, + tehmarbutaarabic: 0x0629, + tehmarbutafinalarabic: 0xFE94, + tehmedialarabic: 0xFE98, + tehmeeminitialarabic: 0xFCA4, + tehmeemisolatedarabic: 0xFC0E, + tehnoonfinalarabic: 0xFC73, + tekatakana: 0x30C6, + tekatakanahalfwidth: 0xFF83, + telephone: 0x2121, + telephoneblack: 0x260E, + telishagedolahebrew: 0x05A0, + telishaqetanahebrew: 0x05A9, + tencircle: 0x2469, + tenideographicparen: 0x3229, + tenparen: 0x247D, + tenperiod: 0x2491, + tenroman: 0x2179, + tesh: 0x02A7, + tet: 0x05D8, + tetdagesh: 0xFB38, + tetdageshhebrew: 0xFB38, + tethebrew: 0x05D8, + tetsecyrillic: 0x04B5, + tevirhebrew: 0x059B, + tevirlefthebrew: 0x059B, + thabengali: 0x09A5, + thadeva: 0x0925, + thagujarati: 0x0AA5, + thagurmukhi: 0x0A25, + thalarabic: 0x0630, + thalfinalarabic: 0xFEAC, + thanthakhatlowleftthai: 0xF898, + thanthakhatlowrightthai: 0xF897, + thanthakhatthai: 0x0E4C, + thanthakhatupperleftthai: 0xF896, + theharabic: 0x062B, + thehfinalarabic: 0xFE9A, + thehinitialarabic: 0xFE9B, + thehmedialarabic: 0xFE9C, + thereexists: 0x2203, + therefore: 0x2234, + theta: 0x03B8, + theta1: 0x03D1, + thetasymbolgreek: 0x03D1, + thieuthacirclekorean: 0x3279, + thieuthaparenkorean: 0x3219, + thieuthcirclekorean: 0x326B, + thieuthkorean: 0x314C, + thieuthparenkorean: 0x320B, + thirteencircle: 0x246C, + thirteenparen: 0x2480, + thirteenperiod: 0x2494, + thonangmonthothai: 0x0E11, + thook: 0x01AD, + thophuthaothai: 0x0E12, + thorn: 0x00FE, + thothahanthai: 0x0E17, + thothanthai: 0x0E10, + thothongthai: 0x0E18, + thothungthai: 0x0E16, + thousandcyrillic: 0x0482, + thousandsseparatorarabic: 0x066C, + thousandsseparatorpersian: 0x066C, + three: 0x0033, + threearabic: 0x0663, + threebengali: 0x09E9, + threecircle: 0x2462, + threecircleinversesansserif: 0x278C, + threedeva: 0x0969, + threeeighths: 0x215C, + threegujarati: 0x0AE9, + threegurmukhi: 0x0A69, + threehackarabic: 0x0663, + threehangzhou: 0x3023, + threeideographicparen: 0x3222, + threeinferior: 0x2083, + threemonospace: 0xFF13, + threenumeratorbengali: 0x09F6, + threeoldstyle: 0xF733, + threeparen: 0x2476, + threeperiod: 0x248A, + threepersian: 0x06F3, + threequarters: 0x00BE, + threequartersemdash: 0xF6DE, + threeroman: 0x2172, + threesuperior: 0x00B3, + threethai: 0x0E53, + thzsquare: 0x3394, + tihiragana: 0x3061, + tikatakana: 0x30C1, + tikatakanahalfwidth: 0xFF81, + tikeutacirclekorean: 0x3270, + tikeutaparenkorean: 0x3210, + tikeutcirclekorean: 0x3262, + tikeutkorean: 0x3137, + tikeutparenkorean: 0x3202, + tilde: 0x02DC, + tildebelowcmb: 0x0330, + tildecmb: 0x0303, + tildecomb: 0x0303, + tildedoublecmb: 0x0360, + tildeoperator: 0x223C, + tildeoverlaycmb: 0x0334, + tildeverticalcmb: 0x033E, + timescircle: 0x2297, + tipehahebrew: 0x0596, + tipehalefthebrew: 0x0596, + tippigurmukhi: 0x0A70, + titlocyrilliccmb: 0x0483, + tiwnarmenian: 0x057F, + tlinebelow: 0x1E6F, + tmonospace: 0xFF54, + toarmenian: 0x0569, + tohiragana: 0x3068, + tokatakana: 0x30C8, + tokatakanahalfwidth: 0xFF84, + tonebarextrahighmod: 0x02E5, + tonebarextralowmod: 0x02E9, + tonebarhighmod: 0x02E6, + tonebarlowmod: 0x02E8, + tonebarmidmod: 0x02E7, + tonefive: 0x01BD, + tonesix: 0x0185, + tonetwo: 0x01A8, + tonos: 0x0384, + tonsquare: 0x3327, + topatakthai: 0x0E0F, + tortoiseshellbracketleft: 0x3014, + tortoiseshellbracketleftsmall: 0xFE5D, + tortoiseshellbracketleftvertical: 0xFE39, + tortoiseshellbracketright: 0x3015, + tortoiseshellbracketrightsmall: 0xFE5E, + tortoiseshellbracketrightvertical: 0xFE3A, + totaothai: 0x0E15, + tpalatalhook: 0x01AB, + tparen: 0x24AF, + trademark: 0x2122, + trademarksans: 0xF8EA, + trademarkserif: 0xF6DB, + tretroflexhook: 0x0288, + triagdn: 0x25BC, + triaglf: 0x25C4, + triagrt: 0x25BA, + triagup: 0x25B2, + ts: 0x02A6, + tsadi: 0x05E6, + tsadidagesh: 0xFB46, + tsadidageshhebrew: 0xFB46, + tsadihebrew: 0x05E6, + tsecyrillic: 0x0446, + tsere: 0x05B5, + tsere12: 0x05B5, + tsere1e: 0x05B5, + tsere2b: 0x05B5, + tserehebrew: 0x05B5, + tserenarrowhebrew: 0x05B5, + tserequarterhebrew: 0x05B5, + tserewidehebrew: 0x05B5, + tshecyrillic: 0x045B, + tsuperior: 0xF6F3, + ttabengali: 0x099F, + ttadeva: 0x091F, + ttagujarati: 0x0A9F, + ttagurmukhi: 0x0A1F, + tteharabic: 0x0679, + ttehfinalarabic: 0xFB67, + ttehinitialarabic: 0xFB68, + ttehmedialarabic: 0xFB69, + tthabengali: 0x09A0, + tthadeva: 0x0920, + tthagujarati: 0x0AA0, + tthagurmukhi: 0x0A20, + tturned: 0x0287, + tuhiragana: 0x3064, + tukatakana: 0x30C4, + tukatakanahalfwidth: 0xFF82, + tusmallhiragana: 0x3063, + tusmallkatakana: 0x30C3, + tusmallkatakanahalfwidth: 0xFF6F, + twelvecircle: 0x246B, + twelveparen: 0x247F, + twelveperiod: 0x2493, + twelveroman: 0x217B, + twentycircle: 0x2473, + twentyhangzhou: 0x5344, + twentyparen: 0x2487, + twentyperiod: 0x249B, + two: 0x0032, + twoarabic: 0x0662, + twobengali: 0x09E8, + twocircle: 0x2461, + twocircleinversesansserif: 0x278B, + twodeva: 0x0968, + twodotenleader: 0x2025, + twodotleader: 0x2025, + twodotleadervertical: 0xFE30, + twogujarati: 0x0AE8, + twogurmukhi: 0x0A68, + twohackarabic: 0x0662, + twohangzhou: 0x3022, + twoideographicparen: 0x3221, + twoinferior: 0x2082, + twomonospace: 0xFF12, + twonumeratorbengali: 0x09F5, + twooldstyle: 0xF732, + twoparen: 0x2475, + twoperiod: 0x2489, + twopersian: 0x06F2, + tworoman: 0x2171, + twostroke: 0x01BB, + twosuperior: 0x00B2, + twothai: 0x0E52, + twothirds: 0x2154, + u: 0x0075, + uacute: 0x00FA, + ubar: 0x0289, + ubengali: 0x0989, + ubopomofo: 0x3128, + ubreve: 0x016D, + ucaron: 0x01D4, + ucircle: 0x24E4, + ucircumflex: 0x00FB, + ucircumflexbelow: 0x1E77, + ucyrillic: 0x0443, + udattadeva: 0x0951, + udblacute: 0x0171, + udblgrave: 0x0215, + udeva: 0x0909, + udieresis: 0x00FC, + udieresisacute: 0x01D8, + udieresisbelow: 0x1E73, + udieresiscaron: 0x01DA, + udieresiscyrillic: 0x04F1, + udieresisgrave: 0x01DC, + udieresismacron: 0x01D6, + udotbelow: 0x1EE5, + ugrave: 0x00F9, + ugujarati: 0x0A89, + ugurmukhi: 0x0A09, + uhiragana: 0x3046, + uhookabove: 0x1EE7, + uhorn: 0x01B0, + uhornacute: 0x1EE9, + uhorndotbelow: 0x1EF1, + uhorngrave: 0x1EEB, + uhornhookabove: 0x1EED, + uhorntilde: 0x1EEF, + uhungarumlaut: 0x0171, + uhungarumlautcyrillic: 0x04F3, + uinvertedbreve: 0x0217, + ukatakana: 0x30A6, + ukatakanahalfwidth: 0xFF73, + ukcyrillic: 0x0479, + ukorean: 0x315C, + umacron: 0x016B, + umacroncyrillic: 0x04EF, + umacrondieresis: 0x1E7B, + umatragurmukhi: 0x0A41, + umonospace: 0xFF55, + underscore: 0x005F, + underscoredbl: 0x2017, + underscoremonospace: 0xFF3F, + underscorevertical: 0xFE33, + underscorewavy: 0xFE4F, + union: 0x222A, + universal: 0x2200, + uogonek: 0x0173, + uparen: 0x24B0, + upblock: 0x2580, + upperdothebrew: 0x05C4, + upsilon: 0x03C5, + upsilondieresis: 0x03CB, + upsilondieresistonos: 0x03B0, + upsilonlatin: 0x028A, + upsilontonos: 0x03CD, + uptackbelowcmb: 0x031D, + uptackmod: 0x02D4, + uragurmukhi: 0x0A73, + uring: 0x016F, + ushortcyrillic: 0x045E, + usmallhiragana: 0x3045, + usmallkatakana: 0x30A5, + usmallkatakanahalfwidth: 0xFF69, + ustraightcyrillic: 0x04AF, + ustraightstrokecyrillic: 0x04B1, + utilde: 0x0169, + utildeacute: 0x1E79, + utildebelow: 0x1E75, + uubengali: 0x098A, + uudeva: 0x090A, + uugujarati: 0x0A8A, + uugurmukhi: 0x0A0A, + uumatragurmukhi: 0x0A42, + uuvowelsignbengali: 0x09C2, + uuvowelsigndeva: 0x0942, + uuvowelsigngujarati: 0x0AC2, + uvowelsignbengali: 0x09C1, + uvowelsigndeva: 0x0941, + uvowelsigngujarati: 0x0AC1, + v: 0x0076, + vadeva: 0x0935, + vagujarati: 0x0AB5, + vagurmukhi: 0x0A35, + vakatakana: 0x30F7, + vav: 0x05D5, + vavdagesh: 0xFB35, + vavdagesh65: 0xFB35, + vavdageshhebrew: 0xFB35, + vavhebrew: 0x05D5, + vavholam: 0xFB4B, + vavholamhebrew: 0xFB4B, + vavvavhebrew: 0x05F0, + vavyodhebrew: 0x05F1, + vcircle: 0x24E5, + vdotbelow: 0x1E7F, + vecyrillic: 0x0432, + veharabic: 0x06A4, + vehfinalarabic: 0xFB6B, + vehinitialarabic: 0xFB6C, + vehmedialarabic: 0xFB6D, + vekatakana: 0x30F9, + venus: 0x2640, + verticalbar: 0x007C, + verticallineabovecmb: 0x030D, + verticallinebelowcmb: 0x0329, + verticallinelowmod: 0x02CC, + verticallinemod: 0x02C8, + vewarmenian: 0x057E, + vhook: 0x028B, + vikatakana: 0x30F8, + viramabengali: 0x09CD, + viramadeva: 0x094D, + viramagujarati: 0x0ACD, + visargabengali: 0x0983, + visargadeva: 0x0903, + visargagujarati: 0x0A83, + vmonospace: 0xFF56, + voarmenian: 0x0578, + voicediterationhiragana: 0x309E, + voicediterationkatakana: 0x30FE, + voicedmarkkana: 0x309B, + voicedmarkkanahalfwidth: 0xFF9E, + vokatakana: 0x30FA, + vparen: 0x24B1, + vtilde: 0x1E7D, + vturned: 0x028C, + vuhiragana: 0x3094, + vukatakana: 0x30F4, + w: 0x0077, + wacute: 0x1E83, + waekorean: 0x3159, + wahiragana: 0x308F, + wakatakana: 0x30EF, + wakatakanahalfwidth: 0xFF9C, + wakorean: 0x3158, + wasmallhiragana: 0x308E, + wasmallkatakana: 0x30EE, + wattosquare: 0x3357, + wavedash: 0x301C, + wavyunderscorevertical: 0xFE34, + wawarabic: 0x0648, + wawfinalarabic: 0xFEEE, + wawhamzaabovearabic: 0x0624, + wawhamzaabovefinalarabic: 0xFE86, + wbsquare: 0x33DD, + wcircle: 0x24E6, + wcircumflex: 0x0175, + wdieresis: 0x1E85, + wdotaccent: 0x1E87, + wdotbelow: 0x1E89, + wehiragana: 0x3091, + weierstrass: 0x2118, + wekatakana: 0x30F1, + wekorean: 0x315E, + weokorean: 0x315D, + wgrave: 0x1E81, + whitebullet: 0x25E6, + whitecircle: 0x25CB, + whitecircleinverse: 0x25D9, + whitecornerbracketleft: 0x300E, + whitecornerbracketleftvertical: 0xFE43, + whitecornerbracketright: 0x300F, + whitecornerbracketrightvertical: 0xFE44, + whitediamond: 0x25C7, + whitediamondcontainingblacksmalldiamond: 0x25C8, + whitedownpointingsmalltriangle: 0x25BF, + whitedownpointingtriangle: 0x25BD, + whiteleftpointingsmalltriangle: 0x25C3, + whiteleftpointingtriangle: 0x25C1, + whitelenticularbracketleft: 0x3016, + whitelenticularbracketright: 0x3017, + whiterightpointingsmalltriangle: 0x25B9, + whiterightpointingtriangle: 0x25B7, + whitesmallsquare: 0x25AB, + whitesmilingface: 0x263A, + whitesquare: 0x25A1, + whitestar: 0x2606, + whitetelephone: 0x260F, + whitetortoiseshellbracketleft: 0x3018, + whitetortoiseshellbracketright: 0x3019, + whiteuppointingsmalltriangle: 0x25B5, + whiteuppointingtriangle: 0x25B3, + wihiragana: 0x3090, + wikatakana: 0x30F0, + wikorean: 0x315F, + wmonospace: 0xFF57, + wohiragana: 0x3092, + wokatakana: 0x30F2, + wokatakanahalfwidth: 0xFF66, + won: 0x20A9, + wonmonospace: 0xFFE6, + wowaenthai: 0x0E27, + wparen: 0x24B2, + wring: 0x1E98, + wsuperior: 0x02B7, + wturned: 0x028D, + wynn: 0x01BF, + x: 0x0078, + xabovecmb: 0x033D, + xbopomofo: 0x3112, + xcircle: 0x24E7, + xdieresis: 0x1E8D, + xdotaccent: 0x1E8B, + xeharmenian: 0x056D, + xi: 0x03BE, + xmonospace: 0xFF58, + xparen: 0x24B3, + xsuperior: 0x02E3, + y: 0x0079, + yaadosquare: 0x334E, + yabengali: 0x09AF, + yacute: 0x00FD, + yadeva: 0x092F, + yaekorean: 0x3152, + yagujarati: 0x0AAF, + yagurmukhi: 0x0A2F, + yahiragana: 0x3084, + yakatakana: 0x30E4, + yakatakanahalfwidth: 0xFF94, + yakorean: 0x3151, + yamakkanthai: 0x0E4E, + yasmallhiragana: 0x3083, + yasmallkatakana: 0x30E3, + yasmallkatakanahalfwidth: 0xFF6C, + yatcyrillic: 0x0463, + ycircle: 0x24E8, + ycircumflex: 0x0177, + ydieresis: 0x00FF, + ydotaccent: 0x1E8F, + ydotbelow: 0x1EF5, + yeharabic: 0x064A, + yehbarreearabic: 0x06D2, + yehbarreefinalarabic: 0xFBAF, + yehfinalarabic: 0xFEF2, + yehhamzaabovearabic: 0x0626, + yehhamzaabovefinalarabic: 0xFE8A, + yehhamzaaboveinitialarabic: 0xFE8B, + yehhamzaabovemedialarabic: 0xFE8C, + yehinitialarabic: 0xFEF3, + yehmedialarabic: 0xFEF4, + yehmeeminitialarabic: 0xFCDD, + yehmeemisolatedarabic: 0xFC58, + yehnoonfinalarabic: 0xFC94, + yehthreedotsbelowarabic: 0x06D1, + yekorean: 0x3156, + yen: 0x00A5, + yenmonospace: 0xFFE5, + yeokorean: 0x3155, + yeorinhieuhkorean: 0x3186, + yerahbenyomohebrew: 0x05AA, + yerahbenyomolefthebrew: 0x05AA, + yericyrillic: 0x044B, + yerudieresiscyrillic: 0x04F9, + yesieungkorean: 0x3181, + yesieungpansioskorean: 0x3183, + yesieungsioskorean: 0x3182, + yetivhebrew: 0x059A, + ygrave: 0x1EF3, + yhook: 0x01B4, + yhookabove: 0x1EF7, + yiarmenian: 0x0575, + yicyrillic: 0x0457, + yikorean: 0x3162, + yinyang: 0x262F, + yiwnarmenian: 0x0582, + ymonospace: 0xFF59, + yod: 0x05D9, + yoddagesh: 0xFB39, + yoddageshhebrew: 0xFB39, + yodhebrew: 0x05D9, + yodyodhebrew: 0x05F2, + yodyodpatahhebrew: 0xFB1F, + yohiragana: 0x3088, + yoikorean: 0x3189, + yokatakana: 0x30E8, + yokatakanahalfwidth: 0xFF96, + yokorean: 0x315B, + yosmallhiragana: 0x3087, + yosmallkatakana: 0x30E7, + yosmallkatakanahalfwidth: 0xFF6E, + yotgreek: 0x03F3, + yoyaekorean: 0x3188, + yoyakorean: 0x3187, + yoyakthai: 0x0E22, + yoyingthai: 0x0E0D, + yparen: 0x24B4, + ypogegrammeni: 0x037A, + ypogegrammenigreekcmb: 0x0345, + yr: 0x01A6, + yring: 0x1E99, + ysuperior: 0x02B8, + ytilde: 0x1EF9, + yturned: 0x028E, + yuhiragana: 0x3086, + yuikorean: 0x318C, + yukatakana: 0x30E6, + yukatakanahalfwidth: 0xFF95, + yukorean: 0x3160, + yusbigcyrillic: 0x046B, + yusbigiotifiedcyrillic: 0x046D, + yuslittlecyrillic: 0x0467, + yuslittleiotifiedcyrillic: 0x0469, + yusmallhiragana: 0x3085, + yusmallkatakana: 0x30E5, + yusmallkatakanahalfwidth: 0xFF6D, + yuyekorean: 0x318B, + yuyeokorean: 0x318A, + yyabengali: 0x09DF, + yyadeva: 0x095F, + z: 0x007A, + zaarmenian: 0x0566, + zacute: 0x017A, + zadeva: 0x095B, + zagurmukhi: 0x0A5B, + zaharabic: 0x0638, + zahfinalarabic: 0xFEC6, + zahinitialarabic: 0xFEC7, + zahiragana: 0x3056, + zahmedialarabic: 0xFEC8, + zainarabic: 0x0632, + zainfinalarabic: 0xFEB0, + zakatakana: 0x30B6, + zaqefgadolhebrew: 0x0595, + zaqefqatanhebrew: 0x0594, + zarqahebrew: 0x0598, + zayin: 0x05D6, + zayindagesh: 0xFB36, + zayindageshhebrew: 0xFB36, + zayinhebrew: 0x05D6, + zbopomofo: 0x3117, + zcaron: 0x017E, + zcircle: 0x24E9, + zcircumflex: 0x1E91, + zcurl: 0x0291, + zdot: 0x017C, + zdotaccent: 0x017C, + zdotbelow: 0x1E93, + zecyrillic: 0x0437, + zedescendercyrillic: 0x0499, + zedieresiscyrillic: 0x04DF, + zehiragana: 0x305C, + zekatakana: 0x30BC, + zero: 0x0030, + zeroarabic: 0x0660, + zerobengali: 0x09E6, + zerodeva: 0x0966, + zerogujarati: 0x0AE6, + zerogurmukhi: 0x0A66, + zerohackarabic: 0x0660, + zeroinferior: 0x2080, + zeromonospace: 0xFF10, + zerooldstyle: 0xF730, + zeropersian: 0x06F0, + zerosuperior: 0x2070, + zerothai: 0x0E50, + zerowidthjoiner: 0xFEFF, + zerowidthnonjoiner: 0x200C, + zerowidthspace: 0x200B, + zeta: 0x03B6, + zhbopomofo: 0x3113, + zhearmenian: 0x056A, + zhebrevecyrillic: 0x04C2, + zhecyrillic: 0x0436, + zhedescendercyrillic: 0x0497, + zhedieresiscyrillic: 0x04DD, + zihiragana: 0x3058, + zikatakana: 0x30B8, + zinorhebrew: 0x05AE, + zlinebelow: 0x1E95, + zmonospace: 0xFF5A, + zohiragana: 0x305E, + zokatakana: 0x30BE, + zparen: 0x24B5, + zretroflexhook: 0x0290, + zstroke: 0x01B6, + zuhiragana: 0x305A, + zukatakana: 0x30BA }; // Add missing glyphs from the original Adobe's list -GlyphsUnicode["angbracketleft"] = "3008"; -GlyphsUnicode["angbracketright"] = "3009"; -GlyphsUnicode["circlecopyrt"] = "00A9"; +GlyphsUnicode["angbracketleft"] = 0x3008; +GlyphsUnicode["angbracketright"] = 0x3009; +GlyphsUnicode["circlecopyrt"] = 0x00A9; From 995c825cc5574a291633fb22977058a057ab7d46 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 00:46:27 -0700 Subject: [PATCH 051/439] revert commit 2311c954f8b74297725bda9e90e3eabf79862193 --- fonts.js | 2 +- glyphlist.js | 8406 +++++++++++++++++++++++++------------------------- 2 files changed, 4204 insertions(+), 4204 deletions(-) diff --git a/fonts.js b/fonts.js index e64001155..2db7e745f 100644 --- a/fonts.js +++ b/fonts.js @@ -40,7 +40,7 @@ var Fonts = { unicodeFromCode: function fonts_unicodeFromCode(aCode) { var unicode = GlyphsUnicode[this.active.encoding[aCode]]; - return unicode ? unicode : aCode; + return unicode ? "0x" + unicode : aCode; } }; diff --git a/glyphlist.js b/glyphlist.js index f5a11b522..e147f6c8a 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1,1510 +1,1510 @@ var GlyphsUnicode = { - A: 0x0041, - AE: 0x00C6, - AEacute: 0x01FC, - AEmacron: 0x01E2, - AEsmall: 0xF7E6, - Aacute: 0x00C1, - Aacutesmall: 0xF7E1, - Abreve: 0x0102, - Abreveacute: 0x1EAE, - Abrevecyrillic: 0x04D0, - Abrevedotbelow: 0x1EB6, - Abrevegrave: 0x1EB0, - Abrevehookabove: 0x1EB2, - Abrevetilde: 0x1EB4, - Acaron: 0x01CD, - Acircle: 0x24B6, - Acircumflex: 0x00C2, - Acircumflexacute: 0x1EA4, - Acircumflexdotbelow: 0x1EAC, - Acircumflexgrave: 0x1EA6, - Acircumflexhookabove: 0x1EA8, - Acircumflexsmall: 0xF7E2, - Acircumflextilde: 0x1EAA, - Acute: 0xF6C9, - Acutesmall: 0xF7B4, - Acyrillic: 0x0410, - Adblgrave: 0x0200, - Adieresis: 0x00C4, - Adieresiscyrillic: 0x04D2, - Adieresismacron: 0x01DE, - Adieresissmall: 0xF7E4, - Adotbelow: 0x1EA0, - Adotmacron: 0x01E0, - Agrave: 0x00C0, - Agravesmall: 0xF7E0, - Ahookabove: 0x1EA2, - Aiecyrillic: 0x04D4, - Ainvertedbreve: 0x0202, - Alpha: 0x0391, - Alphatonos: 0x0386, - Amacron: 0x0100, - Amonospace: 0xFF21, - Aogonek: 0x0104, - Aring: 0x00C5, - Aringacute: 0x01FA, - Aringbelow: 0x1E00, - Aringsmall: 0xF7E5, - Asmall: 0xF761, - Atilde: 0x00C3, - Atildesmall: 0xF7E3, - Aybarmenian: 0x0531, - B: 0x0042, - Bcircle: 0x24B7, - Bdotaccent: 0x1E02, - Bdotbelow: 0x1E04, - Becyrillic: 0x0411, - Benarmenian: 0x0532, - Beta: 0x0392, - Bhook: 0x0181, - Blinebelow: 0x1E06, - Bmonospace: 0xFF22, - Brevesmall: 0xF6F4, - Bsmall: 0xF762, - Btopbar: 0x0182, - C: 0x0043, - Caarmenian: 0x053E, - Cacute: 0x0106, - Caron: 0xF6CA, - Caronsmall: 0xF6F5, - Ccaron: 0x010C, - Ccedilla: 0x00C7, - Ccedillaacute: 0x1E08, - Ccedillasmall: 0xF7E7, - Ccircle: 0x24B8, - Ccircumflex: 0x0108, - Cdot: 0x010A, - Cdotaccent: 0x010A, - Cedillasmall: 0xF7B8, - Chaarmenian: 0x0549, - Cheabkhasiancyrillic: 0x04BC, - Checyrillic: 0x0427, - Chedescenderabkhasiancyrillic: 0x04BE, - Chedescendercyrillic: 0x04B6, - Chedieresiscyrillic: 0x04F4, - Cheharmenian: 0x0543, - Chekhakassiancyrillic: 0x04CB, - Cheverticalstrokecyrillic: 0x04B8, - Chi: 0x03A7, - Chook: 0x0187, - Circumflexsmall: 0xF6F6, - Cmonospace: 0xFF23, - Coarmenian: 0x0551, - Csmall: 0xF763, - D: 0x0044, - DZ: 0x01F1, - DZcaron: 0x01C4, - Daarmenian: 0x0534, - Dafrican: 0x0189, - Dcaron: 0x010E, - Dcedilla: 0x1E10, - Dcircle: 0x24B9, - Dcircumflexbelow: 0x1E12, - Dcroat: 0x0110, - Ddotaccent: 0x1E0A, - Ddotbelow: 0x1E0C, - Decyrillic: 0x0414, - Deicoptic: 0x03EE, - Delta: 0x2206, - Deltagreek: 0x0394, - Dhook: 0x018A, - Dieresis: 0xF6CB, - DieresisAcute: 0xF6CC, - DieresisGrave: 0xF6CD, - Dieresissmall: 0xF7A8, - Digammagreek: 0x03DC, - Djecyrillic: 0x0402, - Dlinebelow: 0x1E0E, - Dmonospace: 0xFF24, - Dotaccentsmall: 0xF6F7, - Dslash: 0x0110, - Dsmall: 0xF764, - Dtopbar: 0x018B, - Dz: 0x01F2, - Dzcaron: 0x01C5, - Dzeabkhasiancyrillic: 0x04E0, - Dzecyrillic: 0x0405, - Dzhecyrillic: 0x040F, - E: 0x0045, - Eacute: 0x00C9, - Eacutesmall: 0xF7E9, - Ebreve: 0x0114, - Ecaron: 0x011A, - Ecedillabreve: 0x1E1C, - Echarmenian: 0x0535, - Ecircle: 0x24BA, - Ecircumflex: 0x00CA, - Ecircumflexacute: 0x1EBE, - Ecircumflexbelow: 0x1E18, - Ecircumflexdotbelow: 0x1EC6, - Ecircumflexgrave: 0x1EC0, - Ecircumflexhookabove: 0x1EC2, - Ecircumflexsmall: 0xF7EA, - Ecircumflextilde: 0x1EC4, - Ecyrillic: 0x0404, - Edblgrave: 0x0204, - Edieresis: 0x00CB, - Edieresissmall: 0xF7EB, - Edot: 0x0116, - Edotaccent: 0x0116, - Edotbelow: 0x1EB8, - Efcyrillic: 0x0424, - Egrave: 0x00C8, - Egravesmall: 0xF7E8, - Eharmenian: 0x0537, - Ehookabove: 0x1EBA, - Eightroman: 0x2167, - Einvertedbreve: 0x0206, - Eiotifiedcyrillic: 0x0464, - Elcyrillic: 0x041B, - Elevenroman: 0x216A, - Emacron: 0x0112, - Emacronacute: 0x1E16, - Emacrongrave: 0x1E14, - Emcyrillic: 0x041C, - Emonospace: 0xFF25, - Encyrillic: 0x041D, - Endescendercyrillic: 0x04A2, - Eng: 0x014A, - Enghecyrillic: 0x04A4, - Enhookcyrillic: 0x04C7, - Eogonek: 0x0118, - Eopen: 0x0190, - Epsilon: 0x0395, - Epsilontonos: 0x0388, - Ercyrillic: 0x0420, - Ereversed: 0x018E, - Ereversedcyrillic: 0x042D, - Escyrillic: 0x0421, - Esdescendercyrillic: 0x04AA, - Esh: 0x01A9, - Esmall: 0xF765, - Eta: 0x0397, - Etarmenian: 0x0538, - Etatonos: 0x0389, - Eth: 0x00D0, - Ethsmall: 0xF7F0, - Etilde: 0x1EBC, - Etildebelow: 0x1E1A, - Euro: 0x20AC, - Ezh: 0x01B7, - Ezhcaron: 0x01EE, - Ezhreversed: 0x01B8, - F: 0x0046, - Fcircle: 0x24BB, - Fdotaccent: 0x1E1E, - Feharmenian: 0x0556, - Feicoptic: 0x03E4, - Fhook: 0x0191, - Fitacyrillic: 0x0472, - Fiveroman: 0x2164, - Fmonospace: 0xFF26, - Fourroman: 0x2163, - Fsmall: 0xF766, - G: 0x0047, - GBsquare: 0x3387, - Gacute: 0x01F4, - Gamma: 0x0393, - Gammaafrican: 0x0194, - Gangiacoptic: 0x03EA, - Gbreve: 0x011E, - Gcaron: 0x01E6, - Gcedilla: 0x0122, - Gcircle: 0x24BC, - Gcircumflex: 0x011C, - Gcommaaccent: 0x0122, - Gdot: 0x0120, - Gdotaccent: 0x0120, - Gecyrillic: 0x0413, - Ghadarmenian: 0x0542, - Ghemiddlehookcyrillic: 0x0494, - Ghestrokecyrillic: 0x0492, - Gheupturncyrillic: 0x0490, - Ghook: 0x0193, - Gimarmenian: 0x0533, - Gjecyrillic: 0x0403, - Gmacron: 0x1E20, - Gmonospace: 0xFF27, - Grave: 0xF6CE, - Gravesmall: 0xF760, - Gsmall: 0xF767, - Gsmallhook: 0x029B, - Gstroke: 0x01E4, - H: 0x0048, - H18533: 0x25CF, - H18543: 0x25AA, - H18551: 0x25AB, - H22073: 0x25A1, - HPsquare: 0x33CB, - Haabkhasiancyrillic: 0x04A8, - Hadescendercyrillic: 0x04B2, - Hardsigncyrillic: 0x042A, - Hbar: 0x0126, - Hbrevebelow: 0x1E2A, - Hcedilla: 0x1E28, - Hcircle: 0x24BD, - Hcircumflex: 0x0124, - Hdieresis: 0x1E26, - Hdotaccent: 0x1E22, - Hdotbelow: 0x1E24, - Hmonospace: 0xFF28, - Hoarmenian: 0x0540, - Horicoptic: 0x03E8, - Hsmall: 0xF768, - Hungarumlaut: 0xF6CF, - Hungarumlautsmall: 0xF6F8, - Hzsquare: 0x3390, - I: 0x0049, - IAcyrillic: 0x042F, - IJ: 0x0132, - IUcyrillic: 0x042E, - Iacute: 0x00CD, - Iacutesmall: 0xF7ED, - Ibreve: 0x012C, - Icaron: 0x01CF, - Icircle: 0x24BE, - Icircumflex: 0x00CE, - Icircumflexsmall: 0xF7EE, - Icyrillic: 0x0406, - Idblgrave: 0x0208, - Idieresis: 0x00CF, - Idieresisacute: 0x1E2E, - Idieresiscyrillic: 0x04E4, - Idieresissmall: 0xF7EF, - Idot: 0x0130, - Idotaccent: 0x0130, - Idotbelow: 0x1ECA, - Iebrevecyrillic: 0x04D6, - Iecyrillic: 0x0415, - Ifraktur: 0x2111, - Igrave: 0x00CC, - Igravesmall: 0xF7EC, - Ihookabove: 0x1EC8, - Iicyrillic: 0x0418, - Iinvertedbreve: 0x020A, - Iishortcyrillic: 0x0419, - Imacron: 0x012A, - Imacroncyrillic: 0x04E2, - Imonospace: 0xFF29, - Iniarmenian: 0x053B, - Iocyrillic: 0x0401, - Iogonek: 0x012E, - Iota: 0x0399, - Iotaafrican: 0x0196, - Iotadieresis: 0x03AA, - Iotatonos: 0x038A, - Ismall: 0xF769, - Istroke: 0x0197, - Itilde: 0x0128, - Itildebelow: 0x1E2C, - Izhitsacyrillic: 0x0474, - Izhitsadblgravecyrillic: 0x0476, - J: 0x004A, - Jaarmenian: 0x0541, - Jcircle: 0x24BF, - Jcircumflex: 0x0134, - Jecyrillic: 0x0408, - Jheharmenian: 0x054B, - Jmonospace: 0xFF2A, - Jsmall: 0xF76A, - K: 0x004B, - KBsquare: 0x3385, - KKsquare: 0x33CD, - Kabashkircyrillic: 0x04A0, - Kacute: 0x1E30, - Kacyrillic: 0x041A, - Kadescendercyrillic: 0x049A, - Kahookcyrillic: 0x04C3, - Kappa: 0x039A, - Kastrokecyrillic: 0x049E, - Kaverticalstrokecyrillic: 0x049C, - Kcaron: 0x01E8, - Kcedilla: 0x0136, - Kcircle: 0x24C0, - Kcommaaccent: 0x0136, - Kdotbelow: 0x1E32, - Keharmenian: 0x0554, - Kenarmenian: 0x053F, - Khacyrillic: 0x0425, - Kheicoptic: 0x03E6, - Khook: 0x0198, - Kjecyrillic: 0x040C, - Klinebelow: 0x1E34, - Kmonospace: 0xFF2B, - Koppacyrillic: 0x0480, - Koppagreek: 0x03DE, - Ksicyrillic: 0x046E, - Ksmall: 0xF76B, - L: 0x004C, - LJ: 0x01C7, - LL: 0xF6BF, - Lacute: 0x0139, - Lambda: 0x039B, - Lcaron: 0x013D, - Lcedilla: 0x013B, - Lcircle: 0x24C1, - Lcircumflexbelow: 0x1E3C, - Lcommaaccent: 0x013B, - Ldot: 0x013F, - Ldotaccent: 0x013F, - Ldotbelow: 0x1E36, - Ldotbelowmacron: 0x1E38, - Liwnarmenian: 0x053C, - Lj: 0x01C8, - Ljecyrillic: 0x0409, - Llinebelow: 0x1E3A, - Lmonospace: 0xFF2C, - Lslash: 0x0141, - Lslashsmall: 0xF6F9, - Lsmall: 0xF76C, - M: 0x004D, - MBsquare: 0x3386, - Macron: 0xF6D0, - Macronsmall: 0xF7AF, - Macute: 0x1E3E, - Mcircle: 0x24C2, - Mdotaccent: 0x1E40, - Mdotbelow: 0x1E42, - Menarmenian: 0x0544, - Mmonospace: 0xFF2D, - Msmall: 0xF76D, - Mturned: 0x019C, - Mu: 0x039C, - N: 0x004E, - NJ: 0x01CA, - Nacute: 0x0143, - Ncaron: 0x0147, - Ncedilla: 0x0145, - Ncircle: 0x24C3, - Ncircumflexbelow: 0x1E4A, - Ncommaaccent: 0x0145, - Ndotaccent: 0x1E44, - Ndotbelow: 0x1E46, - Nhookleft: 0x019D, - Nineroman: 0x2168, - Nj: 0x01CB, - Njecyrillic: 0x040A, - Nlinebelow: 0x1E48, - Nmonospace: 0xFF2E, - Nowarmenian: 0x0546, - Nsmall: 0xF76E, - Ntilde: 0x00D1, - Ntildesmall: 0xF7F1, - Nu: 0x039D, - O: 0x004F, - OE: 0x0152, - OEsmall: 0xF6FA, - Oacute: 0x00D3, - Oacutesmall: 0xF7F3, - Obarredcyrillic: 0x04E8, - Obarreddieresiscyrillic: 0x04EA, - Obreve: 0x014E, - Ocaron: 0x01D1, - Ocenteredtilde: 0x019F, - Ocircle: 0x24C4, - Ocircumflex: 0x00D4, - Ocircumflexacute: 0x1ED0, - Ocircumflexdotbelow: 0x1ED8, - Ocircumflexgrave: 0x1ED2, - Ocircumflexhookabove: 0x1ED4, - Ocircumflexsmall: 0xF7F4, - Ocircumflextilde: 0x1ED6, - Ocyrillic: 0x041E, - Odblacute: 0x0150, - Odblgrave: 0x020C, - Odieresis: 0x00D6, - Odieresiscyrillic: 0x04E6, - Odieresissmall: 0xF7F6, - Odotbelow: 0x1ECC, - Ogoneksmall: 0xF6FB, - Ograve: 0x00D2, - Ogravesmall: 0xF7F2, - Oharmenian: 0x0555, - Ohm: 0x2126, - Ohookabove: 0x1ECE, - Ohorn: 0x01A0, - Ohornacute: 0x1EDA, - Ohorndotbelow: 0x1EE2, - Ohorngrave: 0x1EDC, - Ohornhookabove: 0x1EDE, - Ohorntilde: 0x1EE0, - Ohungarumlaut: 0x0150, - Oi: 0x01A2, - Oinvertedbreve: 0x020E, - Omacron: 0x014C, - Omacronacute: 0x1E52, - Omacrongrave: 0x1E50, - Omega: 0x2126, - Omegacyrillic: 0x0460, - Omegagreek: 0x03A9, - Omegaroundcyrillic: 0x047A, - Omegatitlocyrillic: 0x047C, - Omegatonos: 0x038F, - Omicron: 0x039F, - Omicrontonos: 0x038C, - Omonospace: 0xFF2F, - Oneroman: 0x2160, - Oogonek: 0x01EA, - Oogonekmacron: 0x01EC, - Oopen: 0x0186, - Oslash: 0x00D8, - Oslashacute: 0x01FE, - Oslashsmall: 0xF7F8, - Osmall: 0xF76F, - Ostrokeacute: 0x01FE, - Otcyrillic: 0x047E, - Otilde: 0x00D5, - Otildeacute: 0x1E4C, - Otildedieresis: 0x1E4E, - Otildesmall: 0xF7F5, - P: 0x0050, - Pacute: 0x1E54, - Pcircle: 0x24C5, - Pdotaccent: 0x1E56, - Pecyrillic: 0x041F, - Peharmenian: 0x054A, - Pemiddlehookcyrillic: 0x04A6, - Phi: 0x03A6, - Phook: 0x01A4, - Pi: 0x03A0, - Piwrarmenian: 0x0553, - Pmonospace: 0xFF30, - Psi: 0x03A8, - Psicyrillic: 0x0470, - Psmall: 0xF770, - Q: 0x0051, - Qcircle: 0x24C6, - Qmonospace: 0xFF31, - Qsmall: 0xF771, - R: 0x0052, - Raarmenian: 0x054C, - Racute: 0x0154, - Rcaron: 0x0158, - Rcedilla: 0x0156, - Rcircle: 0x24C7, - Rcommaaccent: 0x0156, - Rdblgrave: 0x0210, - Rdotaccent: 0x1E58, - Rdotbelow: 0x1E5A, - Rdotbelowmacron: 0x1E5C, - Reharmenian: 0x0550, - Rfraktur: 0x211C, - Rho: 0x03A1, - Ringsmall: 0xF6FC, - Rinvertedbreve: 0x0212, - Rlinebelow: 0x1E5E, - Rmonospace: 0xFF32, - Rsmall: 0xF772, - Rsmallinverted: 0x0281, - Rsmallinvertedsuperior: 0x02B6, - S: 0x0053, - SF010000: 0x250C, - SF020000: 0x2514, - SF030000: 0x2510, - SF040000: 0x2518, - SF050000: 0x253C, - SF060000: 0x252C, - SF070000: 0x2534, - SF080000: 0x251C, - SF090000: 0x2524, - SF100000: 0x2500, - SF110000: 0x2502, - SF190000: 0x2561, - SF200000: 0x2562, - SF210000: 0x2556, - SF220000: 0x2555, - SF230000: 0x2563, - SF240000: 0x2551, - SF250000: 0x2557, - SF260000: 0x255D, - SF270000: 0x255C, - SF280000: 0x255B, - SF360000: 0x255E, - SF370000: 0x255F, - SF380000: 0x255A, - SF390000: 0x2554, - SF400000: 0x2569, - SF410000: 0x2566, - SF420000: 0x2560, - SF430000: 0x2550, - SF440000: 0x256C, - SF450000: 0x2567, - SF460000: 0x2568, - SF470000: 0x2564, - SF480000: 0x2565, - SF490000: 0x2559, - SF500000: 0x2558, - SF510000: 0x2552, - SF520000: 0x2553, - SF530000: 0x256B, - SF540000: 0x256A, - Sacute: 0x015A, - Sacutedotaccent: 0x1E64, - Sampigreek: 0x03E0, - Scaron: 0x0160, - Scarondotaccent: 0x1E66, - Scaronsmall: 0xF6FD, - Scedilla: 0x015E, - Schwa: 0x018F, - Schwacyrillic: 0x04D8, - Schwadieresiscyrillic: 0x04DA, - Scircle: 0x24C8, - Scircumflex: 0x015C, - Scommaaccent: 0x0218, - Sdotaccent: 0x1E60, - Sdotbelow: 0x1E62, - Sdotbelowdotaccent: 0x1E68, - Seharmenian: 0x054D, - Sevenroman: 0x2166, - Shaarmenian: 0x0547, - Shacyrillic: 0x0428, - Shchacyrillic: 0x0429, - Sheicoptic: 0x03E2, - Shhacyrillic: 0x04BA, - Shimacoptic: 0x03EC, - Sigma: 0x03A3, - Sixroman: 0x2165, - Smonospace: 0xFF33, - Softsigncyrillic: 0x042C, - Ssmall: 0xF773, - Stigmagreek: 0x03DA, - T: 0x0054, - Tau: 0x03A4, - Tbar: 0x0166, - Tcaron: 0x0164, - Tcedilla: 0x0162, - Tcircle: 0x24C9, - Tcircumflexbelow: 0x1E70, - Tcommaaccent: 0x0162, - Tdotaccent: 0x1E6A, - Tdotbelow: 0x1E6C, - Tecyrillic: 0x0422, - Tedescendercyrillic: 0x04AC, - Tenroman: 0x2169, - Tetsecyrillic: 0x04B4, - Theta: 0x0398, - Thook: 0x01AC, - Thorn: 0x00DE, - Thornsmall: 0xF7FE, - Threeroman: 0x2162, - Tildesmall: 0xF6FE, - Tiwnarmenian: 0x054F, - Tlinebelow: 0x1E6E, - Tmonospace: 0xFF34, - Toarmenian: 0x0539, - Tonefive: 0x01BC, - Tonesix: 0x0184, - Tonetwo: 0x01A7, - Tretroflexhook: 0x01AE, - Tsecyrillic: 0x0426, - Tshecyrillic: 0x040B, - Tsmall: 0xF774, - Twelveroman: 0x216B, - Tworoman: 0x2161, - U: 0x0055, - Uacute: 0x00DA, - Uacutesmall: 0xF7FA, - Ubreve: 0x016C, - Ucaron: 0x01D3, - Ucircle: 0x24CA, - Ucircumflex: 0x00DB, - Ucircumflexbelow: 0x1E76, - Ucircumflexsmall: 0xF7FB, - Ucyrillic: 0x0423, - Udblacute: 0x0170, - Udblgrave: 0x0214, - Udieresis: 0x00DC, - Udieresisacute: 0x01D7, - Udieresisbelow: 0x1E72, - Udieresiscaron: 0x01D9, - Udieresiscyrillic: 0x04F0, - Udieresisgrave: 0x01DB, - Udieresismacron: 0x01D5, - Udieresissmall: 0xF7FC, - Udotbelow: 0x1EE4, - Ugrave: 0x00D9, - Ugravesmall: 0xF7F9, - Uhookabove: 0x1EE6, - Uhorn: 0x01AF, - Uhornacute: 0x1EE8, - Uhorndotbelow: 0x1EF0, - Uhorngrave: 0x1EEA, - Uhornhookabove: 0x1EEC, - Uhorntilde: 0x1EEE, - Uhungarumlaut: 0x0170, - Uhungarumlautcyrillic: 0x04F2, - Uinvertedbreve: 0x0216, - Ukcyrillic: 0x0478, - Umacron: 0x016A, - Umacroncyrillic: 0x04EE, - Umacrondieresis: 0x1E7A, - Umonospace: 0xFF35, - Uogonek: 0x0172, - Upsilon: 0x03A5, - Upsilon1: 0x03D2, - Upsilonacutehooksymbolgreek: 0x03D3, - Upsilonafrican: 0x01B1, - Upsilondieresis: 0x03AB, - Upsilondieresishooksymbolgreek: 0x03D4, - Upsilonhooksymbol: 0x03D2, - Upsilontonos: 0x038E, - Uring: 0x016E, - Ushortcyrillic: 0x040E, - Usmall: 0xF775, - Ustraightcyrillic: 0x04AE, - Ustraightstrokecyrillic: 0x04B0, - Utilde: 0x0168, - Utildeacute: 0x1E78, - Utildebelow: 0x1E74, - V: 0x0056, - Vcircle: 0x24CB, - Vdotbelow: 0x1E7E, - Vecyrillic: 0x0412, - Vewarmenian: 0x054E, - Vhook: 0x01B2, - Vmonospace: 0xFF36, - Voarmenian: 0x0548, - Vsmall: 0xF776, - Vtilde: 0x1E7C, - W: 0x0057, - Wacute: 0x1E82, - Wcircle: 0x24CC, - Wcircumflex: 0x0174, - Wdieresis: 0x1E84, - Wdotaccent: 0x1E86, - Wdotbelow: 0x1E88, - Wgrave: 0x1E80, - Wmonospace: 0xFF37, - Wsmall: 0xF777, - X: 0x0058, - Xcircle: 0x24CD, - Xdieresis: 0x1E8C, - Xdotaccent: 0x1E8A, - Xeharmenian: 0x053D, - Xi: 0x039E, - Xmonospace: 0xFF38, - Xsmall: 0xF778, - Y: 0x0059, - Yacute: 0x00DD, - Yacutesmall: 0xF7FD, - Yatcyrillic: 0x0462, - Ycircle: 0x24CE, - Ycircumflex: 0x0176, - Ydieresis: 0x0178, - Ydieresissmall: 0xF7FF, - Ydotaccent: 0x1E8E, - Ydotbelow: 0x1EF4, - Yericyrillic: 0x042B, - Yerudieresiscyrillic: 0x04F8, - Ygrave: 0x1EF2, - Yhook: 0x01B3, - Yhookabove: 0x1EF6, - Yiarmenian: 0x0545, - Yicyrillic: 0x0407, - Yiwnarmenian: 0x0552, - Ymonospace: 0xFF39, - Ysmall: 0xF779, - Ytilde: 0x1EF8, - Yusbigcyrillic: 0x046A, - Yusbigiotifiedcyrillic: 0x046C, - Yuslittlecyrillic: 0x0466, - Yuslittleiotifiedcyrillic: 0x0468, - Z: 0x005A, - Zaarmenian: 0x0536, - Zacute: 0x0179, - Zcaron: 0x017D, - Zcaronsmall: 0xF6FF, - Zcircle: 0x24CF, - Zcircumflex: 0x1E90, - Zdot: 0x017B, - Zdotaccent: 0x017B, - Zdotbelow: 0x1E92, - Zecyrillic: 0x0417, - Zedescendercyrillic: 0x0498, - Zedieresiscyrillic: 0x04DE, - Zeta: 0x0396, - Zhearmenian: 0x053A, - Zhebrevecyrillic: 0x04C1, - Zhecyrillic: 0x0416, - Zhedescendercyrillic: 0x0496, - Zhedieresiscyrillic: 0x04DC, - Zlinebelow: 0x1E94, - Zmonospace: 0xFF3A, - Zsmall: 0xF77A, - Zstroke: 0x01B5, - a: 0x0061, - aabengali: 0x0986, - aacute: 0x00E1, - aadeva: 0x0906, - aagujarati: 0x0A86, - aagurmukhi: 0x0A06, - aamatragurmukhi: 0x0A3E, - aarusquare: 0x3303, - aavowelsignbengali: 0x09BE, - aavowelsigndeva: 0x093E, - aavowelsigngujarati: 0x0ABE, - abbreviationmarkarmenian: 0x055F, - abbreviationsigndeva: 0x0970, - abengali: 0x0985, - abopomofo: 0x311A, - abreve: 0x0103, - abreveacute: 0x1EAF, - abrevecyrillic: 0x04D1, - abrevedotbelow: 0x1EB7, - abrevegrave: 0x1EB1, - abrevehookabove: 0x1EB3, - abrevetilde: 0x1EB5, - acaron: 0x01CE, - acircle: 0x24D0, - acircumflex: 0x00E2, - acircumflexacute: 0x1EA5, - acircumflexdotbelow: 0x1EAD, - acircumflexgrave: 0x1EA7, - acircumflexhookabove: 0x1EA9, - acircumflextilde: 0x1EAB, - acute: 0x00B4, - acutebelowcmb: 0x0317, - acutecmb: 0x0301, - acutecomb: 0x0301, - acutedeva: 0x0954, - acutelowmod: 0x02CF, - acutetonecmb: 0x0341, - acyrillic: 0x0430, - adblgrave: 0x0201, - addakgurmukhi: 0x0A71, - adeva: 0x0905, - adieresis: 0x00E4, - adieresiscyrillic: 0x04D3, - adieresismacron: 0x01DF, - adotbelow: 0x1EA1, - adotmacron: 0x01E1, - ae: 0x00E6, - aeacute: 0x01FD, - aekorean: 0x3150, - aemacron: 0x01E3, - afii00208: 0x2015, - afii08941: 0x20A4, - afii10017: 0x0410, - afii10018: 0x0411, - afii10019: 0x0412, - afii10020: 0x0413, - afii10021: 0x0414, - afii10022: 0x0415, - afii10023: 0x0401, - afii10024: 0x0416, - afii10025: 0x0417, - afii10026: 0x0418, - afii10027: 0x0419, - afii10028: 0x041A, - afii10029: 0x041B, - afii10030: 0x041C, - afii10031: 0x041D, - afii10032: 0x041E, - afii10033: 0x041F, - afii10034: 0x0420, - afii10035: 0x0421, - afii10036: 0x0422, - afii10037: 0x0423, - afii10038: 0x0424, - afii10039: 0x0425, - afii10040: 0x0426, - afii10041: 0x0427, - afii10042: 0x0428, - afii10043: 0x0429, - afii10044: 0x042A, - afii10045: 0x042B, - afii10046: 0x042C, - afii10047: 0x042D, - afii10048: 0x042E, - afii10049: 0x042F, - afii10050: 0x0490, - afii10051: 0x0402, - afii10052: 0x0403, - afii10053: 0x0404, - afii10054: 0x0405, - afii10055: 0x0406, - afii10056: 0x0407, - afii10057: 0x0408, - afii10058: 0x0409, - afii10059: 0x040A, - afii10060: 0x040B, - afii10061: 0x040C, - afii10062: 0x040E, - afii10063: 0xF6C4, - afii10064: 0xF6C5, - afii10065: 0x0430, - afii10066: 0x0431, - afii10067: 0x0432, - afii10068: 0x0433, - afii10069: 0x0434, - afii10070: 0x0435, - afii10071: 0x0451, - afii10072: 0x0436, - afii10073: 0x0437, - afii10074: 0x0438, - afii10075: 0x0439, - afii10076: 0x043A, - afii10077: 0x043B, - afii10078: 0x043C, - afii10079: 0x043D, - afii10080: 0x043E, - afii10081: 0x043F, - afii10082: 0x0440, - afii10083: 0x0441, - afii10084: 0x0442, - afii10085: 0x0443, - afii10086: 0x0444, - afii10087: 0x0445, - afii10088: 0x0446, - afii10089: 0x0447, - afii10090: 0x0448, - afii10091: 0x0449, - afii10092: 0x044A, - afii10093: 0x044B, - afii10094: 0x044C, - afii10095: 0x044D, - afii10096: 0x044E, - afii10097: 0x044F, - afii10098: 0x0491, - afii10099: 0x0452, - afii10100: 0x0453, - afii10101: 0x0454, - afii10102: 0x0455, - afii10103: 0x0456, - afii10104: 0x0457, - afii10105: 0x0458, - afii10106: 0x0459, - afii10107: 0x045A, - afii10108: 0x045B, - afii10109: 0x045C, - afii10110: 0x045E, - afii10145: 0x040F, - afii10146: 0x0462, - afii10147: 0x0472, - afii10148: 0x0474, - afii10192: 0xF6C6, - afii10193: 0x045F, - afii10194: 0x0463, - afii10195: 0x0473, - afii10196: 0x0475, - afii10831: 0xF6C7, - afii10832: 0xF6C8, - afii10846: 0x04D9, - afii299: 0x200E, - afii300: 0x200F, - afii301: 0x200D, - afii57381: 0x066A, - afii57388: 0x060C, - afii57392: 0x0660, - afii57393: 0x0661, - afii57394: 0x0662, - afii57395: 0x0663, - afii57396: 0x0664, - afii57397: 0x0665, - afii57398: 0x0666, - afii57399: 0x0667, - afii57400: 0x0668, - afii57401: 0x0669, - afii57403: 0x061B, - afii57407: 0x061F, - afii57409: 0x0621, - afii57410: 0x0622, - afii57411: 0x0623, - afii57412: 0x0624, - afii57413: 0x0625, - afii57414: 0x0626, - afii57415: 0x0627, - afii57416: 0x0628, - afii57417: 0x0629, - afii57418: 0x062A, - afii57419: 0x062B, - afii57420: 0x062C, - afii57421: 0x062D, - afii57422: 0x062E, - afii57423: 0x062F, - afii57424: 0x0630, - afii57425: 0x0631, - afii57426: 0x0632, - afii57427: 0x0633, - afii57428: 0x0634, - afii57429: 0x0635, - afii57430: 0x0636, - afii57431: 0x0637, - afii57432: 0x0638, - afii57433: 0x0639, - afii57434: 0x063A, - afii57440: 0x0640, - afii57441: 0x0641, - afii57442: 0x0642, - afii57443: 0x0643, - afii57444: 0x0644, - afii57445: 0x0645, - afii57446: 0x0646, - afii57448: 0x0648, - afii57449: 0x0649, - afii57450: 0x064A, - afii57451: 0x064B, - afii57452: 0x064C, - afii57453: 0x064D, - afii57454: 0x064E, - afii57455: 0x064F, - afii57456: 0x0650, - afii57457: 0x0651, - afii57458: 0x0652, - afii57470: 0x0647, - afii57505: 0x06A4, - afii57506: 0x067E, - afii57507: 0x0686, - afii57508: 0x0698, - afii57509: 0x06AF, - afii57511: 0x0679, - afii57512: 0x0688, - afii57513: 0x0691, - afii57514: 0x06BA, - afii57519: 0x06D2, - afii57534: 0x06D5, - afii57636: 0x20AA, - afii57645: 0x05BE, - afii57658: 0x05C3, - afii57664: 0x05D0, - afii57665: 0x05D1, - afii57666: 0x05D2, - afii57667: 0x05D3, - afii57668: 0x05D4, - afii57669: 0x05D5, - afii57670: 0x05D6, - afii57671: 0x05D7, - afii57672: 0x05D8, - afii57673: 0x05D9, - afii57674: 0x05DA, - afii57675: 0x05DB, - afii57676: 0x05DC, - afii57677: 0x05DD, - afii57678: 0x05DE, - afii57679: 0x05DF, - afii57680: 0x05E0, - afii57681: 0x05E1, - afii57682: 0x05E2, - afii57683: 0x05E3, - afii57684: 0x05E4, - afii57685: 0x05E5, - afii57686: 0x05E6, - afii57687: 0x05E7, - afii57688: 0x05E8, - afii57689: 0x05E9, - afii57690: 0x05EA, - afii57694: 0xFB2A, - afii57695: 0xFB2B, - afii57700: 0xFB4B, - afii57705: 0xFB1F, - afii57716: 0x05F0, - afii57717: 0x05F1, - afii57718: 0x05F2, - afii57723: 0xFB35, - afii57793: 0x05B4, - afii57794: 0x05B5, - afii57795: 0x05B6, - afii57796: 0x05BB, - afii57797: 0x05B8, - afii57798: 0x05B7, - afii57799: 0x05B0, - afii57800: 0x05B2, - afii57801: 0x05B1, - afii57802: 0x05B3, - afii57803: 0x05C2, - afii57804: 0x05C1, - afii57806: 0x05B9, - afii57807: 0x05BC, - afii57839: 0x05BD, - afii57841: 0x05BF, - afii57842: 0x05C0, - afii57929: 0x02BC, - afii61248: 0x2105, - afii61289: 0x2113, - afii61352: 0x2116, - afii61573: 0x202C, - afii61574: 0x202D, - afii61575: 0x202E, - afii61664: 0x200C, - afii63167: 0x066D, - afii64937: 0x02BD, - agrave: 0x00E0, - agujarati: 0x0A85, - agurmukhi: 0x0A05, - ahiragana: 0x3042, - ahookabove: 0x1EA3, - aibengali: 0x0990, - aibopomofo: 0x311E, - aideva: 0x0910, - aiecyrillic: 0x04D5, - aigujarati: 0x0A90, - aigurmukhi: 0x0A10, - aimatragurmukhi: 0x0A48, - ainarabic: 0x0639, - ainfinalarabic: 0xFECA, - aininitialarabic: 0xFECB, - ainmedialarabic: 0xFECC, - ainvertedbreve: 0x0203, - aivowelsignbengali: 0x09C8, - aivowelsigndeva: 0x0948, - aivowelsigngujarati: 0x0AC8, - akatakana: 0x30A2, - akatakanahalfwidth: 0xFF71, - akorean: 0x314F, - alef: 0x05D0, - alefarabic: 0x0627, - alefdageshhebrew: 0xFB30, - aleffinalarabic: 0xFE8E, - alefhamzaabovearabic: 0x0623, - alefhamzaabovefinalarabic: 0xFE84, - alefhamzabelowarabic: 0x0625, - alefhamzabelowfinalarabic: 0xFE88, - alefhebrew: 0x05D0, - aleflamedhebrew: 0xFB4F, - alefmaddaabovearabic: 0x0622, - alefmaddaabovefinalarabic: 0xFE82, - alefmaksuraarabic: 0x0649, - alefmaksurafinalarabic: 0xFEF0, - alefmaksurainitialarabic: 0xFEF3, - alefmaksuramedialarabic: 0xFEF4, - alefpatahhebrew: 0xFB2E, - alefqamatshebrew: 0xFB2F, - aleph: 0x2135, - allequal: 0x224C, - alpha: 0x03B1, - alphatonos: 0x03AC, - amacron: 0x0101, - amonospace: 0xFF41, - ampersand: 0x0026, - ampersandmonospace: 0xFF06, - ampersandsmall: 0xF726, - amsquare: 0x33C2, - anbopomofo: 0x3122, - angbopomofo: 0x3124, - angkhankhuthai: 0x0E5A, - angle: 0x2220, - anglebracketleft: 0x3008, - anglebracketleftvertical: 0xFE3F, - anglebracketright: 0x3009, - anglebracketrightvertical: 0xFE40, - angleleft: 0x2329, - angleright: 0x232A, - angstrom: 0x212B, - anoteleia: 0x0387, - anudattadeva: 0x0952, - anusvarabengali: 0x0982, - anusvaradeva: 0x0902, - anusvaragujarati: 0x0A82, - aogonek: 0x0105, - apaatosquare: 0x3300, - aparen: 0x249C, - apostrophearmenian: 0x055A, - apostrophemod: 0x02BC, - apple: 0xF8FF, - approaches: 0x2250, - approxequal: 0x2248, - approxequalorimage: 0x2252, - approximatelyequal: 0x2245, - araeaekorean: 0x318E, - araeakorean: 0x318D, - arc: 0x2312, - arighthalfring: 0x1E9A, - aring: 0x00E5, - aringacute: 0x01FB, - aringbelow: 0x1E01, - arrowboth: 0x2194, - arrowdashdown: 0x21E3, - arrowdashleft: 0x21E0, - arrowdashright: 0x21E2, - arrowdashup: 0x21E1, - arrowdblboth: 0x21D4, - arrowdbldown: 0x21D3, - arrowdblleft: 0x21D0, - arrowdblright: 0x21D2, - arrowdblup: 0x21D1, - arrowdown: 0x2193, - arrowdownleft: 0x2199, - arrowdownright: 0x2198, - arrowdownwhite: 0x21E9, - arrowheaddownmod: 0x02C5, - arrowheadleftmod: 0x02C2, - arrowheadrightmod: 0x02C3, - arrowheadupmod: 0x02C4, - arrowhorizex: 0xF8E7, - arrowleft: 0x2190, - arrowleftdbl: 0x21D0, - arrowleftdblstroke: 0x21CD, - arrowleftoverright: 0x21C6, - arrowleftwhite: 0x21E6, - arrowright: 0x2192, - arrowrightdblstroke: 0x21CF, - arrowrightheavy: 0x279E, - arrowrightoverleft: 0x21C4, - arrowrightwhite: 0x21E8, - arrowtableft: 0x21E4, - arrowtabright: 0x21E5, - arrowup: 0x2191, - arrowupdn: 0x2195, - arrowupdnbse: 0x21A8, - arrowupdownbase: 0x21A8, - arrowupleft: 0x2196, - arrowupleftofdown: 0x21C5, - arrowupright: 0x2197, - arrowupwhite: 0x21E7, - arrowvertex: 0xF8E6, - asciicircum: 0x005E, - asciicircummonospace: 0xFF3E, - asciitilde: 0x007E, - asciitildemonospace: 0xFF5E, - ascript: 0x0251, - ascriptturned: 0x0252, - asmallhiragana: 0x3041, - asmallkatakana: 0x30A1, - asmallkatakanahalfwidth: 0xFF67, - asterisk: 0x002A, - asteriskaltonearabic: 0x066D, - asteriskarabic: 0x066D, - asteriskmath: 0x2217, - asteriskmonospace: 0xFF0A, - asterisksmall: 0xFE61, - asterism: 0x2042, - asuperior: 0xF6E9, - asymptoticallyequal: 0x2243, - at: 0x0040, - atilde: 0x00E3, - atmonospace: 0xFF20, - atsmall: 0xFE6B, - aturned: 0x0250, - aubengali: 0x0994, - aubopomofo: 0x3120, - audeva: 0x0914, - augujarati: 0x0A94, - augurmukhi: 0x0A14, - aulengthmarkbengali: 0x09D7, - aumatragurmukhi: 0x0A4C, - auvowelsignbengali: 0x09CC, - auvowelsigndeva: 0x094C, - auvowelsigngujarati: 0x0ACC, - avagrahadeva: 0x093D, - aybarmenian: 0x0561, - ayin: 0x05E2, - ayinaltonehebrew: 0xFB20, - ayinhebrew: 0x05E2, - b: 0x0062, - babengali: 0x09AC, - backslash: 0x005C, - backslashmonospace: 0xFF3C, - badeva: 0x092C, - bagujarati: 0x0AAC, - bagurmukhi: 0x0A2C, - bahiragana: 0x3070, - bahtthai: 0x0E3F, - bakatakana: 0x30D0, - bar: 0x007C, - barmonospace: 0xFF5C, - bbopomofo: 0x3105, - bcircle: 0x24D1, - bdotaccent: 0x1E03, - bdotbelow: 0x1E05, - beamedsixteenthnotes: 0x266C, - because: 0x2235, - becyrillic: 0x0431, - beharabic: 0x0628, - behfinalarabic: 0xFE90, - behinitialarabic: 0xFE91, - behiragana: 0x3079, - behmedialarabic: 0xFE92, - behmeeminitialarabic: 0xFC9F, - behmeemisolatedarabic: 0xFC08, - behnoonfinalarabic: 0xFC6D, - bekatakana: 0x30D9, - benarmenian: 0x0562, - bet: 0x05D1, - beta: 0x03B2, - betasymbolgreek: 0x03D0, - betdagesh: 0xFB31, - betdageshhebrew: 0xFB31, - bethebrew: 0x05D1, - betrafehebrew: 0xFB4C, - bhabengali: 0x09AD, - bhadeva: 0x092D, - bhagujarati: 0x0AAD, - bhagurmukhi: 0x0A2D, - bhook: 0x0253, - bihiragana: 0x3073, - bikatakana: 0x30D3, - bilabialclick: 0x0298, - bindigurmukhi: 0x0A02, - birusquare: 0x3331, - blackcircle: 0x25CF, - blackdiamond: 0x25C6, - blackdownpointingtriangle: 0x25BC, - blackleftpointingpointer: 0x25C4, - blackleftpointingtriangle: 0x25C0, - blacklenticularbracketleft: 0x3010, - blacklenticularbracketleftvertical: 0xFE3B, - blacklenticularbracketright: 0x3011, - blacklenticularbracketrightvertical: 0xFE3C, - blacklowerlefttriangle: 0x25E3, - blacklowerrighttriangle: 0x25E2, - blackrectangle: 0x25AC, - blackrightpointingpointer: 0x25BA, - blackrightpointingtriangle: 0x25B6, - blacksmallsquare: 0x25AA, - blacksmilingface: 0x263B, - blacksquare: 0x25A0, - blackstar: 0x2605, - blackupperlefttriangle: 0x25E4, - blackupperrighttriangle: 0x25E5, - blackuppointingsmalltriangle: 0x25B4, - blackuppointingtriangle: 0x25B2, - blank: 0x2423, - blinebelow: 0x1E07, - block: 0x2588, - bmonospace: 0xFF42, - bobaimaithai: 0x0E1A, - bohiragana: 0x307C, - bokatakana: 0x30DC, - bparen: 0x249D, - bqsquare: 0x33C3, - braceex: 0xF8F4, - braceleft: 0x007B, - braceleftbt: 0xF8F3, - braceleftmid: 0xF8F2, - braceleftmonospace: 0xFF5B, - braceleftsmall: 0xFE5B, - bracelefttp: 0xF8F1, - braceleftvertical: 0xFE37, - braceright: 0x007D, - bracerightbt: 0xF8FE, - bracerightmid: 0xF8FD, - bracerightmonospace: 0xFF5D, - bracerightsmall: 0xFE5C, - bracerighttp: 0xF8FC, - bracerightvertical: 0xFE38, - bracketleft: 0x005B, - bracketleftbt: 0xF8F0, - bracketleftex: 0xF8EF, - bracketleftmonospace: 0xFF3B, - bracketlefttp: 0xF8EE, - bracketright: 0x005D, - bracketrightbt: 0xF8FB, - bracketrightex: 0xF8FA, - bracketrightmonospace: 0xFF3D, - bracketrighttp: 0xF8F9, - breve: 0x02D8, - brevebelowcmb: 0x032E, - brevecmb: 0x0306, - breveinvertedbelowcmb: 0x032F, - breveinvertedcmb: 0x0311, - breveinverteddoublecmb: 0x0361, - bridgebelowcmb: 0x032A, - bridgeinvertedbelowcmb: 0x033A, - brokenbar: 0x00A6, - bstroke: 0x0180, - bsuperior: 0xF6EA, - btopbar: 0x0183, - buhiragana: 0x3076, - bukatakana: 0x30D6, - bullet: 0x2022, - bulletinverse: 0x25D8, - bulletoperator: 0x2219, - bullseye: 0x25CE, - c: 0x0063, - caarmenian: 0x056E, - cabengali: 0x099A, - cacute: 0x0107, - cadeva: 0x091A, - cagujarati: 0x0A9A, - cagurmukhi: 0x0A1A, - calsquare: 0x3388, - candrabindubengali: 0x0981, - candrabinducmb: 0x0310, - candrabindudeva: 0x0901, - candrabindugujarati: 0x0A81, - capslock: 0x21EA, - careof: 0x2105, - caron: 0x02C7, - caronbelowcmb: 0x032C, - caroncmb: 0x030C, - carriagereturn: 0x21B5, - cbopomofo: 0x3118, - ccaron: 0x010D, - ccedilla: 0x00E7, - ccedillaacute: 0x1E09, - ccircle: 0x24D2, - ccircumflex: 0x0109, - ccurl: 0x0255, - cdot: 0x010B, - cdotaccent: 0x010B, - cdsquare: 0x33C5, - cedilla: 0x00B8, - cedillacmb: 0x0327, - cent: 0x00A2, - centigrade: 0x2103, - centinferior: 0xF6DF, - centmonospace: 0xFFE0, - centoldstyle: 0xF7A2, - centsuperior: 0xF6E0, - chaarmenian: 0x0579, - chabengali: 0x099B, - chadeva: 0x091B, - chagujarati: 0x0A9B, - chagurmukhi: 0x0A1B, - chbopomofo: 0x3114, - cheabkhasiancyrillic: 0x04BD, - checkmark: 0x2713, - checyrillic: 0x0447, - chedescenderabkhasiancyrillic: 0x04BF, - chedescendercyrillic: 0x04B7, - chedieresiscyrillic: 0x04F5, - cheharmenian: 0x0573, - chekhakassiancyrillic: 0x04CC, - cheverticalstrokecyrillic: 0x04B9, - chi: 0x03C7, - chieuchacirclekorean: 0x3277, - chieuchaparenkorean: 0x3217, - chieuchcirclekorean: 0x3269, - chieuchkorean: 0x314A, - chieuchparenkorean: 0x3209, - chochangthai: 0x0E0A, - chochanthai: 0x0E08, - chochingthai: 0x0E09, - chochoethai: 0x0E0C, - chook: 0x0188, - cieucacirclekorean: 0x3276, - cieucaparenkorean: 0x3216, - cieuccirclekorean: 0x3268, - cieuckorean: 0x3148, - cieucparenkorean: 0x3208, - cieucuparenkorean: 0x321C, - circle: 0x25CB, - circlemultiply: 0x2297, - circleot: 0x2299, - circleplus: 0x2295, - circlepostalmark: 0x3036, - circlewithlefthalfblack: 0x25D0, - circlewithrighthalfblack: 0x25D1, - circumflex: 0x02C6, - circumflexbelowcmb: 0x032D, - circumflexcmb: 0x0302, - clear: 0x2327, - clickalveolar: 0x01C2, - clickdental: 0x01C0, - clicklateral: 0x01C1, - clickretroflex: 0x01C3, - club: 0x2663, - clubsuitblack: 0x2663, - clubsuitwhite: 0x2667, - cmcubedsquare: 0x33A4, - cmonospace: 0xFF43, - cmsquaredsquare: 0x33A0, - coarmenian: 0x0581, - colon: 0x003A, - colonmonetary: 0x20A1, - colonmonospace: 0xFF1A, - colonsign: 0x20A1, - colonsmall: 0xFE55, - colontriangularhalfmod: 0x02D1, - colontriangularmod: 0x02D0, - comma: 0x002C, - commaabovecmb: 0x0313, - commaaboverightcmb: 0x0315, - commaaccent: 0xF6C3, - commaarabic: 0x060C, - commaarmenian: 0x055D, - commainferior: 0xF6E1, - commamonospace: 0xFF0C, - commareversedabovecmb: 0x0314, - commareversedmod: 0x02BD, - commasmall: 0xFE50, - commasuperior: 0xF6E2, - commaturnedabovecmb: 0x0312, - commaturnedmod: 0x02BB, - compass: 0x263C, - congruent: 0x2245, - contourintegral: 0x222E, - control: 0x2303, - controlACK: 0x0006, - controlBEL: 0x0007, - controlBS: 0x0008, - controlCAN: 0x0018, - controlCR: 0x000D, - controlDC1: 0x0011, - controlDC2: 0x0012, - controlDC3: 0x0013, - controlDC4: 0x0014, - controlDEL: 0x007F, - controlDLE: 0x0010, - controlEM: 0x0019, - controlENQ: 0x0005, - controlEOT: 0x0004, - controlESC: 0x001B, - controlETB: 0x0017, - controlETX: 0x0003, - controlFF: 0x000C, - controlFS: 0x001C, - controlGS: 0x001D, - controlHT: 0x0009, - controlLF: 0x000A, - controlNAK: 0x0015, - controlRS: 0x001E, - controlSI: 0x000F, - controlSO: 0x000E, - controlSOT: 0x0002, - controlSTX: 0x0001, - controlSUB: 0x001A, - controlSYN: 0x0016, - controlUS: 0x001F, - controlVT: 0x000B, - copyright: 0x00A9, - copyrightsans: 0xF8E9, - copyrightserif: 0xF6D9, - cornerbracketleft: 0x300C, - cornerbracketlefthalfwidth: 0xFF62, - cornerbracketleftvertical: 0xFE41, - cornerbracketright: 0x300D, - cornerbracketrighthalfwidth: 0xFF63, - cornerbracketrightvertical: 0xFE42, - corporationsquare: 0x337F, - cosquare: 0x33C7, - coverkgsquare: 0x33C6, - cparen: 0x249E, - cruzeiro: 0x20A2, - cstretched: 0x0297, - curlyand: 0x22CF, - curlyor: 0x22CE, - currency: 0x00A4, - cyrBreve: 0xF6D1, - cyrFlex: 0xF6D2, - cyrbreve: 0xF6D4, - cyrflex: 0xF6D5, - d: 0x0064, - daarmenian: 0x0564, - dabengali: 0x09A6, - dadarabic: 0x0636, - dadeva: 0x0926, - dadfinalarabic: 0xFEBE, - dadinitialarabic: 0xFEBF, - dadmedialarabic: 0xFEC0, - dagesh: 0x05BC, - dageshhebrew: 0x05BC, - dagger: 0x2020, - daggerdbl: 0x2021, - dagujarati: 0x0AA6, - dagurmukhi: 0x0A26, - dahiragana: 0x3060, - dakatakana: 0x30C0, - dalarabic: 0x062F, - dalet: 0x05D3, - daletdagesh: 0xFB33, - daletdageshhebrew: 0xFB33, + A: "0041", + AE: "00C6", + AEacute: "01FC", + AEmacron: "01E2", + AEsmall: "F7E6", + Aacute: "00C1", + Aacutesmall: "F7E1", + Abreve: "0102", + Abreveacute: "1EAE", + Abrevecyrillic: "04D0", + Abrevedotbelow: "1EB6", + Abrevegrave: "1EB0", + Abrevehookabove: "1EB2", + Abrevetilde: "1EB4", + Acaron: "01CD", + Acircle: "24B6", + Acircumflex: "00C2", + Acircumflexacute: "1EA4", + Acircumflexdotbelow: "1EAC", + Acircumflexgrave: "1EA6", + Acircumflexhookabove: "1EA8", + Acircumflexsmall: "F7E2", + Acircumflextilde: "1EAA", + Acute: "F6C9", + Acutesmall: "F7B4", + Acyrillic: "0410", + Adblgrave: "0200", + Adieresis: "00C4", + Adieresiscyrillic: "04D2", + Adieresismacron: "01DE", + Adieresissmall: "F7E4", + Adotbelow: "1EA0", + Adotmacron: "01E0", + Agrave: "00C0", + Agravesmall: "F7E0", + Ahookabove: "1EA2", + Aiecyrillic: "04D4", + Ainvertedbreve: "0202", + Alpha: "0391", + Alphatonos: "0386", + Amacron: "0100", + Amonospace: "FF21", + Aogonek: "0104", + Aring: "00C5", + Aringacute: "01FA", + Aringbelow: "1E00", + Aringsmall: "F7E5", + Asmall: "F761", + Atilde: "00C3", + Atildesmall: "F7E3", + Aybarmenian: "0531", + B: "0042", + Bcircle: "24B7", + Bdotaccent: "1E02", + Bdotbelow: "1E04", + Becyrillic: "0411", + Benarmenian: "0532", + Beta: "0392", + Bhook: "0181", + Blinebelow: "1E06", + Bmonospace: "FF22", + Brevesmall: "F6F4", + Bsmall: "F762", + Btopbar: "0182", + C: "0043", + Caarmenian: "053E", + Cacute: "0106", + Caron: "F6CA", + Caronsmall: "F6F5", + Ccaron: "010C", + Ccedilla: "00C7", + Ccedillaacute: "1E08", + Ccedillasmall: "F7E7", + Ccircle: "24B8", + Ccircumflex: "0108", + Cdot: "010A", + Cdotaccent: "010A", + Cedillasmall: "F7B8", + Chaarmenian: "0549", + Cheabkhasiancyrillic: "04BC", + Checyrillic: "0427", + Chedescenderabkhasiancyrillic: "04BE", + Chedescendercyrillic: "04B6", + Chedieresiscyrillic: "04F4", + Cheharmenian: "0543", + Chekhakassiancyrillic: "04CB", + Cheverticalstrokecyrillic: "04B8", + Chi: "03A7", + Chook: "0187", + Circumflexsmall: "F6F6", + Cmonospace: "FF23", + Coarmenian: "0551", + Csmall: "F763", + D: "0044", + DZ: "01F1", + DZcaron: "01C4", + Daarmenian: "0534", + Dafrican: "0189", + Dcaron: "010E", + Dcedilla: "1E10", + Dcircle: "24B9", + Dcircumflexbelow: "1E12", + Dcroat: "0110", + Ddotaccent: "1E0A", + Ddotbelow: "1E0C", + Decyrillic: "0414", + Deicoptic: "03EE", + Delta: "2206", + Deltagreek: "0394", + Dhook: "018A", + Dieresis: "F6CB", + DieresisAcute: "F6CC", + DieresisGrave: "F6CD", + Dieresissmall: "F7A8", + Digammagreek: "03DC", + Djecyrillic: "0402", + Dlinebelow: "1E0E", + Dmonospace: "FF24", + Dotaccentsmall: "F6F7", + Dslash: "0110", + Dsmall: "F764", + Dtopbar: "018B", + Dz: "01F2", + Dzcaron: "01C5", + Dzeabkhasiancyrillic: "04E0", + Dzecyrillic: "0405", + Dzhecyrillic: "040F", + E: "0045", + Eacute: "00C9", + Eacutesmall: "F7E9", + Ebreve: "0114", + Ecaron: "011A", + Ecedillabreve: "1E1C", + Echarmenian: "0535", + Ecircle: "24BA", + Ecircumflex: "00CA", + Ecircumflexacute: "1EBE", + Ecircumflexbelow: "1E18", + Ecircumflexdotbelow: "1EC6", + Ecircumflexgrave: "1EC0", + Ecircumflexhookabove: "1EC2", + Ecircumflexsmall: "F7EA", + Ecircumflextilde: "1EC4", + Ecyrillic: "0404", + Edblgrave: "0204", + Edieresis: "00CB", + Edieresissmall: "F7EB", + Edot: "0116", + Edotaccent: "0116", + Edotbelow: "1EB8", + Efcyrillic: "0424", + Egrave: "00C8", + Egravesmall: "F7E8", + Eharmenian: "0537", + Ehookabove: "1EBA", + Eightroman: "2167", + Einvertedbreve: "0206", + Eiotifiedcyrillic: "0464", + Elcyrillic: "041B", + Elevenroman: "216A", + Emacron: "0112", + Emacronacute: "1E16", + Emacrongrave: "1E14", + Emcyrillic: "041C", + Emonospace: "FF25", + Encyrillic: "041D", + Endescendercyrillic: "04A2", + Eng: "014A", + Enghecyrillic: "04A4", + Enhookcyrillic: "04C7", + Eogonek: "0118", + Eopen: "0190", + Epsilon: "0395", + Epsilontonos: "0388", + Ercyrillic: "0420", + Ereversed: "018E", + Ereversedcyrillic: "042D", + Escyrillic: "0421", + Esdescendercyrillic: "04AA", + Esh: "01A9", + Esmall: "F765", + Eta: "0397", + Etarmenian: "0538", + Etatonos: "0389", + Eth: "00D0", + Ethsmall: "F7F0", + Etilde: "1EBC", + Etildebelow: "1E1A", + Euro: "20AC", + Ezh: "01B7", + Ezhcaron: "01EE", + Ezhreversed: "01B8", + F: "0046", + Fcircle: "24BB", + Fdotaccent: "1E1E", + Feharmenian: "0556", + Feicoptic: "03E4", + Fhook: "0191", + Fitacyrillic: "0472", + Fiveroman: "2164", + Fmonospace: "FF26", + Fourroman: "2163", + Fsmall: "F766", + G: "0047", + GBsquare: "3387", + Gacute: "01F4", + Gamma: "0393", + Gammaafrican: "0194", + Gangiacoptic: "03EA", + Gbreve: "011E", + Gcaron: "01E6", + Gcedilla: "0122", + Gcircle: "24BC", + Gcircumflex: "011C", + Gcommaaccent: "0122", + Gdot: "0120", + Gdotaccent: "0120", + Gecyrillic: "0413", + Ghadarmenian: "0542", + Ghemiddlehookcyrillic: "0494", + Ghestrokecyrillic: "0492", + Gheupturncyrillic: "0490", + Ghook: "0193", + Gimarmenian: "0533", + Gjecyrillic: "0403", + Gmacron: "1E20", + Gmonospace: "FF27", + Grave: "F6CE", + Gravesmall: "F760", + Gsmall: "F767", + Gsmallhook: "029B", + Gstroke: "01E4", + H: "0048", + H18533: "25CF", + H18543: "25AA", + H18551: "25AB", + H22073: "25A1", + HPsquare: "33CB", + Haabkhasiancyrillic: "04A8", + Hadescendercyrillic: "04B2", + Hardsigncyrillic: "042A", + Hbar: "0126", + Hbrevebelow: "1E2A", + Hcedilla: "1E28", + Hcircle: "24BD", + Hcircumflex: "0124", + Hdieresis: "1E26", + Hdotaccent: "1E22", + Hdotbelow: "1E24", + Hmonospace: "FF28", + Hoarmenian: "0540", + Horicoptic: "03E8", + Hsmall: "F768", + Hungarumlaut: "F6CF", + Hungarumlautsmall: "F6F8", + Hzsquare: "3390", + I: "0049", + IAcyrillic: "042F", + IJ: "0132", + IUcyrillic: "042E", + Iacute: "00CD", + Iacutesmall: "F7ED", + Ibreve: "012C", + Icaron: "01CF", + Icircle: "24BE", + Icircumflex: "00CE", + Icircumflexsmall: "F7EE", + Icyrillic: "0406", + Idblgrave: "0208", + Idieresis: "00CF", + Idieresisacute: "1E2E", + Idieresiscyrillic: "04E4", + Idieresissmall: "F7EF", + Idot: "0130", + Idotaccent: "0130", + Idotbelow: "1ECA", + Iebrevecyrillic: "04D6", + Iecyrillic: "0415", + Ifraktur: "2111", + Igrave: "00CC", + Igravesmall: "F7EC", + Ihookabove: "1EC8", + Iicyrillic: "0418", + Iinvertedbreve: "020A", + Iishortcyrillic: "0419", + Imacron: "012A", + Imacroncyrillic: "04E2", + Imonospace: "FF29", + Iniarmenian: "053B", + Iocyrillic: "0401", + Iogonek: "012E", + Iota: "0399", + Iotaafrican: "0196", + Iotadieresis: "03AA", + Iotatonos: "038A", + Ismall: "F769", + Istroke: "0197", + Itilde: "0128", + Itildebelow: "1E2C", + Izhitsacyrillic: "0474", + Izhitsadblgravecyrillic: "0476", + J: "004A", + Jaarmenian: "0541", + Jcircle: "24BF", + Jcircumflex: "0134", + Jecyrillic: "0408", + Jheharmenian: "054B", + Jmonospace: "FF2A", + Jsmall: "F76A", + K: "004B", + KBsquare: "3385", + KKsquare: "33CD", + Kabashkircyrillic: "04A0", + Kacute: "1E30", + Kacyrillic: "041A", + Kadescendercyrillic: "049A", + Kahookcyrillic: "04C3", + Kappa: "039A", + Kastrokecyrillic: "049E", + Kaverticalstrokecyrillic: "049C", + Kcaron: "01E8", + Kcedilla: "0136", + Kcircle: "24C0", + Kcommaaccent: "0136", + Kdotbelow: "1E32", + Keharmenian: "0554", + Kenarmenian: "053F", + Khacyrillic: "0425", + Kheicoptic: "03E6", + Khook: "0198", + Kjecyrillic: "040C", + Klinebelow: "1E34", + Kmonospace: "FF2B", + Koppacyrillic: "0480", + Koppagreek: "03DE", + Ksicyrillic: "046E", + Ksmall: "F76B", + L: "004C", + LJ: "01C7", + LL: "F6BF", + Lacute: "0139", + Lambda: "039B", + Lcaron: "013D", + Lcedilla: "013B", + Lcircle: "24C1", + Lcircumflexbelow: "1E3C", + Lcommaaccent: "013B", + Ldot: "013F", + Ldotaccent: "013F", + Ldotbelow: "1E36", + Ldotbelowmacron: "1E38", + Liwnarmenian: "053C", + Lj: "01C8", + Ljecyrillic: "0409", + Llinebelow: "1E3A", + Lmonospace: "FF2C", + Lslash: "0141", + Lslashsmall: "F6F9", + Lsmall: "F76C", + M: "004D", + MBsquare: "3386", + Macron: "F6D0", + Macronsmall: "F7AF", + Macute: "1E3E", + Mcircle: "24C2", + Mdotaccent: "1E40", + Mdotbelow: "1E42", + Menarmenian: "0544", + Mmonospace: "FF2D", + Msmall: "F76D", + Mturned: "019C", + Mu: "039C", + N: "004E", + NJ: "01CA", + Nacute: "0143", + Ncaron: "0147", + Ncedilla: "0145", + Ncircle: "24C3", + Ncircumflexbelow: "1E4A", + Ncommaaccent: "0145", + Ndotaccent: "1E44", + Ndotbelow: "1E46", + Nhookleft: "019D", + Nineroman: "2168", + Nj: "01CB", + Njecyrillic: "040A", + Nlinebelow: "1E48", + Nmonospace: "FF2E", + Nowarmenian: "0546", + Nsmall: "F76E", + Ntilde: "00D1", + Ntildesmall: "F7F1", + Nu: "039D", + O: "004F", + OE: "0152", + OEsmall: "F6FA", + Oacute: "00D3", + Oacutesmall: "F7F3", + Obarredcyrillic: "04E8", + Obarreddieresiscyrillic: "04EA", + Obreve: "014E", + Ocaron: "01D1", + Ocenteredtilde: "019F", + Ocircle: "24C4", + Ocircumflex: "00D4", + Ocircumflexacute: "1ED0", + Ocircumflexdotbelow: "1ED8", + Ocircumflexgrave: "1ED2", + Ocircumflexhookabove: "1ED4", + Ocircumflexsmall: "F7F4", + Ocircumflextilde: "1ED6", + Ocyrillic: "041E", + Odblacute: "0150", + Odblgrave: "020C", + Odieresis: "00D6", + Odieresiscyrillic: "04E6", + Odieresissmall: "F7F6", + Odotbelow: "1ECC", + Ogoneksmall: "F6FB", + Ograve: "00D2", + Ogravesmall: "F7F2", + Oharmenian: "0555", + Ohm: "2126", + Ohookabove: "1ECE", + Ohorn: "01A0", + Ohornacute: "1EDA", + Ohorndotbelow: "1EE2", + Ohorngrave: "1EDC", + Ohornhookabove: "1EDE", + Ohorntilde: "1EE0", + Ohungarumlaut: "0150", + Oi: "01A2", + Oinvertedbreve: "020E", + Omacron: "014C", + Omacronacute: "1E52", + Omacrongrave: "1E50", + Omega: "2126", + Omegacyrillic: "0460", + Omegagreek: "03A9", + Omegaroundcyrillic: "047A", + Omegatitlocyrillic: "047C", + Omegatonos: "038F", + Omicron: "039F", + Omicrontonos: "038C", + Omonospace: "FF2F", + Oneroman: "2160", + Oogonek: "01EA", + Oogonekmacron: "01EC", + Oopen: "0186", + Oslash: "00D8", + Oslashacute: "01FE", + Oslashsmall: "F7F8", + Osmall: "F76F", + Ostrokeacute: "01FE", + Otcyrillic: "047E", + Otilde: "00D5", + Otildeacute: "1E4C", + Otildedieresis: "1E4E", + Otildesmall: "F7F5", + P: "0050", + Pacute: "1E54", + Pcircle: "24C5", + Pdotaccent: "1E56", + Pecyrillic: "041F", + Peharmenian: "054A", + Pemiddlehookcyrillic: "04A6", + Phi: "03A6", + Phook: "01A4", + Pi: "03A0", + Piwrarmenian: "0553", + Pmonospace: "FF30", + Psi: "03A8", + Psicyrillic: "0470", + Psmall: "F770", + Q: "0051", + Qcircle: "24C6", + Qmonospace: "FF31", + Qsmall: "F771", + R: "0052", + Raarmenian: "054C", + Racute: "0154", + Rcaron: "0158", + Rcedilla: "0156", + Rcircle: "24C7", + Rcommaaccent: "0156", + Rdblgrave: "0210", + Rdotaccent: "1E58", + Rdotbelow: "1E5A", + Rdotbelowmacron: "1E5C", + Reharmenian: "0550", + Rfraktur: "211C", + Rho: "03A1", + Ringsmall: "F6FC", + Rinvertedbreve: "0212", + Rlinebelow: "1E5E", + Rmonospace: "FF32", + Rsmall: "F772", + Rsmallinverted: "0281", + Rsmallinvertedsuperior: "02B6", + S: "0053", + SF010000: "250C", + SF020000: "2514", + SF030000: "2510", + SF040000: "2518", + SF050000: "253C", + SF060000: "252C", + SF070000: "2534", + SF080000: "251C", + SF090000: "2524", + SF100000: "2500", + SF110000: "2502", + SF190000: "2561", + SF200000: "2562", + SF210000: "2556", + SF220000: "2555", + SF230000: "2563", + SF240000: "2551", + SF250000: "2557", + SF260000: "255D", + SF270000: "255C", + SF280000: "255B", + SF360000: "255E", + SF370000: "255F", + SF380000: "255A", + SF390000: "2554", + SF400000: "2569", + SF410000: "2566", + SF420000: "2560", + SF430000: "2550", + SF440000: "256C", + SF450000: "2567", + SF460000: "2568", + SF470000: "2564", + SF480000: "2565", + SF490000: "2559", + SF500000: "2558", + SF510000: "2552", + SF520000: "2553", + SF530000: "256B", + SF540000: "256A", + Sacute: "015A", + Sacutedotaccent: "1E64", + Sampigreek: "03E0", + Scaron: "0160", + Scarondotaccent: "1E66", + Scaronsmall: "F6FD", + Scedilla: "015E", + Schwa: "018F", + Schwacyrillic: "04D8", + Schwadieresiscyrillic: "04DA", + Scircle: "24C8", + Scircumflex: "015C", + Scommaaccent: "0218", + Sdotaccent: "1E60", + Sdotbelow: "1E62", + Sdotbelowdotaccent: "1E68", + Seharmenian: "054D", + Sevenroman: "2166", + Shaarmenian: "0547", + Shacyrillic: "0428", + Shchacyrillic: "0429", + Sheicoptic: "03E2", + Shhacyrillic: "04BA", + Shimacoptic: "03EC", + Sigma: "03A3", + Sixroman: "2165", + Smonospace: "FF33", + Softsigncyrillic: "042C", + Ssmall: "F773", + Stigmagreek: "03DA", + T: "0054", + Tau: "03A4", + Tbar: "0166", + Tcaron: "0164", + Tcedilla: "0162", + Tcircle: "24C9", + Tcircumflexbelow: "1E70", + Tcommaaccent: "0162", + Tdotaccent: "1E6A", + Tdotbelow: "1E6C", + Tecyrillic: "0422", + Tedescendercyrillic: "04AC", + Tenroman: "2169", + Tetsecyrillic: "04B4", + Theta: "0398", + Thook: "01AC", + Thorn: "00DE", + Thornsmall: "F7FE", + Threeroman: "2162", + Tildesmall: "F6FE", + Tiwnarmenian: "054F", + Tlinebelow: "1E6E", + Tmonospace: "FF34", + Toarmenian: "0539", + Tonefive: "01BC", + Tonesix: "0184", + Tonetwo: "01A7", + Tretroflexhook: "01AE", + Tsecyrillic: "0426", + Tshecyrillic: "040B", + Tsmall: "F774", + Twelveroman: "216B", + Tworoman: "2161", + U: "0055", + Uacute: "00DA", + Uacutesmall: "F7FA", + Ubreve: "016C", + Ucaron: "01D3", + Ucircle: "24CA", + Ucircumflex: "00DB", + Ucircumflexbelow: "1E76", + Ucircumflexsmall: "F7FB", + Ucyrillic: "0423", + Udblacute: "0170", + Udblgrave: "0214", + Udieresis: "00DC", + Udieresisacute: "01D7", + Udieresisbelow: "1E72", + Udieresiscaron: "01D9", + Udieresiscyrillic: "04F0", + Udieresisgrave: "01DB", + Udieresismacron: "01D5", + Udieresissmall: "F7FC", + Udotbelow: "1EE4", + Ugrave: "00D9", + Ugravesmall: "F7F9", + Uhookabove: "1EE6", + Uhorn: "01AF", + Uhornacute: "1EE8", + Uhorndotbelow: "1EF0", + Uhorngrave: "1EEA", + Uhornhookabove: "1EEC", + Uhorntilde: "1EEE", + Uhungarumlaut: "0170", + Uhungarumlautcyrillic: "04F2", + Uinvertedbreve: "0216", + Ukcyrillic: "0478", + Umacron: "016A", + Umacroncyrillic: "04EE", + Umacrondieresis: "1E7A", + Umonospace: "FF35", + Uogonek: "0172", + Upsilon: "03A5", + Upsilon1: "03D2", + Upsilonacutehooksymbolgreek: "03D3", + Upsilonafrican: "01B1", + Upsilondieresis: "03AB", + Upsilondieresishooksymbolgreek: "03D4", + Upsilonhooksymbol: "03D2", + Upsilontonos: "038E", + Uring: "016E", + Ushortcyrillic: "040E", + Usmall: "F775", + Ustraightcyrillic: "04AE", + Ustraightstrokecyrillic: "04B0", + Utilde: "0168", + Utildeacute: "1E78", + Utildebelow: "1E74", + V: "0056", + Vcircle: "24CB", + Vdotbelow: "1E7E", + Vecyrillic: "0412", + Vewarmenian: "054E", + Vhook: "01B2", + Vmonospace: "FF36", + Voarmenian: "0548", + Vsmall: "F776", + Vtilde: "1E7C", + W: "0057", + Wacute: "1E82", + Wcircle: "24CC", + Wcircumflex: "0174", + Wdieresis: "1E84", + Wdotaccent: "1E86", + Wdotbelow: "1E88", + Wgrave: "1E80", + Wmonospace: "FF37", + Wsmall: "F777", + X: "0058", + Xcircle: "24CD", + Xdieresis: "1E8C", + Xdotaccent: "1E8A", + Xeharmenian: "053D", + Xi: "039E", + Xmonospace: "FF38", + Xsmall: "F778", + Y: "0059", + Yacute: "00DD", + Yacutesmall: "F7FD", + Yatcyrillic: "0462", + Ycircle: "24CE", + Ycircumflex: "0176", + Ydieresis: "0178", + Ydieresissmall: "F7FF", + Ydotaccent: "1E8E", + Ydotbelow: "1EF4", + Yericyrillic: "042B", + Yerudieresiscyrillic: "04F8", + Ygrave: "1EF2", + Yhook: "01B3", + Yhookabove: "1EF6", + Yiarmenian: "0545", + Yicyrillic: "0407", + Yiwnarmenian: "0552", + Ymonospace: "FF39", + Ysmall: "F779", + Ytilde: "1EF8", + Yusbigcyrillic: "046A", + Yusbigiotifiedcyrillic: "046C", + Yuslittlecyrillic: "0466", + Yuslittleiotifiedcyrillic: "0468", + Z: "005A", + Zaarmenian: "0536", + Zacute: "0179", + Zcaron: "017D", + Zcaronsmall: "F6FF", + Zcircle: "24CF", + Zcircumflex: "1E90", + Zdot: "017B", + Zdotaccent: "017B", + Zdotbelow: "1E92", + Zecyrillic: "0417", + Zedescendercyrillic: "0498", + Zedieresiscyrillic: "04DE", + Zeta: "0396", + Zhearmenian: "053A", + Zhebrevecyrillic: "04C1", + Zhecyrillic: "0416", + Zhedescendercyrillic: "0496", + Zhedieresiscyrillic: "04DC", + Zlinebelow: "1E94", + Zmonospace: "FF3A", + Zsmall: "F77A", + Zstroke: "01B5", + a: "0061", + aabengali: "0986", + aacute: "00E1", + aadeva: "0906", + aagujarati: "0A86", + aagurmukhi: "0A06", + aamatragurmukhi: "0A3E", + aarusquare: "3303", + aavowelsignbengali: "09BE", + aavowelsigndeva: "093E", + aavowelsigngujarati: "0ABE", + abbreviationmarkarmenian: "055F", + abbreviationsigndeva: "0970", + abengali: "0985", + abopomofo: "311A", + abreve: "0103", + abreveacute: "1EAF", + abrevecyrillic: "04D1", + abrevedotbelow: "1EB7", + abrevegrave: "1EB1", + abrevehookabove: "1EB3", + abrevetilde: "1EB5", + acaron: "01CE", + acircle: "24D0", + acircumflex: "00E2", + acircumflexacute: "1EA5", + acircumflexdotbelow: "1EAD", + acircumflexgrave: "1EA7", + acircumflexhookabove: "1EA9", + acircumflextilde: "1EAB", + acute: "00B4", + acutebelowcmb: "0317", + acutecmb: "0301", + acutecomb: "0301", + acutedeva: "0954", + acutelowmod: "02CF", + acutetonecmb: "0341", + acyrillic: "0430", + adblgrave: "0201", + addakgurmukhi: "0A71", + adeva: "0905", + adieresis: "00E4", + adieresiscyrillic: "04D3", + adieresismacron: "01DF", + adotbelow: "1EA1", + adotmacron: "01E1", + ae: "00E6", + aeacute: "01FD", + aekorean: "3150", + aemacron: "01E3", + afii00208: "2015", + afii08941: "20A4", + afii10017: "0410", + afii10018: "0411", + afii10019: "0412", + afii10020: "0413", + afii10021: "0414", + afii10022: "0415", + afii10023: "0401", + afii10024: "0416", + afii10025: "0417", + afii10026: "0418", + afii10027: "0419", + afii10028: "041A", + afii10029: "041B", + afii10030: "041C", + afii10031: "041D", + afii10032: "041E", + afii10033: "041F", + afii10034: "0420", + afii10035: "0421", + afii10036: "0422", + afii10037: "0423", + afii10038: "0424", + afii10039: "0425", + afii10040: "0426", + afii10041: "0427", + afii10042: "0428", + afii10043: "0429", + afii10044: "042A", + afii10045: "042B", + afii10046: "042C", + afii10047: "042D", + afii10048: "042E", + afii10049: "042F", + afii10050: "0490", + afii10051: "0402", + afii10052: "0403", + afii10053: "0404", + afii10054: "0405", + afii10055: "0406", + afii10056: "0407", + afii10057: "0408", + afii10058: "0409", + afii10059: "040A", + afii10060: "040B", + afii10061: "040C", + afii10062: "040E", + afii10063: "F6C4", + afii10064: "F6C5", + afii10065: "0430", + afii10066: "0431", + afii10067: "0432", + afii10068: "0433", + afii10069: "0434", + afii10070: "0435", + afii10071: "0451", + afii10072: "0436", + afii10073: "0437", + afii10074: "0438", + afii10075: "0439", + afii10076: "043A", + afii10077: "043B", + afii10078: "043C", + afii10079: "043D", + afii10080: "043E", + afii10081: "043F", + afii10082: "0440", + afii10083: "0441", + afii10084: "0442", + afii10085: "0443", + afii10086: "0444", + afii10087: "0445", + afii10088: "0446", + afii10089: "0447", + afii10090: "0448", + afii10091: "0449", + afii10092: "044A", + afii10093: "044B", + afii10094: "044C", + afii10095: "044D", + afii10096: "044E", + afii10097: "044F", + afii10098: "0491", + afii10099: "0452", + afii10100: "0453", + afii10101: "0454", + afii10102: "0455", + afii10103: "0456", + afii10104: "0457", + afii10105: "0458", + afii10106: "0459", + afii10107: "045A", + afii10108: "045B", + afii10109: "045C", + afii10110: "045E", + afii10145: "040F", + afii10146: "0462", + afii10147: "0472", + afii10148: "0474", + afii10192: "F6C6", + afii10193: "045F", + afii10194: "0463", + afii10195: "0473", + afii10196: "0475", + afii10831: "F6C7", + afii10832: "F6C8", + afii10846: "04D9", + afii299: "200E", + afii300: "200F", + afii301: "200D", + afii57381: "066A", + afii57388: "060C", + afii57392: "0660", + afii57393: "0661", + afii57394: "0662", + afii57395: "0663", + afii57396: "0664", + afii57397: "0665", + afii57398: "0666", + afii57399: "0667", + afii57400: "0668", + afii57401: "0669", + afii57403: "061B", + afii57407: "061F", + afii57409: "0621", + afii57410: "0622", + afii57411: "0623", + afii57412: "0624", + afii57413: "0625", + afii57414: "0626", + afii57415: "0627", + afii57416: "0628", + afii57417: "0629", + afii57418: "062A", + afii57419: "062B", + afii57420: "062C", + afii57421: "062D", + afii57422: "062E", + afii57423: "062F", + afii57424: "0630", + afii57425: "0631", + afii57426: "0632", + afii57427: "0633", + afii57428: "0634", + afii57429: "0635", + afii57430: "0636", + afii57431: "0637", + afii57432: "0638", + afii57433: "0639", + afii57434: "063A", + afii57440: "0640", + afii57441: "0641", + afii57442: "0642", + afii57443: "0643", + afii57444: "0644", + afii57445: "0645", + afii57446: "0646", + afii57448: "0648", + afii57449: "0649", + afii57450: "064A", + afii57451: "064B", + afii57452: "064C", + afii57453: "064D", + afii57454: "064E", + afii57455: "064F", + afii57456: "0650", + afii57457: "0651", + afii57458: "0652", + afii57470: "0647", + afii57505: "06A4", + afii57506: "067E", + afii57507: "0686", + afii57508: "0698", + afii57509: "06AF", + afii57511: "0679", + afii57512: "0688", + afii57513: "0691", + afii57514: "06BA", + afii57519: "06D2", + afii57534: "06D5", + afii57636: "20AA", + afii57645: "05BE", + afii57658: "05C3", + afii57664: "05D0", + afii57665: "05D1", + afii57666: "05D2", + afii57667: "05D3", + afii57668: "05D4", + afii57669: "05D5", + afii57670: "05D6", + afii57671: "05D7", + afii57672: "05D8", + afii57673: "05D9", + afii57674: "05DA", + afii57675: "05DB", + afii57676: "05DC", + afii57677: "05DD", + afii57678: "05DE", + afii57679: "05DF", + afii57680: "05E0", + afii57681: "05E1", + afii57682: "05E2", + afii57683: "05E3", + afii57684: "05E4", + afii57685: "05E5", + afii57686: "05E6", + afii57687: "05E7", + afii57688: "05E8", + afii57689: "05E9", + afii57690: "05EA", + afii57694: "FB2A", + afii57695: "FB2B", + afii57700: "FB4B", + afii57705: "FB1F", + afii57716: "05F0", + afii57717: "05F1", + afii57718: "05F2", + afii57723: "FB35", + afii57793: "05B4", + afii57794: "05B5", + afii57795: "05B6", + afii57796: "05BB", + afii57797: "05B8", + afii57798: "05B7", + afii57799: "05B0", + afii57800: "05B2", + afii57801: "05B1", + afii57802: "05B3", + afii57803: "05C2", + afii57804: "05C1", + afii57806: "05B9", + afii57807: "05BC", + afii57839: "05BD", + afii57841: "05BF", + afii57842: "05C0", + afii57929: "02BC", + afii61248: "2105", + afii61289: "2113", + afii61352: "2116", + afii61573: "202C", + afii61574: "202D", + afii61575: "202E", + afii61664: "200C", + afii63167: "066D", + afii64937: "02BD", + agrave: "00E0", + agujarati: "0A85", + agurmukhi: "0A05", + ahiragana: "3042", + ahookabove: "1EA3", + aibengali: "0990", + aibopomofo: "311E", + aideva: "0910", + aiecyrillic: "04D5", + aigujarati: "0A90", + aigurmukhi: "0A10", + aimatragurmukhi: "0A48", + ainarabic: "0639", + ainfinalarabic: "FECA", + aininitialarabic: "FECB", + ainmedialarabic: "FECC", + ainvertedbreve: "0203", + aivowelsignbengali: "09C8", + aivowelsigndeva: "0948", + aivowelsigngujarati: "0AC8", + akatakana: "30A2", + akatakanahalfwidth: "FF71", + akorean: "314F", + alef: "05D0", + alefarabic: "0627", + alefdageshhebrew: "FB30", + aleffinalarabic: "FE8E", + alefhamzaabovearabic: "0623", + alefhamzaabovefinalarabic: "FE84", + alefhamzabelowarabic: "0625", + alefhamzabelowfinalarabic: "FE88", + alefhebrew: "05D0", + aleflamedhebrew: "FB4F", + alefmaddaabovearabic: "0622", + alefmaddaabovefinalarabic: "FE82", + alefmaksuraarabic: "0649", + alefmaksurafinalarabic: "FEF0", + alefmaksurainitialarabic: "FEF3", + alefmaksuramedialarabic: "FEF4", + alefpatahhebrew: "FB2E", + alefqamatshebrew: "FB2F", + aleph: "2135", + allequal: "224C", + alpha: "03B1", + alphatonos: "03AC", + amacron: "0101", + amonospace: "FF41", + ampersand: "0026", + ampersandmonospace: "FF06", + ampersandsmall: "F726", + amsquare: "33C2", + anbopomofo: "3122", + angbopomofo: "3124", + angkhankhuthai: "0E5A", + angle: "2220", + anglebracketleft: "3008", + anglebracketleftvertical: "FE3F", + anglebracketright: "3009", + anglebracketrightvertical: "FE40", + angleleft: "2329", + angleright: "232A", + angstrom: "212B", + anoteleia: "0387", + anudattadeva: "0952", + anusvarabengali: "0982", + anusvaradeva: "0902", + anusvaragujarati: "0A82", + aogonek: "0105", + apaatosquare: "3300", + aparen: "249C", + apostrophearmenian: "055A", + apostrophemod: "02BC", + apple: "F8FF", + approaches: "2250", + approxequal: "2248", + approxequalorimage: "2252", + approximatelyequal: "2245", + araeaekorean: "318E", + araeakorean: "318D", + arc: "2312", + arighthalfring: "1E9A", + aring: "00E5", + aringacute: "01FB", + aringbelow: "1E01", + arrowboth: "2194", + arrowdashdown: "21E3", + arrowdashleft: "21E0", + arrowdashright: "21E2", + arrowdashup: "21E1", + arrowdblboth: "21D4", + arrowdbldown: "21D3", + arrowdblleft: "21D0", + arrowdblright: "21D2", + arrowdblup: "21D1", + arrowdown: "2193", + arrowdownleft: "2199", + arrowdownright: "2198", + arrowdownwhite: "21E9", + arrowheaddownmod: "02C5", + arrowheadleftmod: "02C2", + arrowheadrightmod: "02C3", + arrowheadupmod: "02C4", + arrowhorizex: "F8E7", + arrowleft: "2190", + arrowleftdbl: "21D0", + arrowleftdblstroke: "21CD", + arrowleftoverright: "21C6", + arrowleftwhite: "21E6", + arrowright: "2192", + arrowrightdblstroke: "21CF", + arrowrightheavy: "279E", + arrowrightoverleft: "21C4", + arrowrightwhite: "21E8", + arrowtableft: "21E4", + arrowtabright: "21E5", + arrowup: "2191", + arrowupdn: "2195", + arrowupdnbse: "21A8", + arrowupdownbase: "21A8", + arrowupleft: "2196", + arrowupleftofdown: "21C5", + arrowupright: "2197", + arrowupwhite: "21E7", + arrowvertex: "F8E6", + asciicircum: "005E", + asciicircummonospace: "FF3E", + asciitilde: "007E", + asciitildemonospace: "FF5E", + ascript: "0251", + ascriptturned: "0252", + asmallhiragana: "3041", + asmallkatakana: "30A1", + asmallkatakanahalfwidth: "FF67", + asterisk: "002A", + asteriskaltonearabic: "066D", + asteriskarabic: "066D", + asteriskmath: "2217", + asteriskmonospace: "FF0A", + asterisksmall: "FE61", + asterism: "2042", + asuperior: "F6E9", + asymptoticallyequal: "2243", + at: "0040", + atilde: "00E3", + atmonospace: "FF20", + atsmall: "FE6B", + aturned: "0250", + aubengali: "0994", + aubopomofo: "3120", + audeva: "0914", + augujarati: "0A94", + augurmukhi: "0A14", + aulengthmarkbengali: "09D7", + aumatragurmukhi: "0A4C", + auvowelsignbengali: "09CC", + auvowelsigndeva: "094C", + auvowelsigngujarati: "0ACC", + avagrahadeva: "093D", + aybarmenian: "0561", + ayin: "05E2", + ayinaltonehebrew: "FB20", + ayinhebrew: "05E2", + b: "0062", + babengali: "09AC", + backslash: "005C", + backslashmonospace: "FF3C", + badeva: "092C", + bagujarati: "0AAC", + bagurmukhi: "0A2C", + bahiragana: "3070", + bahtthai: "0E3F", + bakatakana: "30D0", + bar: "007C", + barmonospace: "FF5C", + bbopomofo: "3105", + bcircle: "24D1", + bdotaccent: "1E03", + bdotbelow: "1E05", + beamedsixteenthnotes: "266C", + because: "2235", + becyrillic: "0431", + beharabic: "0628", + behfinalarabic: "FE90", + behinitialarabic: "FE91", + behiragana: "3079", + behmedialarabic: "FE92", + behmeeminitialarabic: "FC9F", + behmeemisolatedarabic: "FC08", + behnoonfinalarabic: "FC6D", + bekatakana: "30D9", + benarmenian: "0562", + bet: "05D1", + beta: "03B2", + betasymbolgreek: "03D0", + betdagesh: "FB31", + betdageshhebrew: "FB31", + bethebrew: "05D1", + betrafehebrew: "FB4C", + bhabengali: "09AD", + bhadeva: "092D", + bhagujarati: "0AAD", + bhagurmukhi: "0A2D", + bhook: "0253", + bihiragana: "3073", + bikatakana: "30D3", + bilabialclick: "0298", + bindigurmukhi: "0A02", + birusquare: "3331", + blackcircle: "25CF", + blackdiamond: "25C6", + blackdownpointingtriangle: "25BC", + blackleftpointingpointer: "25C4", + blackleftpointingtriangle: "25C0", + blacklenticularbracketleft: "3010", + blacklenticularbracketleftvertical: "FE3B", + blacklenticularbracketright: "3011", + blacklenticularbracketrightvertical: "FE3C", + blacklowerlefttriangle: "25E3", + blacklowerrighttriangle: "25E2", + blackrectangle: "25AC", + blackrightpointingpointer: "25BA", + blackrightpointingtriangle: "25B6", + blacksmallsquare: "25AA", + blacksmilingface: "263B", + blacksquare: "25A0", + blackstar: "2605", + blackupperlefttriangle: "25E4", + blackupperrighttriangle: "25E5", + blackuppointingsmalltriangle: "25B4", + blackuppointingtriangle: "25B2", + blank: "2423", + blinebelow: "1E07", + block: "2588", + bmonospace: "FF42", + bobaimaithai: "0E1A", + bohiragana: "307C", + bokatakana: "30DC", + bparen: "249D", + bqsquare: "33C3", + braceex: "F8F4", + braceleft: "007B", + braceleftbt: "F8F3", + braceleftmid: "F8F2", + braceleftmonospace: "FF5B", + braceleftsmall: "FE5B", + bracelefttp: "F8F1", + braceleftvertical: "FE37", + braceright: "007D", + bracerightbt: "F8FE", + bracerightmid: "F8FD", + bracerightmonospace: "FF5D", + bracerightsmall: "FE5C", + bracerighttp: "F8FC", + bracerightvertical: "FE38", + bracketleft: "005B", + bracketleftbt: "F8F0", + bracketleftex: "F8EF", + bracketleftmonospace: "FF3B", + bracketlefttp: "F8EE", + bracketright: "005D", + bracketrightbt: "F8FB", + bracketrightex: "F8FA", + bracketrightmonospace: "FF3D", + bracketrighttp: "F8F9", + breve: "02D8", + brevebelowcmb: "032E", + brevecmb: "0306", + breveinvertedbelowcmb: "032F", + breveinvertedcmb: "0311", + breveinverteddoublecmb: "0361", + bridgebelowcmb: "032A", + bridgeinvertedbelowcmb: "033A", + brokenbar: "00A6", + bstroke: "0180", + bsuperior: "F6EA", + btopbar: "0183", + buhiragana: "3076", + bukatakana: "30D6", + bullet: "2022", + bulletinverse: "25D8", + bulletoperator: "2219", + bullseye: "25CE", + c: "0063", + caarmenian: "056E", + cabengali: "099A", + cacute: "0107", + cadeva: "091A", + cagujarati: "0A9A", + cagurmukhi: "0A1A", + calsquare: "3388", + candrabindubengali: "0981", + candrabinducmb: "0310", + candrabindudeva: "0901", + candrabindugujarati: "0A81", + capslock: "21EA", + careof: "2105", + caron: "02C7", + caronbelowcmb: "032C", + caroncmb: "030C", + carriagereturn: "21B5", + cbopomofo: "3118", + ccaron: "010D", + ccedilla: "00E7", + ccedillaacute: "1E09", + ccircle: "24D2", + ccircumflex: "0109", + ccurl: "0255", + cdot: "010B", + cdotaccent: "010B", + cdsquare: "33C5", + cedilla: "00B8", + cedillacmb: "0327", + cent: "00A2", + centigrade: "2103", + centinferior: "F6DF", + centmonospace: "FFE0", + centoldstyle: "F7A2", + centsuperior: "F6E0", + chaarmenian: "0579", + chabengali: "099B", + chadeva: "091B", + chagujarati: "0A9B", + chagurmukhi: "0A1B", + chbopomofo: "3114", + cheabkhasiancyrillic: "04BD", + checkmark: "2713", + checyrillic: "0447", + chedescenderabkhasiancyrillic: "04BF", + chedescendercyrillic: "04B7", + chedieresiscyrillic: "04F5", + cheharmenian: "0573", + chekhakassiancyrillic: "04CC", + cheverticalstrokecyrillic: "04B9", + chi: "03C7", + chieuchacirclekorean: "3277", + chieuchaparenkorean: "3217", + chieuchcirclekorean: "3269", + chieuchkorean: "314A", + chieuchparenkorean: "3209", + chochangthai: "0E0A", + chochanthai: "0E08", + chochingthai: "0E09", + chochoethai: "0E0C", + chook: "0188", + cieucacirclekorean: "3276", + cieucaparenkorean: "3216", + cieuccirclekorean: "3268", + cieuckorean: "3148", + cieucparenkorean: "3208", + cieucuparenkorean: "321C", + circle: "25CB", + circlemultiply: "2297", + circleot: "2299", + circleplus: "2295", + circlepostalmark: "3036", + circlewithlefthalfblack: "25D0", + circlewithrighthalfblack: "25D1", + circumflex: "02C6", + circumflexbelowcmb: "032D", + circumflexcmb: "0302", + clear: "2327", + clickalveolar: "01C2", + clickdental: "01C0", + clicklateral: "01C1", + clickretroflex: "01C3", + club: "2663", + clubsuitblack: "2663", + clubsuitwhite: "2667", + cmcubedsquare: "33A4", + cmonospace: "FF43", + cmsquaredsquare: "33A0", + coarmenian: "0581", + colon: "003A", + colonmonetary: "20A1", + colonmonospace: "FF1A", + colonsign: "20A1", + colonsmall: "FE55", + colontriangularhalfmod: "02D1", + colontriangularmod: "02D0", + comma: "002C", + commaabovecmb: "0313", + commaaboverightcmb: "0315", + commaaccent: "F6C3", + commaarabic: "060C", + commaarmenian: "055D", + commainferior: "F6E1", + commamonospace: "FF0C", + commareversedabovecmb: "0314", + commareversedmod: "02BD", + commasmall: "FE50", + commasuperior: "F6E2", + commaturnedabovecmb: "0312", + commaturnedmod: "02BB", + compass: "263C", + congruent: "2245", + contourintegral: "222E", + control: "2303", + controlACK: "0006", + controlBEL: "0007", + controlBS: "0008", + controlCAN: "0018", + controlCR: "000D", + controlDC1: "0011", + controlDC2: "0012", + controlDC3: "0013", + controlDC4: "0014", + controlDEL: "007F", + controlDLE: "0010", + controlEM: "0019", + controlENQ: "0005", + controlEOT: "0004", + controlESC: "001B", + controlETB: "0017", + controlETX: "0003", + controlFF: "000C", + controlFS: "001C", + controlGS: "001D", + controlHT: "0009", + controlLF: "000A", + controlNAK: "0015", + controlRS: "001E", + controlSI: "000F", + controlSO: "000E", + controlSOT: "0002", + controlSTX: "0001", + controlSUB: "001A", + controlSYN: "0016", + controlUS: "001F", + controlVT: "000B", + copyright: "00A9", + copyrightsans: "F8E9", + copyrightserif: "F6D9", + cornerbracketleft: "300C", + cornerbracketlefthalfwidth: "FF62", + cornerbracketleftvertical: "FE41", + cornerbracketright: "300D", + cornerbracketrighthalfwidth: "FF63", + cornerbracketrightvertical: "FE42", + corporationsquare: "337F", + cosquare: "33C7", + coverkgsquare: "33C6", + cparen: "249E", + cruzeiro: "20A2", + cstretched: "0297", + curlyand: "22CF", + curlyor: "22CE", + currency: "00A4", + cyrBreve: "F6D1", + cyrFlex: "F6D2", + cyrbreve: "F6D4", + cyrflex: "F6D5", + d: "0064", + daarmenian: "0564", + dabengali: "09A6", + dadarabic: "0636", + dadeva: "0926", + dadfinalarabic: "FEBE", + dadinitialarabic: "FEBF", + dadmedialarabic: "FEC0", + dagesh: "05BC", + dageshhebrew: "05BC", + dagger: "2020", + daggerdbl: "2021", + dagujarati: "0AA6", + dagurmukhi: "0A26", + dahiragana: "3060", + dakatakana: "30C0", + dalarabic: "062F", + dalet: "05D3", + daletdagesh: "FB33", + daletdageshhebrew: "FB33", dalethatafpatah: "05D3 05B2", dalethatafpatahhebrew: "05D3 05B2", dalethatafsegol: "05D3 05B1", dalethatafsegolhebrew: "05D3 05B1", - dalethebrew: 0x05D3, + dalethebrew: "05D3", dalethiriq: "05D3 05B4", dalethiriqhebrew: "05D3 05B4", daletholam: "05D3 05B9", @@ -1521,1641 +1521,1641 @@ var GlyphsUnicode = { daletshevahebrew: "05D3 05B0", dalettsere: "05D3 05B5", dalettserehebrew: "05D3 05B5", - dalfinalarabic: 0xFEAA, - dammaarabic: 0x064F, - dammalowarabic: 0x064F, - dammatanaltonearabic: 0x064C, - dammatanarabic: 0x064C, - danda: 0x0964, - dargahebrew: 0x05A7, - dargalefthebrew: 0x05A7, - dasiapneumatacyrilliccmb: 0x0485, - dblGrave: 0xF6D3, - dblanglebracketleft: 0x300A, - dblanglebracketleftvertical: 0xFE3D, - dblanglebracketright: 0x300B, - dblanglebracketrightvertical: 0xFE3E, - dblarchinvertedbelowcmb: 0x032B, - dblarrowleft: 0x21D4, - dblarrowright: 0x21D2, - dbldanda: 0x0965, - dblgrave: 0xF6D6, - dblgravecmb: 0x030F, - dblintegral: 0x222C, - dbllowline: 0x2017, - dbllowlinecmb: 0x0333, - dbloverlinecmb: 0x033F, - dblprimemod: 0x02BA, - dblverticalbar: 0x2016, - dblverticallineabovecmb: 0x030E, - dbopomofo: 0x3109, - dbsquare: 0x33C8, - dcaron: 0x010F, - dcedilla: 0x1E11, - dcircle: 0x24D3, - dcircumflexbelow: 0x1E13, - dcroat: 0x0111, - ddabengali: 0x09A1, - ddadeva: 0x0921, - ddagujarati: 0x0AA1, - ddagurmukhi: 0x0A21, - ddalarabic: 0x0688, - ddalfinalarabic: 0xFB89, - dddhadeva: 0x095C, - ddhabengali: 0x09A2, - ddhadeva: 0x0922, - ddhagujarati: 0x0AA2, - ddhagurmukhi: 0x0A22, - ddotaccent: 0x1E0B, - ddotbelow: 0x1E0D, - decimalseparatorarabic: 0x066B, - decimalseparatorpersian: 0x066B, - decyrillic: 0x0434, - degree: 0x00B0, - dehihebrew: 0x05AD, - dehiragana: 0x3067, - deicoptic: 0x03EF, - dekatakana: 0x30C7, - deleteleft: 0x232B, - deleteright: 0x2326, - delta: 0x03B4, - deltaturned: 0x018D, - denominatorminusonenumeratorbengali: 0x09F8, - dezh: 0x02A4, - dhabengali: 0x09A7, - dhadeva: 0x0927, - dhagujarati: 0x0AA7, - dhagurmukhi: 0x0A27, - dhook: 0x0257, - dialytikatonos: 0x0385, - dialytikatonoscmb: 0x0344, - diamond: 0x2666, - diamondsuitwhite: 0x2662, - dieresis: 0x00A8, - dieresisacute: 0xF6D7, - dieresisbelowcmb: 0x0324, - dieresiscmb: 0x0308, - dieresisgrave: 0xF6D8, - dieresistonos: 0x0385, - dihiragana: 0x3062, - dikatakana: 0x30C2, - dittomark: 0x3003, - divide: 0x00F7, - divides: 0x2223, - divisionslash: 0x2215, - djecyrillic: 0x0452, - dkshade: 0x2593, - dlinebelow: 0x1E0F, - dlsquare: 0x3397, - dmacron: 0x0111, - dmonospace: 0xFF44, - dnblock: 0x2584, - dochadathai: 0x0E0E, - dodekthai: 0x0E14, - dohiragana: 0x3069, - dokatakana: 0x30C9, - dollar: 0x0024, - dollarinferior: 0xF6E3, - dollarmonospace: 0xFF04, - dollaroldstyle: 0xF724, - dollarsmall: 0xFE69, - dollarsuperior: 0xF6E4, - dong: 0x20AB, - dorusquare: 0x3326, - dotaccent: 0x02D9, - dotaccentcmb: 0x0307, - dotbelowcmb: 0x0323, - dotbelowcomb: 0x0323, - dotkatakana: 0x30FB, - dotlessi: 0x0131, - dotlessj: 0xF6BE, - dotlessjstrokehook: 0x0284, - dotmath: 0x22C5, - dottedcircle: 0x25CC, - doubleyodpatah: 0xFB1F, - doubleyodpatahhebrew: 0xFB1F, - downtackbelowcmb: 0x031E, - downtackmod: 0x02D5, - dparen: 0x249F, - dsuperior: 0xF6EB, - dtail: 0x0256, - dtopbar: 0x018C, - duhiragana: 0x3065, - dukatakana: 0x30C5, - dz: 0x01F3, - dzaltone: 0x02A3, - dzcaron: 0x01C6, - dzcurl: 0x02A5, - dzeabkhasiancyrillic: 0x04E1, - dzecyrillic: 0x0455, - dzhecyrillic: 0x045F, - e: 0x0065, - eacute: 0x00E9, - earth: 0x2641, - ebengali: 0x098F, - ebopomofo: 0x311C, - ebreve: 0x0115, - ecandradeva: 0x090D, - ecandragujarati: 0x0A8D, - ecandravowelsigndeva: 0x0945, - ecandravowelsigngujarati: 0x0AC5, - ecaron: 0x011B, - ecedillabreve: 0x1E1D, - echarmenian: 0x0565, - echyiwnarmenian: 0x0587, - ecircle: 0x24D4, - ecircumflex: 0x00EA, - ecircumflexacute: 0x1EBF, - ecircumflexbelow: 0x1E19, - ecircumflexdotbelow: 0x1EC7, - ecircumflexgrave: 0x1EC1, - ecircumflexhookabove: 0x1EC3, - ecircumflextilde: 0x1EC5, - ecyrillic: 0x0454, - edblgrave: 0x0205, - edeva: 0x090F, - edieresis: 0x00EB, - edot: 0x0117, - edotaccent: 0x0117, - edotbelow: 0x1EB9, - eegurmukhi: 0x0A0F, - eematragurmukhi: 0x0A47, - efcyrillic: 0x0444, - egrave: 0x00E8, - egujarati: 0x0A8F, - eharmenian: 0x0567, - ehbopomofo: 0x311D, - ehiragana: 0x3048, - ehookabove: 0x1EBB, - eibopomofo: 0x311F, - eight: 0x0038, - eightarabic: 0x0668, - eightbengali: 0x09EE, - eightcircle: 0x2467, - eightcircleinversesansserif: 0x2791, - eightdeva: 0x096E, - eighteencircle: 0x2471, - eighteenparen: 0x2485, - eighteenperiod: 0x2499, - eightgujarati: 0x0AEE, - eightgurmukhi: 0x0A6E, - eighthackarabic: 0x0668, - eighthangzhou: 0x3028, - eighthnotebeamed: 0x266B, - eightideographicparen: 0x3227, - eightinferior: 0x2088, - eightmonospace: 0xFF18, - eightoldstyle: 0xF738, - eightparen: 0x247B, - eightperiod: 0x248F, - eightpersian: 0x06F8, - eightroman: 0x2177, - eightsuperior: 0x2078, - eightthai: 0x0E58, - einvertedbreve: 0x0207, - eiotifiedcyrillic: 0x0465, - ekatakana: 0x30A8, - ekatakanahalfwidth: 0xFF74, - ekonkargurmukhi: 0x0A74, - ekorean: 0x3154, - elcyrillic: 0x043B, - element: 0x2208, - elevencircle: 0x246A, - elevenparen: 0x247E, - elevenperiod: 0x2492, - elevenroman: 0x217A, - ellipsis: 0x2026, - ellipsisvertical: 0x22EE, - emacron: 0x0113, - emacronacute: 0x1E17, - emacrongrave: 0x1E15, - emcyrillic: 0x043C, - emdash: 0x2014, - emdashvertical: 0xFE31, - emonospace: 0xFF45, - emphasismarkarmenian: 0x055B, - emptyset: 0x2205, - enbopomofo: 0x3123, - encyrillic: 0x043D, - endash: 0x2013, - endashvertical: 0xFE32, - endescendercyrillic: 0x04A3, - eng: 0x014B, - engbopomofo: 0x3125, - enghecyrillic: 0x04A5, - enhookcyrillic: 0x04C8, - enspace: 0x2002, - eogonek: 0x0119, - eokorean: 0x3153, - eopen: 0x025B, - eopenclosed: 0x029A, - eopenreversed: 0x025C, - eopenreversedclosed: 0x025E, - eopenreversedhook: 0x025D, - eparen: 0x24A0, - epsilon: 0x03B5, - epsilontonos: 0x03AD, - equal: 0x003D, - equalmonospace: 0xFF1D, - equalsmall: 0xFE66, - equalsuperior: 0x207C, - equivalence: 0x2261, - erbopomofo: 0x3126, - ercyrillic: 0x0440, - ereversed: 0x0258, - ereversedcyrillic: 0x044D, - escyrillic: 0x0441, - esdescendercyrillic: 0x04AB, - esh: 0x0283, - eshcurl: 0x0286, - eshortdeva: 0x090E, - eshortvowelsigndeva: 0x0946, - eshreversedloop: 0x01AA, - eshsquatreversed: 0x0285, - esmallhiragana: 0x3047, - esmallkatakana: 0x30A7, - esmallkatakanahalfwidth: 0xFF6A, - estimated: 0x212E, - esuperior: 0xF6EC, - eta: 0x03B7, - etarmenian: 0x0568, - etatonos: 0x03AE, - eth: 0x00F0, - etilde: 0x1EBD, - etildebelow: 0x1E1B, - etnahtafoukhhebrew: 0x0591, - etnahtafoukhlefthebrew: 0x0591, - etnahtahebrew: 0x0591, - etnahtalefthebrew: 0x0591, - eturned: 0x01DD, - eukorean: 0x3161, - euro: 0x20AC, - evowelsignbengali: 0x09C7, - evowelsigndeva: 0x0947, - evowelsigngujarati: 0x0AC7, - exclam: 0x0021, - exclamarmenian: 0x055C, - exclamdbl: 0x203C, - exclamdown: 0x00A1, - exclamdownsmall: 0xF7A1, - exclammonospace: 0xFF01, - exclamsmall: 0xF721, - existential: 0x2203, - ezh: 0x0292, - ezhcaron: 0x01EF, - ezhcurl: 0x0293, - ezhreversed: 0x01B9, - ezhtail: 0x01BA, - f: 0x0066, - fadeva: 0x095E, - fagurmukhi: 0x0A5E, - fahrenheit: 0x2109, - fathaarabic: 0x064E, - fathalowarabic: 0x064E, - fathatanarabic: 0x064B, - fbopomofo: 0x3108, - fcircle: 0x24D5, - fdotaccent: 0x1E1F, - feharabic: 0x0641, - feharmenian: 0x0586, - fehfinalarabic: 0xFED2, - fehinitialarabic: 0xFED3, - fehmedialarabic: 0xFED4, - feicoptic: 0x03E5, - female: 0x2640, - ff: 0xFB00, - ffi: 0xFB03, - ffl: 0xFB04, - fi: 0xFB01, - fifteencircle: 0x246E, - fifteenparen: 0x2482, - fifteenperiod: 0x2496, - figuredash: 0x2012, - filledbox: 0x25A0, - filledrect: 0x25AC, - finalkaf: 0x05DA, - finalkafdagesh: 0xFB3A, - finalkafdageshhebrew: 0xFB3A, - finalkafhebrew: 0x05DA, + dalfinalarabic: "FEAA", + dammaarabic: "064F", + dammalowarabic: "064F", + dammatanaltonearabic: "064C", + dammatanarabic: "064C", + danda: "0964", + dargahebrew: "05A7", + dargalefthebrew: "05A7", + dasiapneumatacyrilliccmb: "0485", + dblGrave: "F6D3", + dblanglebracketleft: "300A", + dblanglebracketleftvertical: "FE3D", + dblanglebracketright: "300B", + dblanglebracketrightvertical: "FE3E", + dblarchinvertedbelowcmb: "032B", + dblarrowleft: "21D4", + dblarrowright: "21D2", + dbldanda: "0965", + dblgrave: "F6D6", + dblgravecmb: "030F", + dblintegral: "222C", + dbllowline: "2017", + dbllowlinecmb: "0333", + dbloverlinecmb: "033F", + dblprimemod: "02BA", + dblverticalbar: "2016", + dblverticallineabovecmb: "030E", + dbopomofo: "3109", + dbsquare: "33C8", + dcaron: "010F", + dcedilla: "1E11", + dcircle: "24D3", + dcircumflexbelow: "1E13", + dcroat: "0111", + ddabengali: "09A1", + ddadeva: "0921", + ddagujarati: "0AA1", + ddagurmukhi: "0A21", + ddalarabic: "0688", + ddalfinalarabic: "FB89", + dddhadeva: "095C", + ddhabengali: "09A2", + ddhadeva: "0922", + ddhagujarati: "0AA2", + ddhagurmukhi: "0A22", + ddotaccent: "1E0B", + ddotbelow: "1E0D", + decimalseparatorarabic: "066B", + decimalseparatorpersian: "066B", + decyrillic: "0434", + degree: "00B0", + dehihebrew: "05AD", + dehiragana: "3067", + deicoptic: "03EF", + dekatakana: "30C7", + deleteleft: "232B", + deleteright: "2326", + delta: "03B4", + deltaturned: "018D", + denominatorminusonenumeratorbengali: "09F8", + dezh: "02A4", + dhabengali: "09A7", + dhadeva: "0927", + dhagujarati: "0AA7", + dhagurmukhi: "0A27", + dhook: "0257", + dialytikatonos: "0385", + dialytikatonoscmb: "0344", + diamond: "2666", + diamondsuitwhite: "2662", + dieresis: "00A8", + dieresisacute: "F6D7", + dieresisbelowcmb: "0324", + dieresiscmb: "0308", + dieresisgrave: "F6D8", + dieresistonos: "0385", + dihiragana: "3062", + dikatakana: "30C2", + dittomark: "3003", + divide: "00F7", + divides: "2223", + divisionslash: "2215", + djecyrillic: "0452", + dkshade: "2593", + dlinebelow: "1E0F", + dlsquare: "3397", + dmacron: "0111", + dmonospace: "FF44", + dnblock: "2584", + dochadathai: "0E0E", + dodekthai: "0E14", + dohiragana: "3069", + dokatakana: "30C9", + dollar: "0024", + dollarinferior: "F6E3", + dollarmonospace: "FF04", + dollaroldstyle: "F724", + dollarsmall: "FE69", + dollarsuperior: "F6E4", + dong: "20AB", + dorusquare: "3326", + dotaccent: "02D9", + dotaccentcmb: "0307", + dotbelowcmb: "0323", + dotbelowcomb: "0323", + dotkatakana: "30FB", + dotlessi: "0131", + dotlessj: "F6BE", + dotlessjstrokehook: "0284", + dotmath: "22C5", + dottedcircle: "25CC", + doubleyodpatah: "FB1F", + doubleyodpatahhebrew: "FB1F", + downtackbelowcmb: "031E", + downtackmod: "02D5", + dparen: "249F", + dsuperior: "F6EB", + dtail: "0256", + dtopbar: "018C", + duhiragana: "3065", + dukatakana: "30C5", + dz: "01F3", + dzaltone: "02A3", + dzcaron: "01C6", + dzcurl: "02A5", + dzeabkhasiancyrillic: "04E1", + dzecyrillic: "0455", + dzhecyrillic: "045F", + e: "0065", + eacute: "00E9", + earth: "2641", + ebengali: "098F", + ebopomofo: "311C", + ebreve: "0115", + ecandradeva: "090D", + ecandragujarati: "0A8D", + ecandravowelsigndeva: "0945", + ecandravowelsigngujarati: "0AC5", + ecaron: "011B", + ecedillabreve: "1E1D", + echarmenian: "0565", + echyiwnarmenian: "0587", + ecircle: "24D4", + ecircumflex: "00EA", + ecircumflexacute: "1EBF", + ecircumflexbelow: "1E19", + ecircumflexdotbelow: "1EC7", + ecircumflexgrave: "1EC1", + ecircumflexhookabove: "1EC3", + ecircumflextilde: "1EC5", + ecyrillic: "0454", + edblgrave: "0205", + edeva: "090F", + edieresis: "00EB", + edot: "0117", + edotaccent: "0117", + edotbelow: "1EB9", + eegurmukhi: "0A0F", + eematragurmukhi: "0A47", + efcyrillic: "0444", + egrave: "00E8", + egujarati: "0A8F", + eharmenian: "0567", + ehbopomofo: "311D", + ehiragana: "3048", + ehookabove: "1EBB", + eibopomofo: "311F", + eight: "0038", + eightarabic: "0668", + eightbengali: "09EE", + eightcircle: "2467", + eightcircleinversesansserif: "2791", + eightdeva: "096E", + eighteencircle: "2471", + eighteenparen: "2485", + eighteenperiod: "2499", + eightgujarati: "0AEE", + eightgurmukhi: "0A6E", + eighthackarabic: "0668", + eighthangzhou: "3028", + eighthnotebeamed: "266B", + eightideographicparen: "3227", + eightinferior: "2088", + eightmonospace: "FF18", + eightoldstyle: "F738", + eightparen: "247B", + eightperiod: "248F", + eightpersian: "06F8", + eightroman: "2177", + eightsuperior: "2078", + eightthai: "0E58", + einvertedbreve: "0207", + eiotifiedcyrillic: "0465", + ekatakana: "30A8", + ekatakanahalfwidth: "FF74", + ekonkargurmukhi: "0A74", + ekorean: "3154", + elcyrillic: "043B", + element: "2208", + elevencircle: "246A", + elevenparen: "247E", + elevenperiod: "2492", + elevenroman: "217A", + ellipsis: "2026", + ellipsisvertical: "22EE", + emacron: "0113", + emacronacute: "1E17", + emacrongrave: "1E15", + emcyrillic: "043C", + emdash: "2014", + emdashvertical: "FE31", + emonospace: "FF45", + emphasismarkarmenian: "055B", + emptyset: "2205", + enbopomofo: "3123", + encyrillic: "043D", + endash: "2013", + endashvertical: "FE32", + endescendercyrillic: "04A3", + eng: "014B", + engbopomofo: "3125", + enghecyrillic: "04A5", + enhookcyrillic: "04C8", + enspace: "2002", + eogonek: "0119", + eokorean: "3153", + eopen: "025B", + eopenclosed: "029A", + eopenreversed: "025C", + eopenreversedclosed: "025E", + eopenreversedhook: "025D", + eparen: "24A0", + epsilon: "03B5", + epsilontonos: "03AD", + equal: "003D", + equalmonospace: "FF1D", + equalsmall: "FE66", + equalsuperior: "207C", + equivalence: "2261", + erbopomofo: "3126", + ercyrillic: "0440", + ereversed: "0258", + ereversedcyrillic: "044D", + escyrillic: "0441", + esdescendercyrillic: "04AB", + esh: "0283", + eshcurl: "0286", + eshortdeva: "090E", + eshortvowelsigndeva: "0946", + eshreversedloop: "01AA", + eshsquatreversed: "0285", + esmallhiragana: "3047", + esmallkatakana: "30A7", + esmallkatakanahalfwidth: "FF6A", + estimated: "212E", + esuperior: "F6EC", + eta: "03B7", + etarmenian: "0568", + etatonos: "03AE", + eth: "00F0", + etilde: "1EBD", + etildebelow: "1E1B", + etnahtafoukhhebrew: "0591", + etnahtafoukhlefthebrew: "0591", + etnahtahebrew: "0591", + etnahtalefthebrew: "0591", + eturned: "01DD", + eukorean: "3161", + euro: "20AC", + evowelsignbengali: "09C7", + evowelsigndeva: "0947", + evowelsigngujarati: "0AC7", + exclam: "0021", + exclamarmenian: "055C", + exclamdbl: "203C", + exclamdown: "00A1", + exclamdownsmall: "F7A1", + exclammonospace: "FF01", + exclamsmall: "F721", + existential: "2203", + ezh: "0292", + ezhcaron: "01EF", + ezhcurl: "0293", + ezhreversed: "01B9", + ezhtail: "01BA", + f: "0066", + fadeva: "095E", + fagurmukhi: "0A5E", + fahrenheit: "2109", + fathaarabic: "064E", + fathalowarabic: "064E", + fathatanarabic: "064B", + fbopomofo: "3108", + fcircle: "24D5", + fdotaccent: "1E1F", + feharabic: "0641", + feharmenian: "0586", + fehfinalarabic: "FED2", + fehinitialarabic: "FED3", + fehmedialarabic: "FED4", + feicoptic: "03E5", + female: "2640", + ff: "FB00", + ffi: "FB03", + ffl: "FB04", + fi: "FB01", + fifteencircle: "246E", + fifteenparen: "2482", + fifteenperiod: "2496", + figuredash: "2012", + filledbox: "25A0", + filledrect: "25AC", + finalkaf: "05DA", + finalkafdagesh: "FB3A", + finalkafdageshhebrew: "FB3A", + finalkafhebrew: "05DA", finalkafqamats: "05DA 05B8", finalkafqamatshebrew: "05DA 05B8", finalkafsheva: "05DA 05B0", finalkafshevahebrew: "05DA 05B0", - finalmem: 0x05DD, - finalmemhebrew: 0x05DD, - finalnun: 0x05DF, - finalnunhebrew: 0x05DF, - finalpe: 0x05E3, - finalpehebrew: 0x05E3, - finaltsadi: 0x05E5, - finaltsadihebrew: 0x05E5, - firsttonechinese: 0x02C9, - fisheye: 0x25C9, - fitacyrillic: 0x0473, - five: 0x0035, - fivearabic: 0x0665, - fivebengali: 0x09EB, - fivecircle: 0x2464, - fivecircleinversesansserif: 0x278E, - fivedeva: 0x096B, - fiveeighths: 0x215D, - fivegujarati: 0x0AEB, - fivegurmukhi: 0x0A6B, - fivehackarabic: 0x0665, - fivehangzhou: 0x3025, - fiveideographicparen: 0x3224, - fiveinferior: 0x2085, - fivemonospace: 0xFF15, - fiveoldstyle: 0xF735, - fiveparen: 0x2478, - fiveperiod: 0x248C, - fivepersian: 0x06F5, - fiveroman: 0x2174, - fivesuperior: 0x2075, - fivethai: 0x0E55, - fl: 0xFB02, - florin: 0x0192, - fmonospace: 0xFF46, - fmsquare: 0x3399, - fofanthai: 0x0E1F, - fofathai: 0x0E1D, - fongmanthai: 0x0E4F, - forall: 0x2200, - four: 0x0034, - fourarabic: 0x0664, - fourbengali: 0x09EA, - fourcircle: 0x2463, - fourcircleinversesansserif: 0x278D, - fourdeva: 0x096A, - fourgujarati: 0x0AEA, - fourgurmukhi: 0x0A6A, - fourhackarabic: 0x0664, - fourhangzhou: 0x3024, - fourideographicparen: 0x3223, - fourinferior: 0x2084, - fourmonospace: 0xFF14, - fournumeratorbengali: 0x09F7, - fouroldstyle: 0xF734, - fourparen: 0x2477, - fourperiod: 0x248B, - fourpersian: 0x06F4, - fourroman: 0x2173, - foursuperior: 0x2074, - fourteencircle: 0x246D, - fourteenparen: 0x2481, - fourteenperiod: 0x2495, - fourthai: 0x0E54, - fourthtonechinese: 0x02CB, - fparen: 0x24A1, - fraction: 0x2044, - franc: 0x20A3, - g: 0x0067, - gabengali: 0x0997, - gacute: 0x01F5, - gadeva: 0x0917, - gafarabic: 0x06AF, - gaffinalarabic: 0xFB93, - gafinitialarabic: 0xFB94, - gafmedialarabic: 0xFB95, - gagujarati: 0x0A97, - gagurmukhi: 0x0A17, - gahiragana: 0x304C, - gakatakana: 0x30AC, - gamma: 0x03B3, - gammalatinsmall: 0x0263, - gammasuperior: 0x02E0, - gangiacoptic: 0x03EB, - gbopomofo: 0x310D, - gbreve: 0x011F, - gcaron: 0x01E7, - gcedilla: 0x0123, - gcircle: 0x24D6, - gcircumflex: 0x011D, - gcommaaccent: 0x0123, - gdot: 0x0121, - gdotaccent: 0x0121, - gecyrillic: 0x0433, - gehiragana: 0x3052, - gekatakana: 0x30B2, - geometricallyequal: 0x2251, - gereshaccenthebrew: 0x059C, - gereshhebrew: 0x05F3, - gereshmuqdamhebrew: 0x059D, - germandbls: 0x00DF, - gershayimaccenthebrew: 0x059E, - gershayimhebrew: 0x05F4, - getamark: 0x3013, - ghabengali: 0x0998, - ghadarmenian: 0x0572, - ghadeva: 0x0918, - ghagujarati: 0x0A98, - ghagurmukhi: 0x0A18, - ghainarabic: 0x063A, - ghainfinalarabic: 0xFECE, - ghaininitialarabic: 0xFECF, - ghainmedialarabic: 0xFED0, - ghemiddlehookcyrillic: 0x0495, - ghestrokecyrillic: 0x0493, - gheupturncyrillic: 0x0491, - ghhadeva: 0x095A, - ghhagurmukhi: 0x0A5A, - ghook: 0x0260, - ghzsquare: 0x3393, - gihiragana: 0x304E, - gikatakana: 0x30AE, - gimarmenian: 0x0563, - gimel: 0x05D2, - gimeldagesh: 0xFB32, - gimeldageshhebrew: 0xFB32, - gimelhebrew: 0x05D2, - gjecyrillic: 0x0453, - glottalinvertedstroke: 0x01BE, - glottalstop: 0x0294, - glottalstopinverted: 0x0296, - glottalstopmod: 0x02C0, - glottalstopreversed: 0x0295, - glottalstopreversedmod: 0x02C1, - glottalstopreversedsuperior: 0x02E4, - glottalstopstroke: 0x02A1, - glottalstopstrokereversed: 0x02A2, - gmacron: 0x1E21, - gmonospace: 0xFF47, - gohiragana: 0x3054, - gokatakana: 0x30B4, - gparen: 0x24A2, - gpasquare: 0x33AC, - gradient: 0x2207, - grave: 0x0060, - gravebelowcmb: 0x0316, - gravecmb: 0x0300, - gravecomb: 0x0300, - gravedeva: 0x0953, - gravelowmod: 0x02CE, - gravemonospace: 0xFF40, - gravetonecmb: 0x0340, - greater: 0x003E, - greaterequal: 0x2265, - greaterequalorless: 0x22DB, - greatermonospace: 0xFF1E, - greaterorequivalent: 0x2273, - greaterorless: 0x2277, - greateroverequal: 0x2267, - greatersmall: 0xFE65, - gscript: 0x0261, - gstroke: 0x01E5, - guhiragana: 0x3050, - guillemotleft: 0x00AB, - guillemotright: 0x00BB, - guilsinglleft: 0x2039, - guilsinglright: 0x203A, - gukatakana: 0x30B0, - guramusquare: 0x3318, - gysquare: 0x33C9, - h: 0x0068, - haabkhasiancyrillic: 0x04A9, - haaltonearabic: 0x06C1, - habengali: 0x09B9, - hadescendercyrillic: 0x04B3, - hadeva: 0x0939, - hagujarati: 0x0AB9, - hagurmukhi: 0x0A39, - haharabic: 0x062D, - hahfinalarabic: 0xFEA2, - hahinitialarabic: 0xFEA3, - hahiragana: 0x306F, - hahmedialarabic: 0xFEA4, - haitusquare: 0x332A, - hakatakana: 0x30CF, - hakatakanahalfwidth: 0xFF8A, - halantgurmukhi: 0x0A4D, - hamzaarabic: 0x0621, + finalmem: "05DD", + finalmemhebrew: "05DD", + finalnun: "05DF", + finalnunhebrew: "05DF", + finalpe: "05E3", + finalpehebrew: "05E3", + finaltsadi: "05E5", + finaltsadihebrew: "05E5", + firsttonechinese: "02C9", + fisheye: "25C9", + fitacyrillic: "0473", + five: "0035", + fivearabic: "0665", + fivebengali: "09EB", + fivecircle: "2464", + fivecircleinversesansserif: "278E", + fivedeva: "096B", + fiveeighths: "215D", + fivegujarati: "0AEB", + fivegurmukhi: "0A6B", + fivehackarabic: "0665", + fivehangzhou: "3025", + fiveideographicparen: "3224", + fiveinferior: "2085", + fivemonospace: "FF15", + fiveoldstyle: "F735", + fiveparen: "2478", + fiveperiod: "248C", + fivepersian: "06F5", + fiveroman: "2174", + fivesuperior: "2075", + fivethai: "0E55", + fl: "FB02", + florin: "0192", + fmonospace: "FF46", + fmsquare: "3399", + fofanthai: "0E1F", + fofathai: "0E1D", + fongmanthai: "0E4F", + forall: "2200", + four: "0034", + fourarabic: "0664", + fourbengali: "09EA", + fourcircle: "2463", + fourcircleinversesansserif: "278D", + fourdeva: "096A", + fourgujarati: "0AEA", + fourgurmukhi: "0A6A", + fourhackarabic: "0664", + fourhangzhou: "3024", + fourideographicparen: "3223", + fourinferior: "2084", + fourmonospace: "FF14", + fournumeratorbengali: "09F7", + fouroldstyle: "F734", + fourparen: "2477", + fourperiod: "248B", + fourpersian: "06F4", + fourroman: "2173", + foursuperior: "2074", + fourteencircle: "246D", + fourteenparen: "2481", + fourteenperiod: "2495", + fourthai: "0E54", + fourthtonechinese: "02CB", + fparen: "24A1", + fraction: "2044", + franc: "20A3", + g: "0067", + gabengali: "0997", + gacute: "01F5", + gadeva: "0917", + gafarabic: "06AF", + gaffinalarabic: "FB93", + gafinitialarabic: "FB94", + gafmedialarabic: "FB95", + gagujarati: "0A97", + gagurmukhi: "0A17", + gahiragana: "304C", + gakatakana: "30AC", + gamma: "03B3", + gammalatinsmall: "0263", + gammasuperior: "02E0", + gangiacoptic: "03EB", + gbopomofo: "310D", + gbreve: "011F", + gcaron: "01E7", + gcedilla: "0123", + gcircle: "24D6", + gcircumflex: "011D", + gcommaaccent: "0123", + gdot: "0121", + gdotaccent: "0121", + gecyrillic: "0433", + gehiragana: "3052", + gekatakana: "30B2", + geometricallyequal: "2251", + gereshaccenthebrew: "059C", + gereshhebrew: "05F3", + gereshmuqdamhebrew: "059D", + germandbls: "00DF", + gershayimaccenthebrew: "059E", + gershayimhebrew: "05F4", + getamark: "3013", + ghabengali: "0998", + ghadarmenian: "0572", + ghadeva: "0918", + ghagujarati: "0A98", + ghagurmukhi: "0A18", + ghainarabic: "063A", + ghainfinalarabic: "FECE", + ghaininitialarabic: "FECF", + ghainmedialarabic: "FED0", + ghemiddlehookcyrillic: "0495", + ghestrokecyrillic: "0493", + gheupturncyrillic: "0491", + ghhadeva: "095A", + ghhagurmukhi: "0A5A", + ghook: "0260", + ghzsquare: "3393", + gihiragana: "304E", + gikatakana: "30AE", + gimarmenian: "0563", + gimel: "05D2", + gimeldagesh: "FB32", + gimeldageshhebrew: "FB32", + gimelhebrew: "05D2", + gjecyrillic: "0453", + glottalinvertedstroke: "01BE", + glottalstop: "0294", + glottalstopinverted: "0296", + glottalstopmod: "02C0", + glottalstopreversed: "0295", + glottalstopreversedmod: "02C1", + glottalstopreversedsuperior: "02E4", + glottalstopstroke: "02A1", + glottalstopstrokereversed: "02A2", + gmacron: "1E21", + gmonospace: "FF47", + gohiragana: "3054", + gokatakana: "30B4", + gparen: "24A2", + gpasquare: "33AC", + gradient: "2207", + grave: "0060", + gravebelowcmb: "0316", + gravecmb: "0300", + gravecomb: "0300", + gravedeva: "0953", + gravelowmod: "02CE", + gravemonospace: "FF40", + gravetonecmb: "0340", + greater: "003E", + greaterequal: "2265", + greaterequalorless: "22DB", + greatermonospace: "FF1E", + greaterorequivalent: "2273", + greaterorless: "2277", + greateroverequal: "2267", + greatersmall: "FE65", + gscript: "0261", + gstroke: "01E5", + guhiragana: "3050", + guillemotleft: "00AB", + guillemotright: "00BB", + guilsinglleft: "2039", + guilsinglright: "203A", + gukatakana: "30B0", + guramusquare: "3318", + gysquare: "33C9", + h: "0068", + haabkhasiancyrillic: "04A9", + haaltonearabic: "06C1", + habengali: "09B9", + hadescendercyrillic: "04B3", + hadeva: "0939", + hagujarati: "0AB9", + hagurmukhi: "0A39", + haharabic: "062D", + hahfinalarabic: "FEA2", + hahinitialarabic: "FEA3", + hahiragana: "306F", + hahmedialarabic: "FEA4", + haitusquare: "332A", + hakatakana: "30CF", + hakatakanahalfwidth: "FF8A", + halantgurmukhi: "0A4D", + hamzaarabic: "0621", hamzadammaarabic: "0621 064F", hamzadammatanarabic: "0621 064C", hamzafathaarabic: "0621 064E", hamzafathatanarabic: "0621 064B", - hamzalowarabic: 0x0621, + hamzalowarabic: "0621", hamzalowkasraarabic: "0621 0650", hamzalowkasratanarabic: "0621 064D", hamzasukunarabic: "0621 0652", - hangulfiller: 0x3164, - hardsigncyrillic: 0x044A, - harpoonleftbarbup: 0x21BC, - harpoonrightbarbup: 0x21C0, - hasquare: 0x33CA, - hatafpatah: 0x05B2, - hatafpatah16: 0x05B2, - hatafpatah23: 0x05B2, - hatafpatah2f: 0x05B2, - hatafpatahhebrew: 0x05B2, - hatafpatahnarrowhebrew: 0x05B2, - hatafpatahquarterhebrew: 0x05B2, - hatafpatahwidehebrew: 0x05B2, - hatafqamats: 0x05B3, - hatafqamats1b: 0x05B3, - hatafqamats28: 0x05B3, - hatafqamats34: 0x05B3, - hatafqamatshebrew: 0x05B3, - hatafqamatsnarrowhebrew: 0x05B3, - hatafqamatsquarterhebrew: 0x05B3, - hatafqamatswidehebrew: 0x05B3, - hatafsegol: 0x05B1, - hatafsegol17: 0x05B1, - hatafsegol24: 0x05B1, - hatafsegol30: 0x05B1, - hatafsegolhebrew: 0x05B1, - hatafsegolnarrowhebrew: 0x05B1, - hatafsegolquarterhebrew: 0x05B1, - hatafsegolwidehebrew: 0x05B1, - hbar: 0x0127, - hbopomofo: 0x310F, - hbrevebelow: 0x1E2B, - hcedilla: 0x1E29, - hcircle: 0x24D7, - hcircumflex: 0x0125, - hdieresis: 0x1E27, - hdotaccent: 0x1E23, - hdotbelow: 0x1E25, - he: 0x05D4, - heart: 0x2665, - heartsuitblack: 0x2665, - heartsuitwhite: 0x2661, - hedagesh: 0xFB34, - hedageshhebrew: 0xFB34, - hehaltonearabic: 0x06C1, - heharabic: 0x0647, - hehebrew: 0x05D4, - hehfinalaltonearabic: 0xFBA7, - hehfinalalttwoarabic: 0xFEEA, - hehfinalarabic: 0xFEEA, - hehhamzaabovefinalarabic: 0xFBA5, - hehhamzaaboveisolatedarabic: 0xFBA4, - hehinitialaltonearabic: 0xFBA8, - hehinitialarabic: 0xFEEB, - hehiragana: 0x3078, - hehmedialaltonearabic: 0xFBA9, - hehmedialarabic: 0xFEEC, - heiseierasquare: 0x337B, - hekatakana: 0x30D8, - hekatakanahalfwidth: 0xFF8D, - hekutaarusquare: 0x3336, - henghook: 0x0267, - herutusquare: 0x3339, - het: 0x05D7, - hethebrew: 0x05D7, - hhook: 0x0266, - hhooksuperior: 0x02B1, - hieuhacirclekorean: 0x327B, - hieuhaparenkorean: 0x321B, - hieuhcirclekorean: 0x326D, - hieuhkorean: 0x314E, - hieuhparenkorean: 0x320D, - hihiragana: 0x3072, - hikatakana: 0x30D2, - hikatakanahalfwidth: 0xFF8B, - hiriq: 0x05B4, - hiriq14: 0x05B4, - hiriq21: 0x05B4, - hiriq2d: 0x05B4, - hiriqhebrew: 0x05B4, - hiriqnarrowhebrew: 0x05B4, - hiriqquarterhebrew: 0x05B4, - hiriqwidehebrew: 0x05B4, - hlinebelow: 0x1E96, - hmonospace: 0xFF48, - hoarmenian: 0x0570, - hohipthai: 0x0E2B, - hohiragana: 0x307B, - hokatakana: 0x30DB, - hokatakanahalfwidth: 0xFF8E, - holam: 0x05B9, - holam19: 0x05B9, - holam26: 0x05B9, - holam32: 0x05B9, - holamhebrew: 0x05B9, - holamnarrowhebrew: 0x05B9, - holamquarterhebrew: 0x05B9, - holamwidehebrew: 0x05B9, - honokhukthai: 0x0E2E, - hookabovecomb: 0x0309, - hookcmb: 0x0309, - hookpalatalizedbelowcmb: 0x0321, - hookretroflexbelowcmb: 0x0322, - hoonsquare: 0x3342, - horicoptic: 0x03E9, - horizontalbar: 0x2015, - horncmb: 0x031B, - hotsprings: 0x2668, - house: 0x2302, - hparen: 0x24A3, - hsuperior: 0x02B0, - hturned: 0x0265, - huhiragana: 0x3075, - huiitosquare: 0x3333, - hukatakana: 0x30D5, - hukatakanahalfwidth: 0xFF8C, - hungarumlaut: 0x02DD, - hungarumlautcmb: 0x030B, - hv: 0x0195, - hyphen: 0x002D, - hypheninferior: 0xF6E5, - hyphenmonospace: 0xFF0D, - hyphensmall: 0xFE63, - hyphensuperior: 0xF6E6, - hyphentwo: 0x2010, - i: 0x0069, - iacute: 0x00ED, - iacyrillic: 0x044F, - ibengali: 0x0987, - ibopomofo: 0x3127, - ibreve: 0x012D, - icaron: 0x01D0, - icircle: 0x24D8, - icircumflex: 0x00EE, - icyrillic: 0x0456, - idblgrave: 0x0209, - ideographearthcircle: 0x328F, - ideographfirecircle: 0x328B, - ideographicallianceparen: 0x323F, - ideographiccallparen: 0x323A, - ideographiccentrecircle: 0x32A5, - ideographicclose: 0x3006, - ideographiccomma: 0x3001, - ideographiccommaleft: 0xFF64, - ideographiccongratulationparen: 0x3237, - ideographiccorrectcircle: 0x32A3, - ideographicearthparen: 0x322F, - ideographicenterpriseparen: 0x323D, - ideographicexcellentcircle: 0x329D, - ideographicfestivalparen: 0x3240, - ideographicfinancialcircle: 0x3296, - ideographicfinancialparen: 0x3236, - ideographicfireparen: 0x322B, - ideographichaveparen: 0x3232, - ideographichighcircle: 0x32A4, - ideographiciterationmark: 0x3005, - ideographiclaborcircle: 0x3298, - ideographiclaborparen: 0x3238, - ideographicleftcircle: 0x32A7, - ideographiclowcircle: 0x32A6, - ideographicmedicinecircle: 0x32A9, - ideographicmetalparen: 0x322E, - ideographicmoonparen: 0x322A, - ideographicnameparen: 0x3234, - ideographicperiod: 0x3002, - ideographicprintcircle: 0x329E, - ideographicreachparen: 0x3243, - ideographicrepresentparen: 0x3239, - ideographicresourceparen: 0x323E, - ideographicrightcircle: 0x32A8, - ideographicsecretcircle: 0x3299, - ideographicselfparen: 0x3242, - ideographicsocietyparen: 0x3233, - ideographicspace: 0x3000, - ideographicspecialparen: 0x3235, - ideographicstockparen: 0x3231, - ideographicstudyparen: 0x323B, - ideographicsunparen: 0x3230, - ideographicsuperviseparen: 0x323C, - ideographicwaterparen: 0x322C, - ideographicwoodparen: 0x322D, - ideographiczero: 0x3007, - ideographmetalcircle: 0x328E, - ideographmooncircle: 0x328A, - ideographnamecircle: 0x3294, - ideographsuncircle: 0x3290, - ideographwatercircle: 0x328C, - ideographwoodcircle: 0x328D, - ideva: 0x0907, - idieresis: 0x00EF, - idieresisacute: 0x1E2F, - idieresiscyrillic: 0x04E5, - idotbelow: 0x1ECB, - iebrevecyrillic: 0x04D7, - iecyrillic: 0x0435, - ieungacirclekorean: 0x3275, - ieungaparenkorean: 0x3215, - ieungcirclekorean: 0x3267, - ieungkorean: 0x3147, - ieungparenkorean: 0x3207, - igrave: 0x00EC, - igujarati: 0x0A87, - igurmukhi: 0x0A07, - ihiragana: 0x3044, - ihookabove: 0x1EC9, - iibengali: 0x0988, - iicyrillic: 0x0438, - iideva: 0x0908, - iigujarati: 0x0A88, - iigurmukhi: 0x0A08, - iimatragurmukhi: 0x0A40, - iinvertedbreve: 0x020B, - iishortcyrillic: 0x0439, - iivowelsignbengali: 0x09C0, - iivowelsigndeva: 0x0940, - iivowelsigngujarati: 0x0AC0, - ij: 0x0133, - ikatakana: 0x30A4, - ikatakanahalfwidth: 0xFF72, - ikorean: 0x3163, - ilde: 0x02DC, - iluyhebrew: 0x05AC, - imacron: 0x012B, - imacroncyrillic: 0x04E3, - imageorapproximatelyequal: 0x2253, - imatragurmukhi: 0x0A3F, - imonospace: 0xFF49, - increment: 0x2206, - infinity: 0x221E, - iniarmenian: 0x056B, - integral: 0x222B, - integralbottom: 0x2321, - integralbt: 0x2321, - integralex: 0xF8F5, - integraltop: 0x2320, - integraltp: 0x2320, - intersection: 0x2229, - intisquare: 0x3305, - invbullet: 0x25D8, - invcircle: 0x25D9, - invsmileface: 0x263B, - iocyrillic: 0x0451, - iogonek: 0x012F, - iota: 0x03B9, - iotadieresis: 0x03CA, - iotadieresistonos: 0x0390, - iotalatin: 0x0269, - iotatonos: 0x03AF, - iparen: 0x24A4, - irigurmukhi: 0x0A72, - ismallhiragana: 0x3043, - ismallkatakana: 0x30A3, - ismallkatakanahalfwidth: 0xFF68, - issharbengali: 0x09FA, - istroke: 0x0268, - isuperior: 0xF6ED, - iterationhiragana: 0x309D, - iterationkatakana: 0x30FD, - itilde: 0x0129, - itildebelow: 0x1E2D, - iubopomofo: 0x3129, - iucyrillic: 0x044E, - ivowelsignbengali: 0x09BF, - ivowelsigndeva: 0x093F, - ivowelsigngujarati: 0x0ABF, - izhitsacyrillic: 0x0475, - izhitsadblgravecyrillic: 0x0477, - j: 0x006A, - jaarmenian: 0x0571, - jabengali: 0x099C, - jadeva: 0x091C, - jagujarati: 0x0A9C, - jagurmukhi: 0x0A1C, - jbopomofo: 0x3110, - jcaron: 0x01F0, - jcircle: 0x24D9, - jcircumflex: 0x0135, - jcrossedtail: 0x029D, - jdotlessstroke: 0x025F, - jecyrillic: 0x0458, - jeemarabic: 0x062C, - jeemfinalarabic: 0xFE9E, - jeeminitialarabic: 0xFE9F, - jeemmedialarabic: 0xFEA0, - jeharabic: 0x0698, - jehfinalarabic: 0xFB8B, - jhabengali: 0x099D, - jhadeva: 0x091D, - jhagujarati: 0x0A9D, - jhagurmukhi: 0x0A1D, - jheharmenian: 0x057B, - jis: 0x3004, - jmonospace: 0xFF4A, - jparen: 0x24A5, - jsuperior: 0x02B2, - k: 0x006B, - kabashkircyrillic: 0x04A1, - kabengali: 0x0995, - kacute: 0x1E31, - kacyrillic: 0x043A, - kadescendercyrillic: 0x049B, - kadeva: 0x0915, - kaf: 0x05DB, - kafarabic: 0x0643, - kafdagesh: 0xFB3B, - kafdageshhebrew: 0xFB3B, - kaffinalarabic: 0xFEDA, - kafhebrew: 0x05DB, - kafinitialarabic: 0xFEDB, - kafmedialarabic: 0xFEDC, - kafrafehebrew: 0xFB4D, - kagujarati: 0x0A95, - kagurmukhi: 0x0A15, - kahiragana: 0x304B, - kahookcyrillic: 0x04C4, - kakatakana: 0x30AB, - kakatakanahalfwidth: 0xFF76, - kappa: 0x03BA, - kappasymbolgreek: 0x03F0, - kapyeounmieumkorean: 0x3171, - kapyeounphieuphkorean: 0x3184, - kapyeounpieupkorean: 0x3178, - kapyeounssangpieupkorean: 0x3179, - karoriisquare: 0x330D, - kashidaautoarabic: 0x0640, - kashidaautonosidebearingarabic: 0x0640, - kasmallkatakana: 0x30F5, - kasquare: 0x3384, - kasraarabic: 0x0650, - kasratanarabic: 0x064D, - kastrokecyrillic: 0x049F, - katahiraprolongmarkhalfwidth: 0xFF70, - kaverticalstrokecyrillic: 0x049D, - kbopomofo: 0x310E, - kcalsquare: 0x3389, - kcaron: 0x01E9, - kcedilla: 0x0137, - kcircle: 0x24DA, - kcommaaccent: 0x0137, - kdotbelow: 0x1E33, - keharmenian: 0x0584, - kehiragana: 0x3051, - kekatakana: 0x30B1, - kekatakanahalfwidth: 0xFF79, - kenarmenian: 0x056F, - kesmallkatakana: 0x30F6, - kgreenlandic: 0x0138, - khabengali: 0x0996, - khacyrillic: 0x0445, - khadeva: 0x0916, - khagujarati: 0x0A96, - khagurmukhi: 0x0A16, - khaharabic: 0x062E, - khahfinalarabic: 0xFEA6, - khahinitialarabic: 0xFEA7, - khahmedialarabic: 0xFEA8, - kheicoptic: 0x03E7, - khhadeva: 0x0959, - khhagurmukhi: 0x0A59, - khieukhacirclekorean: 0x3278, - khieukhaparenkorean: 0x3218, - khieukhcirclekorean: 0x326A, - khieukhkorean: 0x314B, - khieukhparenkorean: 0x320A, - khokhaithai: 0x0E02, - khokhonthai: 0x0E05, - khokhuatthai: 0x0E03, - khokhwaithai: 0x0E04, - khomutthai: 0x0E5B, - khook: 0x0199, - khorakhangthai: 0x0E06, - khzsquare: 0x3391, - kihiragana: 0x304D, - kikatakana: 0x30AD, - kikatakanahalfwidth: 0xFF77, - kiroguramusquare: 0x3315, - kiromeetorusquare: 0x3316, - kirosquare: 0x3314, - kiyeokacirclekorean: 0x326E, - kiyeokaparenkorean: 0x320E, - kiyeokcirclekorean: 0x3260, - kiyeokkorean: 0x3131, - kiyeokparenkorean: 0x3200, - kiyeoksioskorean: 0x3133, - kjecyrillic: 0x045C, - klinebelow: 0x1E35, - klsquare: 0x3398, - kmcubedsquare: 0x33A6, - kmonospace: 0xFF4B, - kmsquaredsquare: 0x33A2, - kohiragana: 0x3053, - kohmsquare: 0x33C0, - kokaithai: 0x0E01, - kokatakana: 0x30B3, - kokatakanahalfwidth: 0xFF7A, - kooposquare: 0x331E, - koppacyrillic: 0x0481, - koreanstandardsymbol: 0x327F, - koroniscmb: 0x0343, - kparen: 0x24A6, - kpasquare: 0x33AA, - ksicyrillic: 0x046F, - ktsquare: 0x33CF, - kturned: 0x029E, - kuhiragana: 0x304F, - kukatakana: 0x30AF, - kukatakanahalfwidth: 0xFF78, - kvsquare: 0x33B8, - kwsquare: 0x33BE, - l: 0x006C, - labengali: 0x09B2, - lacute: 0x013A, - ladeva: 0x0932, - lagujarati: 0x0AB2, - lagurmukhi: 0x0A32, - lakkhangyaothai: 0x0E45, - lamaleffinalarabic: 0xFEFC, - lamalefhamzaabovefinalarabic: 0xFEF8, - lamalefhamzaaboveisolatedarabic: 0xFEF7, - lamalefhamzabelowfinalarabic: 0xFEFA, - lamalefhamzabelowisolatedarabic: 0xFEF9, - lamalefisolatedarabic: 0xFEFB, - lamalefmaddaabovefinalarabic: 0xFEF6, - lamalefmaddaaboveisolatedarabic: 0xFEF5, - lamarabic: 0x0644, - lambda: 0x03BB, - lambdastroke: 0x019B, - lamed: 0x05DC, - lameddagesh: 0xFB3C, - lameddageshhebrew: 0xFB3C, - lamedhebrew: 0x05DC, + hangulfiller: "3164", + hardsigncyrillic: "044A", + harpoonleftbarbup: "21BC", + harpoonrightbarbup: "21C0", + hasquare: "33CA", + hatafpatah: "05B2", + hatafpatah16: "05B2", + hatafpatah23: "05B2", + hatafpatah2f: "05B2", + hatafpatahhebrew: "05B2", + hatafpatahnarrowhebrew: "05B2", + hatafpatahquarterhebrew: "05B2", + hatafpatahwidehebrew: "05B2", + hatafqamats: "05B3", + hatafqamats1b: "05B3", + hatafqamats28: "05B3", + hatafqamats34: "05B3", + hatafqamatshebrew: "05B3", + hatafqamatsnarrowhebrew: "05B3", + hatafqamatsquarterhebrew: "05B3", + hatafqamatswidehebrew: "05B3", + hatafsegol: "05B1", + hatafsegol17: "05B1", + hatafsegol24: "05B1", + hatafsegol30: "05B1", + hatafsegolhebrew: "05B1", + hatafsegolnarrowhebrew: "05B1", + hatafsegolquarterhebrew: "05B1", + hatafsegolwidehebrew: "05B1", + hbar: "0127", + hbopomofo: "310F", + hbrevebelow: "1E2B", + hcedilla: "1E29", + hcircle: "24D7", + hcircumflex: "0125", + hdieresis: "1E27", + hdotaccent: "1E23", + hdotbelow: "1E25", + he: "05D4", + heart: "2665", + heartsuitblack: "2665", + heartsuitwhite: "2661", + hedagesh: "FB34", + hedageshhebrew: "FB34", + hehaltonearabic: "06C1", + heharabic: "0647", + hehebrew: "05D4", + hehfinalaltonearabic: "FBA7", + hehfinalalttwoarabic: "FEEA", + hehfinalarabic: "FEEA", + hehhamzaabovefinalarabic: "FBA5", + hehhamzaaboveisolatedarabic: "FBA4", + hehinitialaltonearabic: "FBA8", + hehinitialarabic: "FEEB", + hehiragana: "3078", + hehmedialaltonearabic: "FBA9", + hehmedialarabic: "FEEC", + heiseierasquare: "337B", + hekatakana: "30D8", + hekatakanahalfwidth: "FF8D", + hekutaarusquare: "3336", + henghook: "0267", + herutusquare: "3339", + het: "05D7", + hethebrew: "05D7", + hhook: "0266", + hhooksuperior: "02B1", + hieuhacirclekorean: "327B", + hieuhaparenkorean: "321B", + hieuhcirclekorean: "326D", + hieuhkorean: "314E", + hieuhparenkorean: "320D", + hihiragana: "3072", + hikatakana: "30D2", + hikatakanahalfwidth: "FF8B", + hiriq: "05B4", + hiriq14: "05B4", + hiriq21: "05B4", + hiriq2d: "05B4", + hiriqhebrew: "05B4", + hiriqnarrowhebrew: "05B4", + hiriqquarterhebrew: "05B4", + hiriqwidehebrew: "05B4", + hlinebelow: "1E96", + hmonospace: "FF48", + hoarmenian: "0570", + hohipthai: "0E2B", + hohiragana: "307B", + hokatakana: "30DB", + hokatakanahalfwidth: "FF8E", + holam: "05B9", + holam19: "05B9", + holam26: "05B9", + holam32: "05B9", + holamhebrew: "05B9", + holamnarrowhebrew: "05B9", + holamquarterhebrew: "05B9", + holamwidehebrew: "05B9", + honokhukthai: "0E2E", + hookabovecomb: "0309", + hookcmb: "0309", + hookpalatalizedbelowcmb: "0321", + hookretroflexbelowcmb: "0322", + hoonsquare: "3342", + horicoptic: "03E9", + horizontalbar: "2015", + horncmb: "031B", + hotsprings: "2668", + house: "2302", + hparen: "24A3", + hsuperior: "02B0", + hturned: "0265", + huhiragana: "3075", + huiitosquare: "3333", + hukatakana: "30D5", + hukatakanahalfwidth: "FF8C", + hungarumlaut: "02DD", + hungarumlautcmb: "030B", + hv: "0195", + hyphen: "002D", + hypheninferior: "F6E5", + hyphenmonospace: "FF0D", + hyphensmall: "FE63", + hyphensuperior: "F6E6", + hyphentwo: "2010", + i: "0069", + iacute: "00ED", + iacyrillic: "044F", + ibengali: "0987", + ibopomofo: "3127", + ibreve: "012D", + icaron: "01D0", + icircle: "24D8", + icircumflex: "00EE", + icyrillic: "0456", + idblgrave: "0209", + ideographearthcircle: "328F", + ideographfirecircle: "328B", + ideographicallianceparen: "323F", + ideographiccallparen: "323A", + ideographiccentrecircle: "32A5", + ideographicclose: "3006", + ideographiccomma: "3001", + ideographiccommaleft: "FF64", + ideographiccongratulationparen: "3237", + ideographiccorrectcircle: "32A3", + ideographicearthparen: "322F", + ideographicenterpriseparen: "323D", + ideographicexcellentcircle: "329D", + ideographicfestivalparen: "3240", + ideographicfinancialcircle: "3296", + ideographicfinancialparen: "3236", + ideographicfireparen: "322B", + ideographichaveparen: "3232", + ideographichighcircle: "32A4", + ideographiciterationmark: "3005", + ideographiclaborcircle: "3298", + ideographiclaborparen: "3238", + ideographicleftcircle: "32A7", + ideographiclowcircle: "32A6", + ideographicmedicinecircle: "32A9", + ideographicmetalparen: "322E", + ideographicmoonparen: "322A", + ideographicnameparen: "3234", + ideographicperiod: "3002", + ideographicprintcircle: "329E", + ideographicreachparen: "3243", + ideographicrepresentparen: "3239", + ideographicresourceparen: "323E", + ideographicrightcircle: "32A8", + ideographicsecretcircle: "3299", + ideographicselfparen: "3242", + ideographicsocietyparen: "3233", + ideographicspace: "3000", + ideographicspecialparen: "3235", + ideographicstockparen: "3231", + ideographicstudyparen: "323B", + ideographicsunparen: "3230", + ideographicsuperviseparen: "323C", + ideographicwaterparen: "322C", + ideographicwoodparen: "322D", + ideographiczero: "3007", + ideographmetalcircle: "328E", + ideographmooncircle: "328A", + ideographnamecircle: "3294", + ideographsuncircle: "3290", + ideographwatercircle: "328C", + ideographwoodcircle: "328D", + ideva: "0907", + idieresis: "00EF", + idieresisacute: "1E2F", + idieresiscyrillic: "04E5", + idotbelow: "1ECB", + iebrevecyrillic: "04D7", + iecyrillic: "0435", + ieungacirclekorean: "3275", + ieungaparenkorean: "3215", + ieungcirclekorean: "3267", + ieungkorean: "3147", + ieungparenkorean: "3207", + igrave: "00EC", + igujarati: "0A87", + igurmukhi: "0A07", + ihiragana: "3044", + ihookabove: "1EC9", + iibengali: "0988", + iicyrillic: "0438", + iideva: "0908", + iigujarati: "0A88", + iigurmukhi: "0A08", + iimatragurmukhi: "0A40", + iinvertedbreve: "020B", + iishortcyrillic: "0439", + iivowelsignbengali: "09C0", + iivowelsigndeva: "0940", + iivowelsigngujarati: "0AC0", + ij: "0133", + ikatakana: "30A4", + ikatakanahalfwidth: "FF72", + ikorean: "3163", + ilde: "02DC", + iluyhebrew: "05AC", + imacron: "012B", + imacroncyrillic: "04E3", + imageorapproximatelyequal: "2253", + imatragurmukhi: "0A3F", + imonospace: "FF49", + increment: "2206", + infinity: "221E", + iniarmenian: "056B", + integral: "222B", + integralbottom: "2321", + integralbt: "2321", + integralex: "F8F5", + integraltop: "2320", + integraltp: "2320", + intersection: "2229", + intisquare: "3305", + invbullet: "25D8", + invcircle: "25D9", + invsmileface: "263B", + iocyrillic: "0451", + iogonek: "012F", + iota: "03B9", + iotadieresis: "03CA", + iotadieresistonos: "0390", + iotalatin: "0269", + iotatonos: "03AF", + iparen: "24A4", + irigurmukhi: "0A72", + ismallhiragana: "3043", + ismallkatakana: "30A3", + ismallkatakanahalfwidth: "FF68", + issharbengali: "09FA", + istroke: "0268", + isuperior: "F6ED", + iterationhiragana: "309D", + iterationkatakana: "30FD", + itilde: "0129", + itildebelow: "1E2D", + iubopomofo: "3129", + iucyrillic: "044E", + ivowelsignbengali: "09BF", + ivowelsigndeva: "093F", + ivowelsigngujarati: "0ABF", + izhitsacyrillic: "0475", + izhitsadblgravecyrillic: "0477", + j: "006A", + jaarmenian: "0571", + jabengali: "099C", + jadeva: "091C", + jagujarati: "0A9C", + jagurmukhi: "0A1C", + jbopomofo: "3110", + jcaron: "01F0", + jcircle: "24D9", + jcircumflex: "0135", + jcrossedtail: "029D", + jdotlessstroke: "025F", + jecyrillic: "0458", + jeemarabic: "062C", + jeemfinalarabic: "FE9E", + jeeminitialarabic: "FE9F", + jeemmedialarabic: "FEA0", + jeharabic: "0698", + jehfinalarabic: "FB8B", + jhabengali: "099D", + jhadeva: "091D", + jhagujarati: "0A9D", + jhagurmukhi: "0A1D", + jheharmenian: "057B", + jis: "3004", + jmonospace: "FF4A", + jparen: "24A5", + jsuperior: "02B2", + k: "006B", + kabashkircyrillic: "04A1", + kabengali: "0995", + kacute: "1E31", + kacyrillic: "043A", + kadescendercyrillic: "049B", + kadeva: "0915", + kaf: "05DB", + kafarabic: "0643", + kafdagesh: "FB3B", + kafdageshhebrew: "FB3B", + kaffinalarabic: "FEDA", + kafhebrew: "05DB", + kafinitialarabic: "FEDB", + kafmedialarabic: "FEDC", + kafrafehebrew: "FB4D", + kagujarati: "0A95", + kagurmukhi: "0A15", + kahiragana: "304B", + kahookcyrillic: "04C4", + kakatakana: "30AB", + kakatakanahalfwidth: "FF76", + kappa: "03BA", + kappasymbolgreek: "03F0", + kapyeounmieumkorean: "3171", + kapyeounphieuphkorean: "3184", + kapyeounpieupkorean: "3178", + kapyeounssangpieupkorean: "3179", + karoriisquare: "330D", + kashidaautoarabic: "0640", + kashidaautonosidebearingarabic: "0640", + kasmallkatakana: "30F5", + kasquare: "3384", + kasraarabic: "0650", + kasratanarabic: "064D", + kastrokecyrillic: "049F", + katahiraprolongmarkhalfwidth: "FF70", + kaverticalstrokecyrillic: "049D", + kbopomofo: "310E", + kcalsquare: "3389", + kcaron: "01E9", + kcedilla: "0137", + kcircle: "24DA", + kcommaaccent: "0137", + kdotbelow: "1E33", + keharmenian: "0584", + kehiragana: "3051", + kekatakana: "30B1", + kekatakanahalfwidth: "FF79", + kenarmenian: "056F", + kesmallkatakana: "30F6", + kgreenlandic: "0138", + khabengali: "0996", + khacyrillic: "0445", + khadeva: "0916", + khagujarati: "0A96", + khagurmukhi: "0A16", + khaharabic: "062E", + khahfinalarabic: "FEA6", + khahinitialarabic: "FEA7", + khahmedialarabic: "FEA8", + kheicoptic: "03E7", + khhadeva: "0959", + khhagurmukhi: "0A59", + khieukhacirclekorean: "3278", + khieukhaparenkorean: "3218", + khieukhcirclekorean: "326A", + khieukhkorean: "314B", + khieukhparenkorean: "320A", + khokhaithai: "0E02", + khokhonthai: "0E05", + khokhuatthai: "0E03", + khokhwaithai: "0E04", + khomutthai: "0E5B", + khook: "0199", + khorakhangthai: "0E06", + khzsquare: "3391", + kihiragana: "304D", + kikatakana: "30AD", + kikatakanahalfwidth: "FF77", + kiroguramusquare: "3315", + kiromeetorusquare: "3316", + kirosquare: "3314", + kiyeokacirclekorean: "326E", + kiyeokaparenkorean: "320E", + kiyeokcirclekorean: "3260", + kiyeokkorean: "3131", + kiyeokparenkorean: "3200", + kiyeoksioskorean: "3133", + kjecyrillic: "045C", + klinebelow: "1E35", + klsquare: "3398", + kmcubedsquare: "33A6", + kmonospace: "FF4B", + kmsquaredsquare: "33A2", + kohiragana: "3053", + kohmsquare: "33C0", + kokaithai: "0E01", + kokatakana: "30B3", + kokatakanahalfwidth: "FF7A", + kooposquare: "331E", + koppacyrillic: "0481", + koreanstandardsymbol: "327F", + koroniscmb: "0343", + kparen: "24A6", + kpasquare: "33AA", + ksicyrillic: "046F", + ktsquare: "33CF", + kturned: "029E", + kuhiragana: "304F", + kukatakana: "30AF", + kukatakanahalfwidth: "FF78", + kvsquare: "33B8", + kwsquare: "33BE", + l: "006C", + labengali: "09B2", + lacute: "013A", + ladeva: "0932", + lagujarati: "0AB2", + lagurmukhi: "0A32", + lakkhangyaothai: "0E45", + lamaleffinalarabic: "FEFC", + lamalefhamzaabovefinalarabic: "FEF8", + lamalefhamzaaboveisolatedarabic: "FEF7", + lamalefhamzabelowfinalarabic: "FEFA", + lamalefhamzabelowisolatedarabic: "FEF9", + lamalefisolatedarabic: "FEFB", + lamalefmaddaabovefinalarabic: "FEF6", + lamalefmaddaaboveisolatedarabic: "FEF5", + lamarabic: "0644", + lambda: "03BB", + lambdastroke: "019B", + lamed: "05DC", + lameddagesh: "FB3C", + lameddageshhebrew: "FB3C", + lamedhebrew: "05DC", lamedholam: "05DC 05B9", lamedholamdagesh: "05DC 05B9 05BC", lamedholamdageshhebrew: "05DC 05B9 05BC", lamedholamhebrew: "05DC 05B9", - lamfinalarabic: 0xFEDE, - lamhahinitialarabic: 0xFCCA, - laminitialarabic: 0xFEDF, - lamjeeminitialarabic: 0xFCC9, - lamkhahinitialarabic: 0xFCCB, - lamlamhehisolatedarabic: 0xFDF2, - lammedialarabic: 0xFEE0, - lammeemhahinitialarabic: 0xFD88, - lammeeminitialarabic: 0xFCCC, + lamfinalarabic: "FEDE", + lamhahinitialarabic: "FCCA", + laminitialarabic: "FEDF", + lamjeeminitialarabic: "FCC9", + lamkhahinitialarabic: "FCCB", + lamlamhehisolatedarabic: "FDF2", + lammedialarabic: "FEE0", + lammeemhahinitialarabic: "FD88", + lammeeminitialarabic: "FCCC", lammeemjeeminitialarabic: "FEDF FEE4 FEA0", lammeemkhahinitialarabic: "FEDF FEE4 FEA8", - largecircle: 0x25EF, - lbar: 0x019A, - lbelt: 0x026C, - lbopomofo: 0x310C, - lcaron: 0x013E, - lcedilla: 0x013C, - lcircle: 0x24DB, - lcircumflexbelow: 0x1E3D, - lcommaaccent: 0x013C, - ldot: 0x0140, - ldotaccent: 0x0140, - ldotbelow: 0x1E37, - ldotbelowmacron: 0x1E39, - leftangleabovecmb: 0x031A, - lefttackbelowcmb: 0x0318, - less: 0x003C, - lessequal: 0x2264, - lessequalorgreater: 0x22DA, - lessmonospace: 0xFF1C, - lessorequivalent: 0x2272, - lessorgreater: 0x2276, - lessoverequal: 0x2266, - lesssmall: 0xFE64, - lezh: 0x026E, - lfblock: 0x258C, - lhookretroflex: 0x026D, - lira: 0x20A4, - liwnarmenian: 0x056C, - lj: 0x01C9, - ljecyrillic: 0x0459, - ll: 0xF6C0, - lladeva: 0x0933, - llagujarati: 0x0AB3, - llinebelow: 0x1E3B, - llladeva: 0x0934, - llvocalicbengali: 0x09E1, - llvocalicdeva: 0x0961, - llvocalicvowelsignbengali: 0x09E3, - llvocalicvowelsigndeva: 0x0963, - lmiddletilde: 0x026B, - lmonospace: 0xFF4C, - lmsquare: 0x33D0, - lochulathai: 0x0E2C, - logicaland: 0x2227, - logicalnot: 0x00AC, - logicalnotreversed: 0x2310, - logicalor: 0x2228, - lolingthai: 0x0E25, - longs: 0x017F, - lowlinecenterline: 0xFE4E, - lowlinecmb: 0x0332, - lowlinedashed: 0xFE4D, - lozenge: 0x25CA, - lparen: 0x24A7, - lslash: 0x0142, - lsquare: 0x2113, - lsuperior: 0xF6EE, - ltshade: 0x2591, - luthai: 0x0E26, - lvocalicbengali: 0x098C, - lvocalicdeva: 0x090C, - lvocalicvowelsignbengali: 0x09E2, - lvocalicvowelsigndeva: 0x0962, - lxsquare: 0x33D3, - m: 0x006D, - mabengali: 0x09AE, - macron: 0x00AF, - macronbelowcmb: 0x0331, - macroncmb: 0x0304, - macronlowmod: 0x02CD, - macronmonospace: 0xFFE3, - macute: 0x1E3F, - madeva: 0x092E, - magujarati: 0x0AAE, - magurmukhi: 0x0A2E, - mahapakhhebrew: 0x05A4, - mahapakhlefthebrew: 0x05A4, - mahiragana: 0x307E, - maichattawalowleftthai: 0xF895, - maichattawalowrightthai: 0xF894, - maichattawathai: 0x0E4B, - maichattawaupperleftthai: 0xF893, - maieklowleftthai: 0xF88C, - maieklowrightthai: 0xF88B, - maiekthai: 0x0E48, - maiekupperleftthai: 0xF88A, - maihanakatleftthai: 0xF884, - maihanakatthai: 0x0E31, - maitaikhuleftthai: 0xF889, - maitaikhuthai: 0x0E47, - maitholowleftthai: 0xF88F, - maitholowrightthai: 0xF88E, - maithothai: 0x0E49, - maithoupperleftthai: 0xF88D, - maitrilowleftthai: 0xF892, - maitrilowrightthai: 0xF891, - maitrithai: 0x0E4A, - maitriupperleftthai: 0xF890, - maiyamokthai: 0x0E46, - makatakana: 0x30DE, - makatakanahalfwidth: 0xFF8F, - male: 0x2642, - mansyonsquare: 0x3347, - maqafhebrew: 0x05BE, - mars: 0x2642, - masoracirclehebrew: 0x05AF, - masquare: 0x3383, - mbopomofo: 0x3107, - mbsquare: 0x33D4, - mcircle: 0x24DC, - mcubedsquare: 0x33A5, - mdotaccent: 0x1E41, - mdotbelow: 0x1E43, - meemarabic: 0x0645, - meemfinalarabic: 0xFEE2, - meeminitialarabic: 0xFEE3, - meemmedialarabic: 0xFEE4, - meemmeeminitialarabic: 0xFCD1, - meemmeemisolatedarabic: 0xFC48, - meetorusquare: 0x334D, - mehiragana: 0x3081, - meizierasquare: 0x337E, - mekatakana: 0x30E1, - mekatakanahalfwidth: 0xFF92, - mem: 0x05DE, - memdagesh: 0xFB3E, - memdageshhebrew: 0xFB3E, - memhebrew: 0x05DE, - menarmenian: 0x0574, - merkhahebrew: 0x05A5, - merkhakefulahebrew: 0x05A6, - merkhakefulalefthebrew: 0x05A6, - merkhalefthebrew: 0x05A5, - mhook: 0x0271, - mhzsquare: 0x3392, - middledotkatakanahalfwidth: 0xFF65, - middot: 0x00B7, - mieumacirclekorean: 0x3272, - mieumaparenkorean: 0x3212, - mieumcirclekorean: 0x3264, - mieumkorean: 0x3141, - mieumpansioskorean: 0x3170, - mieumparenkorean: 0x3204, - mieumpieupkorean: 0x316E, - mieumsioskorean: 0x316F, - mihiragana: 0x307F, - mikatakana: 0x30DF, - mikatakanahalfwidth: 0xFF90, - minus: 0x2212, - minusbelowcmb: 0x0320, - minuscircle: 0x2296, - minusmod: 0x02D7, - minusplus: 0x2213, - minute: 0x2032, - miribaarusquare: 0x334A, - mirisquare: 0x3349, - mlonglegturned: 0x0270, - mlsquare: 0x3396, - mmcubedsquare: 0x33A3, - mmonospace: 0xFF4D, - mmsquaredsquare: 0x339F, - mohiragana: 0x3082, - mohmsquare: 0x33C1, - mokatakana: 0x30E2, - mokatakanahalfwidth: 0xFF93, - molsquare: 0x33D6, - momathai: 0x0E21, - moverssquare: 0x33A7, - moverssquaredsquare: 0x33A8, - mparen: 0x24A8, - mpasquare: 0x33AB, - mssquare: 0x33B3, - msuperior: 0xF6EF, - mturned: 0x026F, - mu: 0x00B5, - mu1: 0x00B5, - muasquare: 0x3382, - muchgreater: 0x226B, - muchless: 0x226A, - mufsquare: 0x338C, - mugreek: 0x03BC, - mugsquare: 0x338D, - muhiragana: 0x3080, - mukatakana: 0x30E0, - mukatakanahalfwidth: 0xFF91, - mulsquare: 0x3395, - multiply: 0x00D7, - mumsquare: 0x339B, - munahhebrew: 0x05A3, - munahlefthebrew: 0x05A3, - musicalnote: 0x266A, - musicalnotedbl: 0x266B, - musicflatsign: 0x266D, - musicsharpsign: 0x266F, - mussquare: 0x33B2, - muvsquare: 0x33B6, - muwsquare: 0x33BC, - mvmegasquare: 0x33B9, - mvsquare: 0x33B7, - mwmegasquare: 0x33BF, - mwsquare: 0x33BD, - n: 0x006E, - nabengali: 0x09A8, - nabla: 0x2207, - nacute: 0x0144, - nadeva: 0x0928, - nagujarati: 0x0AA8, - nagurmukhi: 0x0A28, - nahiragana: 0x306A, - nakatakana: 0x30CA, - nakatakanahalfwidth: 0xFF85, - napostrophe: 0x0149, - nasquare: 0x3381, - nbopomofo: 0x310B, - nbspace: 0x00A0, - ncaron: 0x0148, - ncedilla: 0x0146, - ncircle: 0x24DD, - ncircumflexbelow: 0x1E4B, - ncommaaccent: 0x0146, - ndotaccent: 0x1E45, - ndotbelow: 0x1E47, - nehiragana: 0x306D, - nekatakana: 0x30CD, - nekatakanahalfwidth: 0xFF88, - newsheqelsign: 0x20AA, - nfsquare: 0x338B, - ngabengali: 0x0999, - ngadeva: 0x0919, - ngagujarati: 0x0A99, - ngagurmukhi: 0x0A19, - ngonguthai: 0x0E07, - nhiragana: 0x3093, - nhookleft: 0x0272, - nhookretroflex: 0x0273, - nieunacirclekorean: 0x326F, - nieunaparenkorean: 0x320F, - nieuncieuckorean: 0x3135, - nieuncirclekorean: 0x3261, - nieunhieuhkorean: 0x3136, - nieunkorean: 0x3134, - nieunpansioskorean: 0x3168, - nieunparenkorean: 0x3201, - nieunsioskorean: 0x3167, - nieuntikeutkorean: 0x3166, - nihiragana: 0x306B, - nikatakana: 0x30CB, - nikatakanahalfwidth: 0xFF86, - nikhahitleftthai: 0xF899, - nikhahitthai: 0x0E4D, - nine: 0x0039, - ninearabic: 0x0669, - ninebengali: 0x09EF, - ninecircle: 0x2468, - ninecircleinversesansserif: 0x2792, - ninedeva: 0x096F, - ninegujarati: 0x0AEF, - ninegurmukhi: 0x0A6F, - ninehackarabic: 0x0669, - ninehangzhou: 0x3029, - nineideographicparen: 0x3228, - nineinferior: 0x2089, - ninemonospace: 0xFF19, - nineoldstyle: 0xF739, - nineparen: 0x247C, - nineperiod: 0x2490, - ninepersian: 0x06F9, - nineroman: 0x2178, - ninesuperior: 0x2079, - nineteencircle: 0x2472, - nineteenparen: 0x2486, - nineteenperiod: 0x249A, - ninethai: 0x0E59, - nj: 0x01CC, - njecyrillic: 0x045A, - nkatakana: 0x30F3, - nkatakanahalfwidth: 0xFF9D, - nlegrightlong: 0x019E, - nlinebelow: 0x1E49, - nmonospace: 0xFF4E, - nmsquare: 0x339A, - nnabengali: 0x09A3, - nnadeva: 0x0923, - nnagujarati: 0x0AA3, - nnagurmukhi: 0x0A23, - nnnadeva: 0x0929, - nohiragana: 0x306E, - nokatakana: 0x30CE, - nokatakanahalfwidth: 0xFF89, - nonbreakingspace: 0x00A0, - nonenthai: 0x0E13, - nonuthai: 0x0E19, - noonarabic: 0x0646, - noonfinalarabic: 0xFEE6, - noonghunnaarabic: 0x06BA, - noonghunnafinalarabic: 0xFB9F, + largecircle: "25EF", + lbar: "019A", + lbelt: "026C", + lbopomofo: "310C", + lcaron: "013E", + lcedilla: "013C", + lcircle: "24DB", + lcircumflexbelow: "1E3D", + lcommaaccent: "013C", + ldot: "0140", + ldotaccent: "0140", + ldotbelow: "1E37", + ldotbelowmacron: "1E39", + leftangleabovecmb: "031A", + lefttackbelowcmb: "0318", + less: "003C", + lessequal: "2264", + lessequalorgreater: "22DA", + lessmonospace: "FF1C", + lessorequivalent: "2272", + lessorgreater: "2276", + lessoverequal: "2266", + lesssmall: "FE64", + lezh: "026E", + lfblock: "258C", + lhookretroflex: "026D", + lira: "20A4", + liwnarmenian: "056C", + lj: "01C9", + ljecyrillic: "0459", + ll: "F6C0", + lladeva: "0933", + llagujarati: "0AB3", + llinebelow: "1E3B", + llladeva: "0934", + llvocalicbengali: "09E1", + llvocalicdeva: "0961", + llvocalicvowelsignbengali: "09E3", + llvocalicvowelsigndeva: "0963", + lmiddletilde: "026B", + lmonospace: "FF4C", + lmsquare: "33D0", + lochulathai: "0E2C", + logicaland: "2227", + logicalnot: "00AC", + logicalnotreversed: "2310", + logicalor: "2228", + lolingthai: "0E25", + longs: "017F", + lowlinecenterline: "FE4E", + lowlinecmb: "0332", + lowlinedashed: "FE4D", + lozenge: "25CA", + lparen: "24A7", + lslash: "0142", + lsquare: "2113", + lsuperior: "F6EE", + ltshade: "2591", + luthai: "0E26", + lvocalicbengali: "098C", + lvocalicdeva: "090C", + lvocalicvowelsignbengali: "09E2", + lvocalicvowelsigndeva: "0962", + lxsquare: "33D3", + m: "006D", + mabengali: "09AE", + macron: "00AF", + macronbelowcmb: "0331", + macroncmb: "0304", + macronlowmod: "02CD", + macronmonospace: "FFE3", + macute: "1E3F", + madeva: "092E", + magujarati: "0AAE", + magurmukhi: "0A2E", + mahapakhhebrew: "05A4", + mahapakhlefthebrew: "05A4", + mahiragana: "307E", + maichattawalowleftthai: "F895", + maichattawalowrightthai: "F894", + maichattawathai: "0E4B", + maichattawaupperleftthai: "F893", + maieklowleftthai: "F88C", + maieklowrightthai: "F88B", + maiekthai: "0E48", + maiekupperleftthai: "F88A", + maihanakatleftthai: "F884", + maihanakatthai: "0E31", + maitaikhuleftthai: "F889", + maitaikhuthai: "0E47", + maitholowleftthai: "F88F", + maitholowrightthai: "F88E", + maithothai: "0E49", + maithoupperleftthai: "F88D", + maitrilowleftthai: "F892", + maitrilowrightthai: "F891", + maitrithai: "0E4A", + maitriupperleftthai: "F890", + maiyamokthai: "0E46", + makatakana: "30DE", + makatakanahalfwidth: "FF8F", + male: "2642", + mansyonsquare: "3347", + maqafhebrew: "05BE", + mars: "2642", + masoracirclehebrew: "05AF", + masquare: "3383", + mbopomofo: "3107", + mbsquare: "33D4", + mcircle: "24DC", + mcubedsquare: "33A5", + mdotaccent: "1E41", + mdotbelow: "1E43", + meemarabic: "0645", + meemfinalarabic: "FEE2", + meeminitialarabic: "FEE3", + meemmedialarabic: "FEE4", + meemmeeminitialarabic: "FCD1", + meemmeemisolatedarabic: "FC48", + meetorusquare: "334D", + mehiragana: "3081", + meizierasquare: "337E", + mekatakana: "30E1", + mekatakanahalfwidth: "FF92", + mem: "05DE", + memdagesh: "FB3E", + memdageshhebrew: "FB3E", + memhebrew: "05DE", + menarmenian: "0574", + merkhahebrew: "05A5", + merkhakefulahebrew: "05A6", + merkhakefulalefthebrew: "05A6", + merkhalefthebrew: "05A5", + mhook: "0271", + mhzsquare: "3392", + middledotkatakanahalfwidth: "FF65", + middot: "00B7", + mieumacirclekorean: "3272", + mieumaparenkorean: "3212", + mieumcirclekorean: "3264", + mieumkorean: "3141", + mieumpansioskorean: "3170", + mieumparenkorean: "3204", + mieumpieupkorean: "316E", + mieumsioskorean: "316F", + mihiragana: "307F", + mikatakana: "30DF", + mikatakanahalfwidth: "FF90", + minus: "2212", + minusbelowcmb: "0320", + minuscircle: "2296", + minusmod: "02D7", + minusplus: "2213", + minute: "2032", + miribaarusquare: "334A", + mirisquare: "3349", + mlonglegturned: "0270", + mlsquare: "3396", + mmcubedsquare: "33A3", + mmonospace: "FF4D", + mmsquaredsquare: "339F", + mohiragana: "3082", + mohmsquare: "33C1", + mokatakana: "30E2", + mokatakanahalfwidth: "FF93", + molsquare: "33D6", + momathai: "0E21", + moverssquare: "33A7", + moverssquaredsquare: "33A8", + mparen: "24A8", + mpasquare: "33AB", + mssquare: "33B3", + msuperior: "F6EF", + mturned: "026F", + mu: "00B5", + mu1: "00B5", + muasquare: "3382", + muchgreater: "226B", + muchless: "226A", + mufsquare: "338C", + mugreek: "03BC", + mugsquare: "338D", + muhiragana: "3080", + mukatakana: "30E0", + mukatakanahalfwidth: "FF91", + mulsquare: "3395", + multiply: "00D7", + mumsquare: "339B", + munahhebrew: "05A3", + munahlefthebrew: "05A3", + musicalnote: "266A", + musicalnotedbl: "266B", + musicflatsign: "266D", + musicsharpsign: "266F", + mussquare: "33B2", + muvsquare: "33B6", + muwsquare: "33BC", + mvmegasquare: "33B9", + mvsquare: "33B7", + mwmegasquare: "33BF", + mwsquare: "33BD", + n: "006E", + nabengali: "09A8", + nabla: "2207", + nacute: "0144", + nadeva: "0928", + nagujarati: "0AA8", + nagurmukhi: "0A28", + nahiragana: "306A", + nakatakana: "30CA", + nakatakanahalfwidth: "FF85", + napostrophe: "0149", + nasquare: "3381", + nbopomofo: "310B", + nbspace: "00A0", + ncaron: "0148", + ncedilla: "0146", + ncircle: "24DD", + ncircumflexbelow: "1E4B", + ncommaaccent: "0146", + ndotaccent: "1E45", + ndotbelow: "1E47", + nehiragana: "306D", + nekatakana: "30CD", + nekatakanahalfwidth: "FF88", + newsheqelsign: "20AA", + nfsquare: "338B", + ngabengali: "0999", + ngadeva: "0919", + ngagujarati: "0A99", + ngagurmukhi: "0A19", + ngonguthai: "0E07", + nhiragana: "3093", + nhookleft: "0272", + nhookretroflex: "0273", + nieunacirclekorean: "326F", + nieunaparenkorean: "320F", + nieuncieuckorean: "3135", + nieuncirclekorean: "3261", + nieunhieuhkorean: "3136", + nieunkorean: "3134", + nieunpansioskorean: "3168", + nieunparenkorean: "3201", + nieunsioskorean: "3167", + nieuntikeutkorean: "3166", + nihiragana: "306B", + nikatakana: "30CB", + nikatakanahalfwidth: "FF86", + nikhahitleftthai: "F899", + nikhahitthai: "0E4D", + nine: "0039", + ninearabic: "0669", + ninebengali: "09EF", + ninecircle: "2468", + ninecircleinversesansserif: "2792", + ninedeva: "096F", + ninegujarati: "0AEF", + ninegurmukhi: "0A6F", + ninehackarabic: "0669", + ninehangzhou: "3029", + nineideographicparen: "3228", + nineinferior: "2089", + ninemonospace: "FF19", + nineoldstyle: "F739", + nineparen: "247C", + nineperiod: "2490", + ninepersian: "06F9", + nineroman: "2178", + ninesuperior: "2079", + nineteencircle: "2472", + nineteenparen: "2486", + nineteenperiod: "249A", + ninethai: "0E59", + nj: "01CC", + njecyrillic: "045A", + nkatakana: "30F3", + nkatakanahalfwidth: "FF9D", + nlegrightlong: "019E", + nlinebelow: "1E49", + nmonospace: "FF4E", + nmsquare: "339A", + nnabengali: "09A3", + nnadeva: "0923", + nnagujarati: "0AA3", + nnagurmukhi: "0A23", + nnnadeva: "0929", + nohiragana: "306E", + nokatakana: "30CE", + nokatakanahalfwidth: "FF89", + nonbreakingspace: "00A0", + nonenthai: "0E13", + nonuthai: "0E19", + noonarabic: "0646", + noonfinalarabic: "FEE6", + noonghunnaarabic: "06BA", + noonghunnafinalarabic: "FB9F", noonhehinitialarabic: "FEE7 FEEC", - nooninitialarabic: 0xFEE7, - noonjeeminitialarabic: 0xFCD2, - noonjeemisolatedarabic: 0xFC4B, - noonmedialarabic: 0xFEE8, - noonmeeminitialarabic: 0xFCD5, - noonmeemisolatedarabic: 0xFC4E, - noonnoonfinalarabic: 0xFC8D, - notcontains: 0x220C, - notelement: 0x2209, - notelementof: 0x2209, - notequal: 0x2260, - notgreater: 0x226F, - notgreaternorequal: 0x2271, - notgreaternorless: 0x2279, - notidentical: 0x2262, - notless: 0x226E, - notlessnorequal: 0x2270, - notparallel: 0x2226, - notprecedes: 0x2280, - notsubset: 0x2284, - notsucceeds: 0x2281, - notsuperset: 0x2285, - nowarmenian: 0x0576, - nparen: 0x24A9, - nssquare: 0x33B1, - nsuperior: 0x207F, - ntilde: 0x00F1, - nu: 0x03BD, - nuhiragana: 0x306C, - nukatakana: 0x30CC, - nukatakanahalfwidth: 0xFF87, - nuktabengali: 0x09BC, - nuktadeva: 0x093C, - nuktagujarati: 0x0ABC, - nuktagurmukhi: 0x0A3C, - numbersign: 0x0023, - numbersignmonospace: 0xFF03, - numbersignsmall: 0xFE5F, - numeralsigngreek: 0x0374, - numeralsignlowergreek: 0x0375, - numero: 0x2116, - nun: 0x05E0, - nundagesh: 0xFB40, - nundageshhebrew: 0xFB40, - nunhebrew: 0x05E0, - nvsquare: 0x33B5, - nwsquare: 0x33BB, - nyabengali: 0x099E, - nyadeva: 0x091E, - nyagujarati: 0x0A9E, - nyagurmukhi: 0x0A1E, - o: 0x006F, - oacute: 0x00F3, - oangthai: 0x0E2D, - obarred: 0x0275, - obarredcyrillic: 0x04E9, - obarreddieresiscyrillic: 0x04EB, - obengali: 0x0993, - obopomofo: 0x311B, - obreve: 0x014F, - ocandradeva: 0x0911, - ocandragujarati: 0x0A91, - ocandravowelsigndeva: 0x0949, - ocandravowelsigngujarati: 0x0AC9, - ocaron: 0x01D2, - ocircle: 0x24DE, - ocircumflex: 0x00F4, - ocircumflexacute: 0x1ED1, - ocircumflexdotbelow: 0x1ED9, - ocircumflexgrave: 0x1ED3, - ocircumflexhookabove: 0x1ED5, - ocircumflextilde: 0x1ED7, - ocyrillic: 0x043E, - odblacute: 0x0151, - odblgrave: 0x020D, - odeva: 0x0913, - odieresis: 0x00F6, - odieresiscyrillic: 0x04E7, - odotbelow: 0x1ECD, - oe: 0x0153, - oekorean: 0x315A, - ogonek: 0x02DB, - ogonekcmb: 0x0328, - ograve: 0x00F2, - ogujarati: 0x0A93, - oharmenian: 0x0585, - ohiragana: 0x304A, - ohookabove: 0x1ECF, - ohorn: 0x01A1, - ohornacute: 0x1EDB, - ohorndotbelow: 0x1EE3, - ohorngrave: 0x1EDD, - ohornhookabove: 0x1EDF, - ohorntilde: 0x1EE1, - ohungarumlaut: 0x0151, - oi: 0x01A3, - oinvertedbreve: 0x020F, - okatakana: 0x30AA, - okatakanahalfwidth: 0xFF75, - okorean: 0x3157, - olehebrew: 0x05AB, - omacron: 0x014D, - omacronacute: 0x1E53, - omacrongrave: 0x1E51, - omdeva: 0x0950, - omega: 0x03C9, - omega1: 0x03D6, - omegacyrillic: 0x0461, - omegalatinclosed: 0x0277, - omegaroundcyrillic: 0x047B, - omegatitlocyrillic: 0x047D, - omegatonos: 0x03CE, - omgujarati: 0x0AD0, - omicron: 0x03BF, - omicrontonos: 0x03CC, - omonospace: 0xFF4F, - one: 0x0031, - onearabic: 0x0661, - onebengali: 0x09E7, - onecircle: 0x2460, - onecircleinversesansserif: 0x278A, - onedeva: 0x0967, - onedotenleader: 0x2024, - oneeighth: 0x215B, - onefitted: 0xF6DC, - onegujarati: 0x0AE7, - onegurmukhi: 0x0A67, - onehackarabic: 0x0661, - onehalf: 0x00BD, - onehangzhou: 0x3021, - oneideographicparen: 0x3220, - oneinferior: 0x2081, - onemonospace: 0xFF11, - onenumeratorbengali: 0x09F4, - oneoldstyle: 0xF731, - oneparen: 0x2474, - oneperiod: 0x2488, - onepersian: 0x06F1, - onequarter: 0x00BC, - oneroman: 0x2170, - onesuperior: 0x00B9, - onethai: 0x0E51, - onethird: 0x2153, - oogonek: 0x01EB, - oogonekmacron: 0x01ED, - oogurmukhi: 0x0A13, - oomatragurmukhi: 0x0A4B, - oopen: 0x0254, - oparen: 0x24AA, - openbullet: 0x25E6, - option: 0x2325, - ordfeminine: 0x00AA, - ordmasculine: 0x00BA, - orthogonal: 0x221F, - oshortdeva: 0x0912, - oshortvowelsigndeva: 0x094A, - oslash: 0x00F8, - oslashacute: 0x01FF, - osmallhiragana: 0x3049, - osmallkatakana: 0x30A9, - osmallkatakanahalfwidth: 0xFF6B, - ostrokeacute: 0x01FF, - osuperior: 0xF6F0, - otcyrillic: 0x047F, - otilde: 0x00F5, - otildeacute: 0x1E4D, - otildedieresis: 0x1E4F, - oubopomofo: 0x3121, - overline: 0x203E, - overlinecenterline: 0xFE4A, - overlinecmb: 0x0305, - overlinedashed: 0xFE49, - overlinedblwavy: 0xFE4C, - overlinewavy: 0xFE4B, - overscore: 0x00AF, - ovowelsignbengali: 0x09CB, - ovowelsigndeva: 0x094B, - ovowelsigngujarati: 0x0ACB, - p: 0x0070, - paampssquare: 0x3380, - paasentosquare: 0x332B, - pabengali: 0x09AA, - pacute: 0x1E55, - padeva: 0x092A, - pagedown: 0x21DF, - pageup: 0x21DE, - pagujarati: 0x0AAA, - pagurmukhi: 0x0A2A, - pahiragana: 0x3071, - paiyannoithai: 0x0E2F, - pakatakana: 0x30D1, - palatalizationcyrilliccmb: 0x0484, - palochkacyrillic: 0x04C0, - pansioskorean: 0x317F, - paragraph: 0x00B6, - parallel: 0x2225, - parenleft: 0x0028, - parenleftaltonearabic: 0xFD3E, - parenleftbt: 0xF8ED, - parenleftex: 0xF8EC, - parenleftinferior: 0x208D, - parenleftmonospace: 0xFF08, - parenleftsmall: 0xFE59, - parenleftsuperior: 0x207D, - parenlefttp: 0xF8EB, - parenleftvertical: 0xFE35, - parenright: 0x0029, - parenrightaltonearabic: 0xFD3F, - parenrightbt: 0xF8F8, - parenrightex: 0xF8F7, - parenrightinferior: 0x208E, - parenrightmonospace: 0xFF09, - parenrightsmall: 0xFE5A, - parenrightsuperior: 0x207E, - parenrighttp: 0xF8F6, - parenrightvertical: 0xFE36, - partialdiff: 0x2202, - paseqhebrew: 0x05C0, - pashtahebrew: 0x0599, - pasquare: 0x33A9, - patah: 0x05B7, - patah11: 0x05B7, - patah1d: 0x05B7, - patah2a: 0x05B7, - patahhebrew: 0x05B7, - patahnarrowhebrew: 0x05B7, - patahquarterhebrew: 0x05B7, - patahwidehebrew: 0x05B7, - pazerhebrew: 0x05A1, - pbopomofo: 0x3106, - pcircle: 0x24DF, - pdotaccent: 0x1E57, - pe: 0x05E4, - pecyrillic: 0x043F, - pedagesh: 0xFB44, - pedageshhebrew: 0xFB44, - peezisquare: 0x333B, - pefinaldageshhebrew: 0xFB43, - peharabic: 0x067E, - peharmenian: 0x057A, - pehebrew: 0x05E4, - pehfinalarabic: 0xFB57, - pehinitialarabic: 0xFB58, - pehiragana: 0x307A, - pehmedialarabic: 0xFB59, - pekatakana: 0x30DA, - pemiddlehookcyrillic: 0x04A7, - perafehebrew: 0xFB4E, - percent: 0x0025, - percentarabic: 0x066A, - percentmonospace: 0xFF05, - percentsmall: 0xFE6A, - period: 0x002E, - periodarmenian: 0x0589, - periodcentered: 0x00B7, - periodhalfwidth: 0xFF61, - periodinferior: 0xF6E7, - periodmonospace: 0xFF0E, - periodsmall: 0xFE52, - periodsuperior: 0xF6E8, - perispomenigreekcmb: 0x0342, - perpendicular: 0x22A5, - perthousand: 0x2030, - peseta: 0x20A7, - pfsquare: 0x338A, - phabengali: 0x09AB, - phadeva: 0x092B, - phagujarati: 0x0AAB, - phagurmukhi: 0x0A2B, - phi: 0x03C6, - phi1: 0x03D5, - phieuphacirclekorean: 0x327A, - phieuphaparenkorean: 0x321A, - phieuphcirclekorean: 0x326C, - phieuphkorean: 0x314D, - phieuphparenkorean: 0x320C, - philatin: 0x0278, - phinthuthai: 0x0E3A, - phisymbolgreek: 0x03D5, - phook: 0x01A5, - phophanthai: 0x0E1E, - phophungthai: 0x0E1C, - phosamphaothai: 0x0E20, - pi: 0x03C0, - pieupacirclekorean: 0x3273, - pieupaparenkorean: 0x3213, - pieupcieuckorean: 0x3176, - pieupcirclekorean: 0x3265, - pieupkiyeokkorean: 0x3172, - pieupkorean: 0x3142, - pieupparenkorean: 0x3205, - pieupsioskiyeokkorean: 0x3174, - pieupsioskorean: 0x3144, - pieupsiostikeutkorean: 0x3175, - pieupthieuthkorean: 0x3177, - pieuptikeutkorean: 0x3173, - pihiragana: 0x3074, - pikatakana: 0x30D4, - pisymbolgreek: 0x03D6, - piwrarmenian: 0x0583, - plus: 0x002B, - plusbelowcmb: 0x031F, - pluscircle: 0x2295, - plusminus: 0x00B1, - plusmod: 0x02D6, - plusmonospace: 0xFF0B, - plussmall: 0xFE62, - plussuperior: 0x207A, - pmonospace: 0xFF50, - pmsquare: 0x33D8, - pohiragana: 0x307D, - pointingindexdownwhite: 0x261F, - pointingindexleftwhite: 0x261C, - pointingindexrightwhite: 0x261E, - pointingindexupwhite: 0x261D, - pokatakana: 0x30DD, - poplathai: 0x0E1B, - postalmark: 0x3012, - postalmarkface: 0x3020, - pparen: 0x24AB, - precedes: 0x227A, - prescription: 0x211E, - primemod: 0x02B9, - primereversed: 0x2035, - product: 0x220F, - projective: 0x2305, - prolongedkana: 0x30FC, - propellor: 0x2318, - propersubset: 0x2282, - propersuperset: 0x2283, - proportion: 0x2237, - proportional: 0x221D, - psi: 0x03C8, - psicyrillic: 0x0471, - psilipneumatacyrilliccmb: 0x0486, - pssquare: 0x33B0, - puhiragana: 0x3077, - pukatakana: 0x30D7, - pvsquare: 0x33B4, - pwsquare: 0x33BA, - q: 0x0071, - qadeva: 0x0958, - qadmahebrew: 0x05A8, - qafarabic: 0x0642, - qaffinalarabic: 0xFED6, - qafinitialarabic: 0xFED7, - qafmedialarabic: 0xFED8, - qamats: 0x05B8, - qamats10: 0x05B8, - qamats1a: 0x05B8, - qamats1c: 0x05B8, - qamats27: 0x05B8, - qamats29: 0x05B8, - qamats33: 0x05B8, - qamatsde: 0x05B8, - qamatshebrew: 0x05B8, - qamatsnarrowhebrew: 0x05B8, - qamatsqatanhebrew: 0x05B8, - qamatsqatannarrowhebrew: 0x05B8, - qamatsqatanquarterhebrew: 0x05B8, - qamatsqatanwidehebrew: 0x05B8, - qamatsquarterhebrew: 0x05B8, - qamatswidehebrew: 0x05B8, - qarneyparahebrew: 0x059F, - qbopomofo: 0x3111, - qcircle: 0x24E0, - qhook: 0x02A0, - qmonospace: 0xFF51, - qof: 0x05E7, - qofdagesh: 0xFB47, - qofdageshhebrew: 0xFB47, + nooninitialarabic: "FEE7", + noonjeeminitialarabic: "FCD2", + noonjeemisolatedarabic: "FC4B", + noonmedialarabic: "FEE8", + noonmeeminitialarabic: "FCD5", + noonmeemisolatedarabic: "FC4E", + noonnoonfinalarabic: "FC8D", + notcontains: "220C", + notelement: "2209", + notelementof: "2209", + notequal: "2260", + notgreater: "226F", + notgreaternorequal: "2271", + notgreaternorless: "2279", + notidentical: "2262", + notless: "226E", + notlessnorequal: "2270", + notparallel: "2226", + notprecedes: "2280", + notsubset: "2284", + notsucceeds: "2281", + notsuperset: "2285", + nowarmenian: "0576", + nparen: "24A9", + nssquare: "33B1", + nsuperior: "207F", + ntilde: "00F1", + nu: "03BD", + nuhiragana: "306C", + nukatakana: "30CC", + nukatakanahalfwidth: "FF87", + nuktabengali: "09BC", + nuktadeva: "093C", + nuktagujarati: "0ABC", + nuktagurmukhi: "0A3C", + numbersign: "0023", + numbersignmonospace: "FF03", + numbersignsmall: "FE5F", + numeralsigngreek: "0374", + numeralsignlowergreek: "0375", + numero: "2116", + nun: "05E0", + nundagesh: "FB40", + nundageshhebrew: "FB40", + nunhebrew: "05E0", + nvsquare: "33B5", + nwsquare: "33BB", + nyabengali: "099E", + nyadeva: "091E", + nyagujarati: "0A9E", + nyagurmukhi: "0A1E", + o: "006F", + oacute: "00F3", + oangthai: "0E2D", + obarred: "0275", + obarredcyrillic: "04E9", + obarreddieresiscyrillic: "04EB", + obengali: "0993", + obopomofo: "311B", + obreve: "014F", + ocandradeva: "0911", + ocandragujarati: "0A91", + ocandravowelsigndeva: "0949", + ocandravowelsigngujarati: "0AC9", + ocaron: "01D2", + ocircle: "24DE", + ocircumflex: "00F4", + ocircumflexacute: "1ED1", + ocircumflexdotbelow: "1ED9", + ocircumflexgrave: "1ED3", + ocircumflexhookabove: "1ED5", + ocircumflextilde: "1ED7", + ocyrillic: "043E", + odblacute: "0151", + odblgrave: "020D", + odeva: "0913", + odieresis: "00F6", + odieresiscyrillic: "04E7", + odotbelow: "1ECD", + oe: "0153", + oekorean: "315A", + ogonek: "02DB", + ogonekcmb: "0328", + ograve: "00F2", + ogujarati: "0A93", + oharmenian: "0585", + ohiragana: "304A", + ohookabove: "1ECF", + ohorn: "01A1", + ohornacute: "1EDB", + ohorndotbelow: "1EE3", + ohorngrave: "1EDD", + ohornhookabove: "1EDF", + ohorntilde: "1EE1", + ohungarumlaut: "0151", + oi: "01A3", + oinvertedbreve: "020F", + okatakana: "30AA", + okatakanahalfwidth: "FF75", + okorean: "3157", + olehebrew: "05AB", + omacron: "014D", + omacronacute: "1E53", + omacrongrave: "1E51", + omdeva: "0950", + omega: "03C9", + omega1: "03D6", + omegacyrillic: "0461", + omegalatinclosed: "0277", + omegaroundcyrillic: "047B", + omegatitlocyrillic: "047D", + omegatonos: "03CE", + omgujarati: "0AD0", + omicron: "03BF", + omicrontonos: "03CC", + omonospace: "FF4F", + one: "0031", + onearabic: "0661", + onebengali: "09E7", + onecircle: "2460", + onecircleinversesansserif: "278A", + onedeva: "0967", + onedotenleader: "2024", + oneeighth: "215B", + onefitted: "F6DC", + onegujarati: "0AE7", + onegurmukhi: "0A67", + onehackarabic: "0661", + onehalf: "00BD", + onehangzhou: "3021", + oneideographicparen: "3220", + oneinferior: "2081", + onemonospace: "FF11", + onenumeratorbengali: "09F4", + oneoldstyle: "F731", + oneparen: "2474", + oneperiod: "2488", + onepersian: "06F1", + onequarter: "00BC", + oneroman: "2170", + onesuperior: "00B9", + onethai: "0E51", + onethird: "2153", + oogonek: "01EB", + oogonekmacron: "01ED", + oogurmukhi: "0A13", + oomatragurmukhi: "0A4B", + oopen: "0254", + oparen: "24AA", + openbullet: "25E6", + option: "2325", + ordfeminine: "00AA", + ordmasculine: "00BA", + orthogonal: "221F", + oshortdeva: "0912", + oshortvowelsigndeva: "094A", + oslash: "00F8", + oslashacute: "01FF", + osmallhiragana: "3049", + osmallkatakana: "30A9", + osmallkatakanahalfwidth: "FF6B", + ostrokeacute: "01FF", + osuperior: "F6F0", + otcyrillic: "047F", + otilde: "00F5", + otildeacute: "1E4D", + otildedieresis: "1E4F", + oubopomofo: "3121", + overline: "203E", + overlinecenterline: "FE4A", + overlinecmb: "0305", + overlinedashed: "FE49", + overlinedblwavy: "FE4C", + overlinewavy: "FE4B", + overscore: "00AF", + ovowelsignbengali: "09CB", + ovowelsigndeva: "094B", + ovowelsigngujarati: "0ACB", + p: "0070", + paampssquare: "3380", + paasentosquare: "332B", + pabengali: "09AA", + pacute: "1E55", + padeva: "092A", + pagedown: "21DF", + pageup: "21DE", + pagujarati: "0AAA", + pagurmukhi: "0A2A", + pahiragana: "3071", + paiyannoithai: "0E2F", + pakatakana: "30D1", + palatalizationcyrilliccmb: "0484", + palochkacyrillic: "04C0", + pansioskorean: "317F", + paragraph: "00B6", + parallel: "2225", + parenleft: "0028", + parenleftaltonearabic: "FD3E", + parenleftbt: "F8ED", + parenleftex: "F8EC", + parenleftinferior: "208D", + parenleftmonospace: "FF08", + parenleftsmall: "FE59", + parenleftsuperior: "207D", + parenlefttp: "F8EB", + parenleftvertical: "FE35", + parenright: "0029", + parenrightaltonearabic: "FD3F", + parenrightbt: "F8F8", + parenrightex: "F8F7", + parenrightinferior: "208E", + parenrightmonospace: "FF09", + parenrightsmall: "FE5A", + parenrightsuperior: "207E", + parenrighttp: "F8F6", + parenrightvertical: "FE36", + partialdiff: "2202", + paseqhebrew: "05C0", + pashtahebrew: "0599", + pasquare: "33A9", + patah: "05B7", + patah11: "05B7", + patah1d: "05B7", + patah2a: "05B7", + patahhebrew: "05B7", + patahnarrowhebrew: "05B7", + patahquarterhebrew: "05B7", + patahwidehebrew: "05B7", + pazerhebrew: "05A1", + pbopomofo: "3106", + pcircle: "24DF", + pdotaccent: "1E57", + pe: "05E4", + pecyrillic: "043F", + pedagesh: "FB44", + pedageshhebrew: "FB44", + peezisquare: "333B", + pefinaldageshhebrew: "FB43", + peharabic: "067E", + peharmenian: "057A", + pehebrew: "05E4", + pehfinalarabic: "FB57", + pehinitialarabic: "FB58", + pehiragana: "307A", + pehmedialarabic: "FB59", + pekatakana: "30DA", + pemiddlehookcyrillic: "04A7", + perafehebrew: "FB4E", + percent: "0025", + percentarabic: "066A", + percentmonospace: "FF05", + percentsmall: "FE6A", + period: "002E", + periodarmenian: "0589", + periodcentered: "00B7", + periodhalfwidth: "FF61", + periodinferior: "F6E7", + periodmonospace: "FF0E", + periodsmall: "FE52", + periodsuperior: "F6E8", + perispomenigreekcmb: "0342", + perpendicular: "22A5", + perthousand: "2030", + peseta: "20A7", + pfsquare: "338A", + phabengali: "09AB", + phadeva: "092B", + phagujarati: "0AAB", + phagurmukhi: "0A2B", + phi: "03C6", + phi1: "03D5", + phieuphacirclekorean: "327A", + phieuphaparenkorean: "321A", + phieuphcirclekorean: "326C", + phieuphkorean: "314D", + phieuphparenkorean: "320C", + philatin: "0278", + phinthuthai: "0E3A", + phisymbolgreek: "03D5", + phook: "01A5", + phophanthai: "0E1E", + phophungthai: "0E1C", + phosamphaothai: "0E20", + pi: "03C0", + pieupacirclekorean: "3273", + pieupaparenkorean: "3213", + pieupcieuckorean: "3176", + pieupcirclekorean: "3265", + pieupkiyeokkorean: "3172", + pieupkorean: "3142", + pieupparenkorean: "3205", + pieupsioskiyeokkorean: "3174", + pieupsioskorean: "3144", + pieupsiostikeutkorean: "3175", + pieupthieuthkorean: "3177", + pieuptikeutkorean: "3173", + pihiragana: "3074", + pikatakana: "30D4", + pisymbolgreek: "03D6", + piwrarmenian: "0583", + plus: "002B", + plusbelowcmb: "031F", + pluscircle: "2295", + plusminus: "00B1", + plusmod: "02D6", + plusmonospace: "FF0B", + plussmall: "FE62", + plussuperior: "207A", + pmonospace: "FF50", + pmsquare: "33D8", + pohiragana: "307D", + pointingindexdownwhite: "261F", + pointingindexleftwhite: "261C", + pointingindexrightwhite: "261E", + pointingindexupwhite: "261D", + pokatakana: "30DD", + poplathai: "0E1B", + postalmark: "3012", + postalmarkface: "3020", + pparen: "24AB", + precedes: "227A", + prescription: "211E", + primemod: "02B9", + primereversed: "2035", + product: "220F", + projective: "2305", + prolongedkana: "30FC", + propellor: "2318", + propersubset: "2282", + propersuperset: "2283", + proportion: "2237", + proportional: "221D", + psi: "03C8", + psicyrillic: "0471", + psilipneumatacyrilliccmb: "0486", + pssquare: "33B0", + puhiragana: "3077", + pukatakana: "30D7", + pvsquare: "33B4", + pwsquare: "33BA", + q: "0071", + qadeva: "0958", + qadmahebrew: "05A8", + qafarabic: "0642", + qaffinalarabic: "FED6", + qafinitialarabic: "FED7", + qafmedialarabic: "FED8", + qamats: "05B8", + qamats10: "05B8", + qamats1a: "05B8", + qamats1c: "05B8", + qamats27: "05B8", + qamats29: "05B8", + qamats33: "05B8", + qamatsde: "05B8", + qamatshebrew: "05B8", + qamatsnarrowhebrew: "05B8", + qamatsqatanhebrew: "05B8", + qamatsqatannarrowhebrew: "05B8", + qamatsqatanquarterhebrew: "05B8", + qamatsqatanwidehebrew: "05B8", + qamatsquarterhebrew: "05B8", + qamatswidehebrew: "05B8", + qarneyparahebrew: "059F", + qbopomofo: "3111", + qcircle: "24E0", + qhook: "02A0", + qmonospace: "FF51", + qof: "05E7", + qofdagesh: "FB47", + qofdageshhebrew: "FB47", qofhatafpatah: "05E7 05B2", qofhatafpatahhebrew: "05E7 05B2", qofhatafsegol: "05E7 05B1", qofhatafsegolhebrew: "05E7 05B1", - qofhebrew: 0x05E7, + qofhebrew: "05E7", qofhiriq: "05E7 05B4", qofhiriqhebrew: "05E7 05B4", qofholam: "05E7 05B9", @@ -3172,89 +3172,89 @@ var GlyphsUnicode = { qofshevahebrew: "05E7 05B0", qoftsere: "05E7 05B5", qoftserehebrew: "05E7 05B5", - qparen: 0x24AC, - quarternote: 0x2669, - qubuts: 0x05BB, - qubuts18: 0x05BB, - qubuts25: 0x05BB, - qubuts31: 0x05BB, - qubutshebrew: 0x05BB, - qubutsnarrowhebrew: 0x05BB, - qubutsquarterhebrew: 0x05BB, - qubutswidehebrew: 0x05BB, - question: 0x003F, - questionarabic: 0x061F, - questionarmenian: 0x055E, - questiondown: 0x00BF, - questiondownsmall: 0xF7BF, - questiongreek: 0x037E, - questionmonospace: 0xFF1F, - questionsmall: 0xF73F, - quotedbl: 0x0022, - quotedblbase: 0x201E, - quotedblleft: 0x201C, - quotedblmonospace: 0xFF02, - quotedblprime: 0x301E, - quotedblprimereversed: 0x301D, - quotedblright: 0x201D, - quoteleft: 0x2018, - quoteleftreversed: 0x201B, - quotereversed: 0x201B, - quoteright: 0x2019, - quoterightn: 0x0149, - quotesinglbase: 0x201A, - quotesingle: 0x0027, - quotesinglemonospace: 0xFF07, - r: 0x0072, - raarmenian: 0x057C, - rabengali: 0x09B0, - racute: 0x0155, - radeva: 0x0930, - radical: 0x221A, - radicalex: 0xF8E5, - radoverssquare: 0x33AE, - radoverssquaredsquare: 0x33AF, - radsquare: 0x33AD, - rafe: 0x05BF, - rafehebrew: 0x05BF, - ragujarati: 0x0AB0, - ragurmukhi: 0x0A30, - rahiragana: 0x3089, - rakatakana: 0x30E9, - rakatakanahalfwidth: 0xFF97, - ralowerdiagonalbengali: 0x09F1, - ramiddlediagonalbengali: 0x09F0, - ramshorn: 0x0264, - ratio: 0x2236, - rbopomofo: 0x3116, - rcaron: 0x0159, - rcedilla: 0x0157, - rcircle: 0x24E1, - rcommaaccent: 0x0157, - rdblgrave: 0x0211, - rdotaccent: 0x1E59, - rdotbelow: 0x1E5B, - rdotbelowmacron: 0x1E5D, - referencemark: 0x203B, - reflexsubset: 0x2286, - reflexsuperset: 0x2287, - registered: 0x00AE, - registersans: 0xF8E8, - registerserif: 0xF6DA, - reharabic: 0x0631, - reharmenian: 0x0580, - rehfinalarabic: 0xFEAE, - rehiragana: 0x308C, + qparen: "24AC", + quarternote: "2669", + qubuts: "05BB", + qubuts18: "05BB", + qubuts25: "05BB", + qubuts31: "05BB", + qubutshebrew: "05BB", + qubutsnarrowhebrew: "05BB", + qubutsquarterhebrew: "05BB", + qubutswidehebrew: "05BB", + question: "003F", + questionarabic: "061F", + questionarmenian: "055E", + questiondown: "00BF", + questiondownsmall: "F7BF", + questiongreek: "037E", + questionmonospace: "FF1F", + questionsmall: "F73F", + quotedbl: "0022", + quotedblbase: "201E", + quotedblleft: "201C", + quotedblmonospace: "FF02", + quotedblprime: "301E", + quotedblprimereversed: "301D", + quotedblright: "201D", + quoteleft: "2018", + quoteleftreversed: "201B", + quotereversed: "201B", + quoteright: "2019", + quoterightn: "0149", + quotesinglbase: "201A", + quotesingle: "0027", + quotesinglemonospace: "FF07", + r: "0072", + raarmenian: "057C", + rabengali: "09B0", + racute: "0155", + radeva: "0930", + radical: "221A", + radicalex: "F8E5", + radoverssquare: "33AE", + radoverssquaredsquare: "33AF", + radsquare: "33AD", + rafe: "05BF", + rafehebrew: "05BF", + ragujarati: "0AB0", + ragurmukhi: "0A30", + rahiragana: "3089", + rakatakana: "30E9", + rakatakanahalfwidth: "FF97", + ralowerdiagonalbengali: "09F1", + ramiddlediagonalbengali: "09F0", + ramshorn: "0264", + ratio: "2236", + rbopomofo: "3116", + rcaron: "0159", + rcedilla: "0157", + rcircle: "24E1", + rcommaaccent: "0157", + rdblgrave: "0211", + rdotaccent: "1E59", + rdotbelow: "1E5B", + rdotbelowmacron: "1E5D", + referencemark: "203B", + reflexsubset: "2286", + reflexsuperset: "2287", + registered: "00AE", + registersans: "F8E8", + registerserif: "F6DA", + reharabic: "0631", + reharmenian: "0580", + rehfinalarabic: "FEAE", + rehiragana: "308C", rehyehaleflamarabic: "0631 FEF3 FE8E 0644", - rekatakana: 0x30EC, - rekatakanahalfwidth: 0xFF9A, - resh: 0x05E8, - reshdageshhebrew: 0xFB48, + rekatakana: "30EC", + rekatakanahalfwidth: "FF9A", + resh: "05E8", + reshdageshhebrew: "FB48", reshhatafpatah: "05E8 05B2", reshhatafpatahhebrew: "05E8 05B2", reshhatafsegol: "05E8 05B1", reshhatafsegolhebrew: "05E8 05B1", - reshhebrew: 0x05E8, + reshhebrew: "05E8", reshhiriq: "05E8 05B4", reshhiriqhebrew: "05E8 05B4", reshholam: "05E8 05B9", @@ -3271,1019 +3271,1019 @@ var GlyphsUnicode = { reshshevahebrew: "05E8 05B0", reshtsere: "05E8 05B5", reshtserehebrew: "05E8 05B5", - reversedtilde: 0x223D, - reviahebrew: 0x0597, - reviamugrashhebrew: 0x0597, - revlogicalnot: 0x2310, - rfishhook: 0x027E, - rfishhookreversed: 0x027F, - rhabengali: 0x09DD, - rhadeva: 0x095D, - rho: 0x03C1, - rhook: 0x027D, - rhookturned: 0x027B, - rhookturnedsuperior: 0x02B5, - rhosymbolgreek: 0x03F1, - rhotichookmod: 0x02DE, - rieulacirclekorean: 0x3271, - rieulaparenkorean: 0x3211, - rieulcirclekorean: 0x3263, - rieulhieuhkorean: 0x3140, - rieulkiyeokkorean: 0x313A, - rieulkiyeoksioskorean: 0x3169, - rieulkorean: 0x3139, - rieulmieumkorean: 0x313B, - rieulpansioskorean: 0x316C, - rieulparenkorean: 0x3203, - rieulphieuphkorean: 0x313F, - rieulpieupkorean: 0x313C, - rieulpieupsioskorean: 0x316B, - rieulsioskorean: 0x313D, - rieulthieuthkorean: 0x313E, - rieultikeutkorean: 0x316A, - rieulyeorinhieuhkorean: 0x316D, - rightangle: 0x221F, - righttackbelowcmb: 0x0319, - righttriangle: 0x22BF, - rihiragana: 0x308A, - rikatakana: 0x30EA, - rikatakanahalfwidth: 0xFF98, - ring: 0x02DA, - ringbelowcmb: 0x0325, - ringcmb: 0x030A, - ringhalfleft: 0x02BF, - ringhalfleftarmenian: 0x0559, - ringhalfleftbelowcmb: 0x031C, - ringhalfleftcentered: 0x02D3, - ringhalfright: 0x02BE, - ringhalfrightbelowcmb: 0x0339, - ringhalfrightcentered: 0x02D2, - rinvertedbreve: 0x0213, - rittorusquare: 0x3351, - rlinebelow: 0x1E5F, - rlongleg: 0x027C, - rlonglegturned: 0x027A, - rmonospace: 0xFF52, - rohiragana: 0x308D, - rokatakana: 0x30ED, - rokatakanahalfwidth: 0xFF9B, - roruathai: 0x0E23, - rparen: 0x24AD, - rrabengali: 0x09DC, - rradeva: 0x0931, - rragurmukhi: 0x0A5C, - rreharabic: 0x0691, - rrehfinalarabic: 0xFB8D, - rrvocalicbengali: 0x09E0, - rrvocalicdeva: 0x0960, - rrvocalicgujarati: 0x0AE0, - rrvocalicvowelsignbengali: 0x09C4, - rrvocalicvowelsigndeva: 0x0944, - rrvocalicvowelsigngujarati: 0x0AC4, - rsuperior: 0xF6F1, - rtblock: 0x2590, - rturned: 0x0279, - rturnedsuperior: 0x02B4, - ruhiragana: 0x308B, - rukatakana: 0x30EB, - rukatakanahalfwidth: 0xFF99, - rupeemarkbengali: 0x09F2, - rupeesignbengali: 0x09F3, - rupiah: 0xF6DD, - ruthai: 0x0E24, - rvocalicbengali: 0x098B, - rvocalicdeva: 0x090B, - rvocalicgujarati: 0x0A8B, - rvocalicvowelsignbengali: 0x09C3, - rvocalicvowelsigndeva: 0x0943, - rvocalicvowelsigngujarati: 0x0AC3, - s: 0x0073, - sabengali: 0x09B8, - sacute: 0x015B, - sacutedotaccent: 0x1E65, - sadarabic: 0x0635, - sadeva: 0x0938, - sadfinalarabic: 0xFEBA, - sadinitialarabic: 0xFEBB, - sadmedialarabic: 0xFEBC, - sagujarati: 0x0AB8, - sagurmukhi: 0x0A38, - sahiragana: 0x3055, - sakatakana: 0x30B5, - sakatakanahalfwidth: 0xFF7B, - sallallahoualayhewasallamarabic: 0xFDFA, - samekh: 0x05E1, - samekhdagesh: 0xFB41, - samekhdageshhebrew: 0xFB41, - samekhhebrew: 0x05E1, - saraaathai: 0x0E32, - saraaethai: 0x0E41, - saraaimaimalaithai: 0x0E44, - saraaimaimuanthai: 0x0E43, - saraamthai: 0x0E33, - saraathai: 0x0E30, - saraethai: 0x0E40, - saraiileftthai: 0xF886, - saraiithai: 0x0E35, - saraileftthai: 0xF885, - saraithai: 0x0E34, - saraothai: 0x0E42, - saraueeleftthai: 0xF888, - saraueethai: 0x0E37, - saraueleftthai: 0xF887, - sarauethai: 0x0E36, - sarauthai: 0x0E38, - sarauuthai: 0x0E39, - sbopomofo: 0x3119, - scaron: 0x0161, - scarondotaccent: 0x1E67, - scedilla: 0x015F, - schwa: 0x0259, - schwacyrillic: 0x04D9, - schwadieresiscyrillic: 0x04DB, - schwahook: 0x025A, - scircle: 0x24E2, - scircumflex: 0x015D, - scommaaccent: 0x0219, - sdotaccent: 0x1E61, - sdotbelow: 0x1E63, - sdotbelowdotaccent: 0x1E69, - seagullbelowcmb: 0x033C, - second: 0x2033, - secondtonechinese: 0x02CA, - section: 0x00A7, - seenarabic: 0x0633, - seenfinalarabic: 0xFEB2, - seeninitialarabic: 0xFEB3, - seenmedialarabic: 0xFEB4, - segol: 0x05B6, - segol13: 0x05B6, - segol1f: 0x05B6, - segol2c: 0x05B6, - segolhebrew: 0x05B6, - segolnarrowhebrew: 0x05B6, - segolquarterhebrew: 0x05B6, - segoltahebrew: 0x0592, - segolwidehebrew: 0x05B6, - seharmenian: 0x057D, - sehiragana: 0x305B, - sekatakana: 0x30BB, - sekatakanahalfwidth: 0xFF7E, - semicolon: 0x003B, - semicolonarabic: 0x061B, - semicolonmonospace: 0xFF1B, - semicolonsmall: 0xFE54, - semivoicedmarkkana: 0x309C, - semivoicedmarkkanahalfwidth: 0xFF9F, - sentisquare: 0x3322, - sentosquare: 0x3323, - seven: 0x0037, - sevenarabic: 0x0667, - sevenbengali: 0x09ED, - sevencircle: 0x2466, - sevencircleinversesansserif: 0x2790, - sevendeva: 0x096D, - seveneighths: 0x215E, - sevengujarati: 0x0AED, - sevengurmukhi: 0x0A6D, - sevenhackarabic: 0x0667, - sevenhangzhou: 0x3027, - sevenideographicparen: 0x3226, - seveninferior: 0x2087, - sevenmonospace: 0xFF17, - sevenoldstyle: 0xF737, - sevenparen: 0x247A, - sevenperiod: 0x248E, - sevenpersian: 0x06F7, - sevenroman: 0x2176, - sevensuperior: 0x2077, - seventeencircle: 0x2470, - seventeenparen: 0x2484, - seventeenperiod: 0x2498, - seventhai: 0x0E57, - sfthyphen: 0x00AD, - shaarmenian: 0x0577, - shabengali: 0x09B6, - shacyrillic: 0x0448, - shaddaarabic: 0x0651, - shaddadammaarabic: 0xFC61, - shaddadammatanarabic: 0xFC5E, - shaddafathaarabic: 0xFC60, + reversedtilde: "223D", + reviahebrew: "0597", + reviamugrashhebrew: "0597", + revlogicalnot: "2310", + rfishhook: "027E", + rfishhookreversed: "027F", + rhabengali: "09DD", + rhadeva: "095D", + rho: "03C1", + rhook: "027D", + rhookturned: "027B", + rhookturnedsuperior: "02B5", + rhosymbolgreek: "03F1", + rhotichookmod: "02DE", + rieulacirclekorean: "3271", + rieulaparenkorean: "3211", + rieulcirclekorean: "3263", + rieulhieuhkorean: "3140", + rieulkiyeokkorean: "313A", + rieulkiyeoksioskorean: "3169", + rieulkorean: "3139", + rieulmieumkorean: "313B", + rieulpansioskorean: "316C", + rieulparenkorean: "3203", + rieulphieuphkorean: "313F", + rieulpieupkorean: "313C", + rieulpieupsioskorean: "316B", + rieulsioskorean: "313D", + rieulthieuthkorean: "313E", + rieultikeutkorean: "316A", + rieulyeorinhieuhkorean: "316D", + rightangle: "221F", + righttackbelowcmb: "0319", + righttriangle: "22BF", + rihiragana: "308A", + rikatakana: "30EA", + rikatakanahalfwidth: "FF98", + ring: "02DA", + ringbelowcmb: "0325", + ringcmb: "030A", + ringhalfleft: "02BF", + ringhalfleftarmenian: "0559", + ringhalfleftbelowcmb: "031C", + ringhalfleftcentered: "02D3", + ringhalfright: "02BE", + ringhalfrightbelowcmb: "0339", + ringhalfrightcentered: "02D2", + rinvertedbreve: "0213", + rittorusquare: "3351", + rlinebelow: "1E5F", + rlongleg: "027C", + rlonglegturned: "027A", + rmonospace: "FF52", + rohiragana: "308D", + rokatakana: "30ED", + rokatakanahalfwidth: "FF9B", + roruathai: "0E23", + rparen: "24AD", + rrabengali: "09DC", + rradeva: "0931", + rragurmukhi: "0A5C", + rreharabic: "0691", + rrehfinalarabic: "FB8D", + rrvocalicbengali: "09E0", + rrvocalicdeva: "0960", + rrvocalicgujarati: "0AE0", + rrvocalicvowelsignbengali: "09C4", + rrvocalicvowelsigndeva: "0944", + rrvocalicvowelsigngujarati: "0AC4", + rsuperior: "F6F1", + rtblock: "2590", + rturned: "0279", + rturnedsuperior: "02B4", + ruhiragana: "308B", + rukatakana: "30EB", + rukatakanahalfwidth: "FF99", + rupeemarkbengali: "09F2", + rupeesignbengali: "09F3", + rupiah: "F6DD", + ruthai: "0E24", + rvocalicbengali: "098B", + rvocalicdeva: "090B", + rvocalicgujarati: "0A8B", + rvocalicvowelsignbengali: "09C3", + rvocalicvowelsigndeva: "0943", + rvocalicvowelsigngujarati: "0AC3", + s: "0073", + sabengali: "09B8", + sacute: "015B", + sacutedotaccent: "1E65", + sadarabic: "0635", + sadeva: "0938", + sadfinalarabic: "FEBA", + sadinitialarabic: "FEBB", + sadmedialarabic: "FEBC", + sagujarati: "0AB8", + sagurmukhi: "0A38", + sahiragana: "3055", + sakatakana: "30B5", + sakatakanahalfwidth: "FF7B", + sallallahoualayhewasallamarabic: "FDFA", + samekh: "05E1", + samekhdagesh: "FB41", + samekhdageshhebrew: "FB41", + samekhhebrew: "05E1", + saraaathai: "0E32", + saraaethai: "0E41", + saraaimaimalaithai: "0E44", + saraaimaimuanthai: "0E43", + saraamthai: "0E33", + saraathai: "0E30", + saraethai: "0E40", + saraiileftthai: "F886", + saraiithai: "0E35", + saraileftthai: "F885", + saraithai: "0E34", + saraothai: "0E42", + saraueeleftthai: "F888", + saraueethai: "0E37", + saraueleftthai: "F887", + sarauethai: "0E36", + sarauthai: "0E38", + sarauuthai: "0E39", + sbopomofo: "3119", + scaron: "0161", + scarondotaccent: "1E67", + scedilla: "015F", + schwa: "0259", + schwacyrillic: "04D9", + schwadieresiscyrillic: "04DB", + schwahook: "025A", + scircle: "24E2", + scircumflex: "015D", + scommaaccent: "0219", + sdotaccent: "1E61", + sdotbelow: "1E63", + sdotbelowdotaccent: "1E69", + seagullbelowcmb: "033C", + second: "2033", + secondtonechinese: "02CA", + section: "00A7", + seenarabic: "0633", + seenfinalarabic: "FEB2", + seeninitialarabic: "FEB3", + seenmedialarabic: "FEB4", + segol: "05B6", + segol13: "05B6", + segol1f: "05B6", + segol2c: "05B6", + segolhebrew: "05B6", + segolnarrowhebrew: "05B6", + segolquarterhebrew: "05B6", + segoltahebrew: "0592", + segolwidehebrew: "05B6", + seharmenian: "057D", + sehiragana: "305B", + sekatakana: "30BB", + sekatakanahalfwidth: "FF7E", + semicolon: "003B", + semicolonarabic: "061B", + semicolonmonospace: "FF1B", + semicolonsmall: "FE54", + semivoicedmarkkana: "309C", + semivoicedmarkkanahalfwidth: "FF9F", + sentisquare: "3322", + sentosquare: "3323", + seven: "0037", + sevenarabic: "0667", + sevenbengali: "09ED", + sevencircle: "2466", + sevencircleinversesansserif: "2790", + sevendeva: "096D", + seveneighths: "215E", + sevengujarati: "0AED", + sevengurmukhi: "0A6D", + sevenhackarabic: "0667", + sevenhangzhou: "3027", + sevenideographicparen: "3226", + seveninferior: "2087", + sevenmonospace: "FF17", + sevenoldstyle: "F737", + sevenparen: "247A", + sevenperiod: "248E", + sevenpersian: "06F7", + sevenroman: "2176", + sevensuperior: "2077", + seventeencircle: "2470", + seventeenparen: "2484", + seventeenperiod: "2498", + seventhai: "0E57", + sfthyphen: "00AD", + shaarmenian: "0577", + shabengali: "09B6", + shacyrillic: "0448", + shaddaarabic: "0651", + shaddadammaarabic: "FC61", + shaddadammatanarabic: "FC5E", + shaddafathaarabic: "FC60", shaddafathatanarabic: "0651 064B", - shaddakasraarabic: 0xFC62, - shaddakasratanarabic: 0xFC5F, - shade: 0x2592, - shadedark: 0x2593, - shadelight: 0x2591, - shademedium: 0x2592, - shadeva: 0x0936, - shagujarati: 0x0AB6, - shagurmukhi: 0x0A36, - shalshelethebrew: 0x0593, - shbopomofo: 0x3115, - shchacyrillic: 0x0449, - sheenarabic: 0x0634, - sheenfinalarabic: 0xFEB6, - sheeninitialarabic: 0xFEB7, - sheenmedialarabic: 0xFEB8, - sheicoptic: 0x03E3, - sheqel: 0x20AA, - sheqelhebrew: 0x20AA, - sheva: 0x05B0, - sheva115: 0x05B0, - sheva15: 0x05B0, - sheva22: 0x05B0, - sheva2e: 0x05B0, - shevahebrew: 0x05B0, - shevanarrowhebrew: 0x05B0, - shevaquarterhebrew: 0x05B0, - shevawidehebrew: 0x05B0, - shhacyrillic: 0x04BB, - shimacoptic: 0x03ED, - shin: 0x05E9, - shindagesh: 0xFB49, - shindageshhebrew: 0xFB49, - shindageshshindot: 0xFB2C, - shindageshshindothebrew: 0xFB2C, - shindageshsindot: 0xFB2D, - shindageshsindothebrew: 0xFB2D, - shindothebrew: 0x05C1, - shinhebrew: 0x05E9, - shinshindot: 0xFB2A, - shinshindothebrew: 0xFB2A, - shinsindot: 0xFB2B, - shinsindothebrew: 0xFB2B, - shook: 0x0282, - sigma: 0x03C3, - sigma1: 0x03C2, - sigmafinal: 0x03C2, - sigmalunatesymbolgreek: 0x03F2, - sihiragana: 0x3057, - sikatakana: 0x30B7, - sikatakanahalfwidth: 0xFF7C, - siluqhebrew: 0x05BD, - siluqlefthebrew: 0x05BD, - similar: 0x223C, - sindothebrew: 0x05C2, - siosacirclekorean: 0x3274, - siosaparenkorean: 0x3214, - sioscieuckorean: 0x317E, - sioscirclekorean: 0x3266, - sioskiyeokkorean: 0x317A, - sioskorean: 0x3145, - siosnieunkorean: 0x317B, - siosparenkorean: 0x3206, - siospieupkorean: 0x317D, - siostikeutkorean: 0x317C, - six: 0x0036, - sixarabic: 0x0666, - sixbengali: 0x09EC, - sixcircle: 0x2465, - sixcircleinversesansserif: 0x278F, - sixdeva: 0x096C, - sixgujarati: 0x0AEC, - sixgurmukhi: 0x0A6C, - sixhackarabic: 0x0666, - sixhangzhou: 0x3026, - sixideographicparen: 0x3225, - sixinferior: 0x2086, - sixmonospace: 0xFF16, - sixoldstyle: 0xF736, - sixparen: 0x2479, - sixperiod: 0x248D, - sixpersian: 0x06F6, - sixroman: 0x2175, - sixsuperior: 0x2076, - sixteencircle: 0x246F, - sixteencurrencydenominatorbengali: 0x09F9, - sixteenparen: 0x2483, - sixteenperiod: 0x2497, - sixthai: 0x0E56, - slash: 0x002F, - slashmonospace: 0xFF0F, - slong: 0x017F, - slongdotaccent: 0x1E9B, - smileface: 0x263A, - smonospace: 0xFF53, - sofpasuqhebrew: 0x05C3, - softhyphen: 0x00AD, - softsigncyrillic: 0x044C, - sohiragana: 0x305D, - sokatakana: 0x30BD, - sokatakanahalfwidth: 0xFF7F, - soliduslongoverlaycmb: 0x0338, - solidusshortoverlaycmb: 0x0337, - sorusithai: 0x0E29, - sosalathai: 0x0E28, - sosothai: 0x0E0B, - sosuathai: 0x0E2A, - space: 0x0020, - spacehackarabic: 0x0020, - spade: 0x2660, - spadesuitblack: 0x2660, - spadesuitwhite: 0x2664, - sparen: 0x24AE, - squarebelowcmb: 0x033B, - squarecc: 0x33C4, - squarecm: 0x339D, - squarediagonalcrosshatchfill: 0x25A9, - squarehorizontalfill: 0x25A4, - squarekg: 0x338F, - squarekm: 0x339E, - squarekmcapital: 0x33CE, - squareln: 0x33D1, - squarelog: 0x33D2, - squaremg: 0x338E, - squaremil: 0x33D5, - squaremm: 0x339C, - squaremsquared: 0x33A1, - squareorthogonalcrosshatchfill: 0x25A6, - squareupperlefttolowerrightfill: 0x25A7, - squareupperrighttolowerleftfill: 0x25A8, - squareverticalfill: 0x25A5, - squarewhitewithsmallblack: 0x25A3, - srsquare: 0x33DB, - ssabengali: 0x09B7, - ssadeva: 0x0937, - ssagujarati: 0x0AB7, - ssangcieuckorean: 0x3149, - ssanghieuhkorean: 0x3185, - ssangieungkorean: 0x3180, - ssangkiyeokkorean: 0x3132, - ssangnieunkorean: 0x3165, - ssangpieupkorean: 0x3143, - ssangsioskorean: 0x3146, - ssangtikeutkorean: 0x3138, - ssuperior: 0xF6F2, - sterling: 0x00A3, - sterlingmonospace: 0xFFE1, - strokelongoverlaycmb: 0x0336, - strokeshortoverlaycmb: 0x0335, - subset: 0x2282, - subsetnotequal: 0x228A, - subsetorequal: 0x2286, - succeeds: 0x227B, - suchthat: 0x220B, - suhiragana: 0x3059, - sukatakana: 0x30B9, - sukatakanahalfwidth: 0xFF7D, - sukunarabic: 0x0652, - summation: 0x2211, - sun: 0x263C, - superset: 0x2283, - supersetnotequal: 0x228B, - supersetorequal: 0x2287, - svsquare: 0x33DC, - syouwaerasquare: 0x337C, - t: 0x0074, - tabengali: 0x09A4, - tackdown: 0x22A4, - tackleft: 0x22A3, - tadeva: 0x0924, - tagujarati: 0x0AA4, - tagurmukhi: 0x0A24, - taharabic: 0x0637, - tahfinalarabic: 0xFEC2, - tahinitialarabic: 0xFEC3, - tahiragana: 0x305F, - tahmedialarabic: 0xFEC4, - taisyouerasquare: 0x337D, - takatakana: 0x30BF, - takatakanahalfwidth: 0xFF80, - tatweelarabic: 0x0640, - tau: 0x03C4, - tav: 0x05EA, - tavdages: 0xFB4A, - tavdagesh: 0xFB4A, - tavdageshhebrew: 0xFB4A, - tavhebrew: 0x05EA, - tbar: 0x0167, - tbopomofo: 0x310A, - tcaron: 0x0165, - tccurl: 0x02A8, - tcedilla: 0x0163, - tcheharabic: 0x0686, - tchehfinalarabic: 0xFB7B, - tchehinitialarabic: 0xFB7C, - tchehmedialarabic: 0xFB7D, + shaddakasraarabic: "FC62", + shaddakasratanarabic: "FC5F", + shade: "2592", + shadedark: "2593", + shadelight: "2591", + shademedium: "2592", + shadeva: "0936", + shagujarati: "0AB6", + shagurmukhi: "0A36", + shalshelethebrew: "0593", + shbopomofo: "3115", + shchacyrillic: "0449", + sheenarabic: "0634", + sheenfinalarabic: "FEB6", + sheeninitialarabic: "FEB7", + sheenmedialarabic: "FEB8", + sheicoptic: "03E3", + sheqel: "20AA", + sheqelhebrew: "20AA", + sheva: "05B0", + sheva115: "05B0", + sheva15: "05B0", + sheva22: "05B0", + sheva2e: "05B0", + shevahebrew: "05B0", + shevanarrowhebrew: "05B0", + shevaquarterhebrew: "05B0", + shevawidehebrew: "05B0", + shhacyrillic: "04BB", + shimacoptic: "03ED", + shin: "05E9", + shindagesh: "FB49", + shindageshhebrew: "FB49", + shindageshshindot: "FB2C", + shindageshshindothebrew: "FB2C", + shindageshsindot: "FB2D", + shindageshsindothebrew: "FB2D", + shindothebrew: "05C1", + shinhebrew: "05E9", + shinshindot: "FB2A", + shinshindothebrew: "FB2A", + shinsindot: "FB2B", + shinsindothebrew: "FB2B", + shook: "0282", + sigma: "03C3", + sigma1: "03C2", + sigmafinal: "03C2", + sigmalunatesymbolgreek: "03F2", + sihiragana: "3057", + sikatakana: "30B7", + sikatakanahalfwidth: "FF7C", + siluqhebrew: "05BD", + siluqlefthebrew: "05BD", + similar: "223C", + sindothebrew: "05C2", + siosacirclekorean: "3274", + siosaparenkorean: "3214", + sioscieuckorean: "317E", + sioscirclekorean: "3266", + sioskiyeokkorean: "317A", + sioskorean: "3145", + siosnieunkorean: "317B", + siosparenkorean: "3206", + siospieupkorean: "317D", + siostikeutkorean: "317C", + six: "0036", + sixarabic: "0666", + sixbengali: "09EC", + sixcircle: "2465", + sixcircleinversesansserif: "278F", + sixdeva: "096C", + sixgujarati: "0AEC", + sixgurmukhi: "0A6C", + sixhackarabic: "0666", + sixhangzhou: "3026", + sixideographicparen: "3225", + sixinferior: "2086", + sixmonospace: "FF16", + sixoldstyle: "F736", + sixparen: "2479", + sixperiod: "248D", + sixpersian: "06F6", + sixroman: "2175", + sixsuperior: "2076", + sixteencircle: "246F", + sixteencurrencydenominatorbengali: "09F9", + sixteenparen: "2483", + sixteenperiod: "2497", + sixthai: "0E56", + slash: "002F", + slashmonospace: "FF0F", + slong: "017F", + slongdotaccent: "1E9B", + smileface: "263A", + smonospace: "FF53", + sofpasuqhebrew: "05C3", + softhyphen: "00AD", + softsigncyrillic: "044C", + sohiragana: "305D", + sokatakana: "30BD", + sokatakanahalfwidth: "FF7F", + soliduslongoverlaycmb: "0338", + solidusshortoverlaycmb: "0337", + sorusithai: "0E29", + sosalathai: "0E28", + sosothai: "0E0B", + sosuathai: "0E2A", + space: "0020", + spacehackarabic: "0020", + spade: "2660", + spadesuitblack: "2660", + spadesuitwhite: "2664", + sparen: "24AE", + squarebelowcmb: "033B", + squarecc: "33C4", + squarecm: "339D", + squarediagonalcrosshatchfill: "25A9", + squarehorizontalfill: "25A4", + squarekg: "338F", + squarekm: "339E", + squarekmcapital: "33CE", + squareln: "33D1", + squarelog: "33D2", + squaremg: "338E", + squaremil: "33D5", + squaremm: "339C", + squaremsquared: "33A1", + squareorthogonalcrosshatchfill: "25A6", + squareupperlefttolowerrightfill: "25A7", + squareupperrighttolowerleftfill: "25A8", + squareverticalfill: "25A5", + squarewhitewithsmallblack: "25A3", + srsquare: "33DB", + ssabengali: "09B7", + ssadeva: "0937", + ssagujarati: "0AB7", + ssangcieuckorean: "3149", + ssanghieuhkorean: "3185", + ssangieungkorean: "3180", + ssangkiyeokkorean: "3132", + ssangnieunkorean: "3165", + ssangpieupkorean: "3143", + ssangsioskorean: "3146", + ssangtikeutkorean: "3138", + ssuperior: "F6F2", + sterling: "00A3", + sterlingmonospace: "FFE1", + strokelongoverlaycmb: "0336", + strokeshortoverlaycmb: "0335", + subset: "2282", + subsetnotequal: "228A", + subsetorequal: "2286", + succeeds: "227B", + suchthat: "220B", + suhiragana: "3059", + sukatakana: "30B9", + sukatakanahalfwidth: "FF7D", + sukunarabic: "0652", + summation: "2211", + sun: "263C", + superset: "2283", + supersetnotequal: "228B", + supersetorequal: "2287", + svsquare: "33DC", + syouwaerasquare: "337C", + t: "0074", + tabengali: "09A4", + tackdown: "22A4", + tackleft: "22A3", + tadeva: "0924", + tagujarati: "0AA4", + tagurmukhi: "0A24", + taharabic: "0637", + tahfinalarabic: "FEC2", + tahinitialarabic: "FEC3", + tahiragana: "305F", + tahmedialarabic: "FEC4", + taisyouerasquare: "337D", + takatakana: "30BF", + takatakanahalfwidth: "FF80", + tatweelarabic: "0640", + tau: "03C4", + tav: "05EA", + tavdages: "FB4A", + tavdagesh: "FB4A", + tavdageshhebrew: "FB4A", + tavhebrew: "05EA", + tbar: "0167", + tbopomofo: "310A", + tcaron: "0165", + tccurl: "02A8", + tcedilla: "0163", + tcheharabic: "0686", + tchehfinalarabic: "FB7B", + tchehinitialarabic: "FB7C", + tchehmedialarabic: "FB7D", tchehmeeminitialarabic: "FB7C FEE4", - tcircle: 0x24E3, - tcircumflexbelow: 0x1E71, - tcommaaccent: 0x0163, - tdieresis: 0x1E97, - tdotaccent: 0x1E6B, - tdotbelow: 0x1E6D, - tecyrillic: 0x0442, - tedescendercyrillic: 0x04AD, - teharabic: 0x062A, - tehfinalarabic: 0xFE96, - tehhahinitialarabic: 0xFCA2, - tehhahisolatedarabic: 0xFC0C, - tehinitialarabic: 0xFE97, - tehiragana: 0x3066, - tehjeeminitialarabic: 0xFCA1, - tehjeemisolatedarabic: 0xFC0B, - tehmarbutaarabic: 0x0629, - tehmarbutafinalarabic: 0xFE94, - tehmedialarabic: 0xFE98, - tehmeeminitialarabic: 0xFCA4, - tehmeemisolatedarabic: 0xFC0E, - tehnoonfinalarabic: 0xFC73, - tekatakana: 0x30C6, - tekatakanahalfwidth: 0xFF83, - telephone: 0x2121, - telephoneblack: 0x260E, - telishagedolahebrew: 0x05A0, - telishaqetanahebrew: 0x05A9, - tencircle: 0x2469, - tenideographicparen: 0x3229, - tenparen: 0x247D, - tenperiod: 0x2491, - tenroman: 0x2179, - tesh: 0x02A7, - tet: 0x05D8, - tetdagesh: 0xFB38, - tetdageshhebrew: 0xFB38, - tethebrew: 0x05D8, - tetsecyrillic: 0x04B5, - tevirhebrew: 0x059B, - tevirlefthebrew: 0x059B, - thabengali: 0x09A5, - thadeva: 0x0925, - thagujarati: 0x0AA5, - thagurmukhi: 0x0A25, - thalarabic: 0x0630, - thalfinalarabic: 0xFEAC, - thanthakhatlowleftthai: 0xF898, - thanthakhatlowrightthai: 0xF897, - thanthakhatthai: 0x0E4C, - thanthakhatupperleftthai: 0xF896, - theharabic: 0x062B, - thehfinalarabic: 0xFE9A, - thehinitialarabic: 0xFE9B, - thehmedialarabic: 0xFE9C, - thereexists: 0x2203, - therefore: 0x2234, - theta: 0x03B8, - theta1: 0x03D1, - thetasymbolgreek: 0x03D1, - thieuthacirclekorean: 0x3279, - thieuthaparenkorean: 0x3219, - thieuthcirclekorean: 0x326B, - thieuthkorean: 0x314C, - thieuthparenkorean: 0x320B, - thirteencircle: 0x246C, - thirteenparen: 0x2480, - thirteenperiod: 0x2494, - thonangmonthothai: 0x0E11, - thook: 0x01AD, - thophuthaothai: 0x0E12, - thorn: 0x00FE, - thothahanthai: 0x0E17, - thothanthai: 0x0E10, - thothongthai: 0x0E18, - thothungthai: 0x0E16, - thousandcyrillic: 0x0482, - thousandsseparatorarabic: 0x066C, - thousandsseparatorpersian: 0x066C, - three: 0x0033, - threearabic: 0x0663, - threebengali: 0x09E9, - threecircle: 0x2462, - threecircleinversesansserif: 0x278C, - threedeva: 0x0969, - threeeighths: 0x215C, - threegujarati: 0x0AE9, - threegurmukhi: 0x0A69, - threehackarabic: 0x0663, - threehangzhou: 0x3023, - threeideographicparen: 0x3222, - threeinferior: 0x2083, - threemonospace: 0xFF13, - threenumeratorbengali: 0x09F6, - threeoldstyle: 0xF733, - threeparen: 0x2476, - threeperiod: 0x248A, - threepersian: 0x06F3, - threequarters: 0x00BE, - threequartersemdash: 0xF6DE, - threeroman: 0x2172, - threesuperior: 0x00B3, - threethai: 0x0E53, - thzsquare: 0x3394, - tihiragana: 0x3061, - tikatakana: 0x30C1, - tikatakanahalfwidth: 0xFF81, - tikeutacirclekorean: 0x3270, - tikeutaparenkorean: 0x3210, - tikeutcirclekorean: 0x3262, - tikeutkorean: 0x3137, - tikeutparenkorean: 0x3202, - tilde: 0x02DC, - tildebelowcmb: 0x0330, - tildecmb: 0x0303, - tildecomb: 0x0303, - tildedoublecmb: 0x0360, - tildeoperator: 0x223C, - tildeoverlaycmb: 0x0334, - tildeverticalcmb: 0x033E, - timescircle: 0x2297, - tipehahebrew: 0x0596, - tipehalefthebrew: 0x0596, - tippigurmukhi: 0x0A70, - titlocyrilliccmb: 0x0483, - tiwnarmenian: 0x057F, - tlinebelow: 0x1E6F, - tmonospace: 0xFF54, - toarmenian: 0x0569, - tohiragana: 0x3068, - tokatakana: 0x30C8, - tokatakanahalfwidth: 0xFF84, - tonebarextrahighmod: 0x02E5, - tonebarextralowmod: 0x02E9, - tonebarhighmod: 0x02E6, - tonebarlowmod: 0x02E8, - tonebarmidmod: 0x02E7, - tonefive: 0x01BD, - tonesix: 0x0185, - tonetwo: 0x01A8, - tonos: 0x0384, - tonsquare: 0x3327, - topatakthai: 0x0E0F, - tortoiseshellbracketleft: 0x3014, - tortoiseshellbracketleftsmall: 0xFE5D, - tortoiseshellbracketleftvertical: 0xFE39, - tortoiseshellbracketright: 0x3015, - tortoiseshellbracketrightsmall: 0xFE5E, - tortoiseshellbracketrightvertical: 0xFE3A, - totaothai: 0x0E15, - tpalatalhook: 0x01AB, - tparen: 0x24AF, - trademark: 0x2122, - trademarksans: 0xF8EA, - trademarkserif: 0xF6DB, - tretroflexhook: 0x0288, - triagdn: 0x25BC, - triaglf: 0x25C4, - triagrt: 0x25BA, - triagup: 0x25B2, - ts: 0x02A6, - tsadi: 0x05E6, - tsadidagesh: 0xFB46, - tsadidageshhebrew: 0xFB46, - tsadihebrew: 0x05E6, - tsecyrillic: 0x0446, - tsere: 0x05B5, - tsere12: 0x05B5, - tsere1e: 0x05B5, - tsere2b: 0x05B5, - tserehebrew: 0x05B5, - tserenarrowhebrew: 0x05B5, - tserequarterhebrew: 0x05B5, - tserewidehebrew: 0x05B5, - tshecyrillic: 0x045B, - tsuperior: 0xF6F3, - ttabengali: 0x099F, - ttadeva: 0x091F, - ttagujarati: 0x0A9F, - ttagurmukhi: 0x0A1F, - tteharabic: 0x0679, - ttehfinalarabic: 0xFB67, - ttehinitialarabic: 0xFB68, - ttehmedialarabic: 0xFB69, - tthabengali: 0x09A0, - tthadeva: 0x0920, - tthagujarati: 0x0AA0, - tthagurmukhi: 0x0A20, - tturned: 0x0287, - tuhiragana: 0x3064, - tukatakana: 0x30C4, - tukatakanahalfwidth: 0xFF82, - tusmallhiragana: 0x3063, - tusmallkatakana: 0x30C3, - tusmallkatakanahalfwidth: 0xFF6F, - twelvecircle: 0x246B, - twelveparen: 0x247F, - twelveperiod: 0x2493, - twelveroman: 0x217B, - twentycircle: 0x2473, - twentyhangzhou: 0x5344, - twentyparen: 0x2487, - twentyperiod: 0x249B, - two: 0x0032, - twoarabic: 0x0662, - twobengali: 0x09E8, - twocircle: 0x2461, - twocircleinversesansserif: 0x278B, - twodeva: 0x0968, - twodotenleader: 0x2025, - twodotleader: 0x2025, - twodotleadervertical: 0xFE30, - twogujarati: 0x0AE8, - twogurmukhi: 0x0A68, - twohackarabic: 0x0662, - twohangzhou: 0x3022, - twoideographicparen: 0x3221, - twoinferior: 0x2082, - twomonospace: 0xFF12, - twonumeratorbengali: 0x09F5, - twooldstyle: 0xF732, - twoparen: 0x2475, - twoperiod: 0x2489, - twopersian: 0x06F2, - tworoman: 0x2171, - twostroke: 0x01BB, - twosuperior: 0x00B2, - twothai: 0x0E52, - twothirds: 0x2154, - u: 0x0075, - uacute: 0x00FA, - ubar: 0x0289, - ubengali: 0x0989, - ubopomofo: 0x3128, - ubreve: 0x016D, - ucaron: 0x01D4, - ucircle: 0x24E4, - ucircumflex: 0x00FB, - ucircumflexbelow: 0x1E77, - ucyrillic: 0x0443, - udattadeva: 0x0951, - udblacute: 0x0171, - udblgrave: 0x0215, - udeva: 0x0909, - udieresis: 0x00FC, - udieresisacute: 0x01D8, - udieresisbelow: 0x1E73, - udieresiscaron: 0x01DA, - udieresiscyrillic: 0x04F1, - udieresisgrave: 0x01DC, - udieresismacron: 0x01D6, - udotbelow: 0x1EE5, - ugrave: 0x00F9, - ugujarati: 0x0A89, - ugurmukhi: 0x0A09, - uhiragana: 0x3046, - uhookabove: 0x1EE7, - uhorn: 0x01B0, - uhornacute: 0x1EE9, - uhorndotbelow: 0x1EF1, - uhorngrave: 0x1EEB, - uhornhookabove: 0x1EED, - uhorntilde: 0x1EEF, - uhungarumlaut: 0x0171, - uhungarumlautcyrillic: 0x04F3, - uinvertedbreve: 0x0217, - ukatakana: 0x30A6, - ukatakanahalfwidth: 0xFF73, - ukcyrillic: 0x0479, - ukorean: 0x315C, - umacron: 0x016B, - umacroncyrillic: 0x04EF, - umacrondieresis: 0x1E7B, - umatragurmukhi: 0x0A41, - umonospace: 0xFF55, - underscore: 0x005F, - underscoredbl: 0x2017, - underscoremonospace: 0xFF3F, - underscorevertical: 0xFE33, - underscorewavy: 0xFE4F, - union: 0x222A, - universal: 0x2200, - uogonek: 0x0173, - uparen: 0x24B0, - upblock: 0x2580, - upperdothebrew: 0x05C4, - upsilon: 0x03C5, - upsilondieresis: 0x03CB, - upsilondieresistonos: 0x03B0, - upsilonlatin: 0x028A, - upsilontonos: 0x03CD, - uptackbelowcmb: 0x031D, - uptackmod: 0x02D4, - uragurmukhi: 0x0A73, - uring: 0x016F, - ushortcyrillic: 0x045E, - usmallhiragana: 0x3045, - usmallkatakana: 0x30A5, - usmallkatakanahalfwidth: 0xFF69, - ustraightcyrillic: 0x04AF, - ustraightstrokecyrillic: 0x04B1, - utilde: 0x0169, - utildeacute: 0x1E79, - utildebelow: 0x1E75, - uubengali: 0x098A, - uudeva: 0x090A, - uugujarati: 0x0A8A, - uugurmukhi: 0x0A0A, - uumatragurmukhi: 0x0A42, - uuvowelsignbengali: 0x09C2, - uuvowelsigndeva: 0x0942, - uuvowelsigngujarati: 0x0AC2, - uvowelsignbengali: 0x09C1, - uvowelsigndeva: 0x0941, - uvowelsigngujarati: 0x0AC1, - v: 0x0076, - vadeva: 0x0935, - vagujarati: 0x0AB5, - vagurmukhi: 0x0A35, - vakatakana: 0x30F7, - vav: 0x05D5, - vavdagesh: 0xFB35, - vavdagesh65: 0xFB35, - vavdageshhebrew: 0xFB35, - vavhebrew: 0x05D5, - vavholam: 0xFB4B, - vavholamhebrew: 0xFB4B, - vavvavhebrew: 0x05F0, - vavyodhebrew: 0x05F1, - vcircle: 0x24E5, - vdotbelow: 0x1E7F, - vecyrillic: 0x0432, - veharabic: 0x06A4, - vehfinalarabic: 0xFB6B, - vehinitialarabic: 0xFB6C, - vehmedialarabic: 0xFB6D, - vekatakana: 0x30F9, - venus: 0x2640, - verticalbar: 0x007C, - verticallineabovecmb: 0x030D, - verticallinebelowcmb: 0x0329, - verticallinelowmod: 0x02CC, - verticallinemod: 0x02C8, - vewarmenian: 0x057E, - vhook: 0x028B, - vikatakana: 0x30F8, - viramabengali: 0x09CD, - viramadeva: 0x094D, - viramagujarati: 0x0ACD, - visargabengali: 0x0983, - visargadeva: 0x0903, - visargagujarati: 0x0A83, - vmonospace: 0xFF56, - voarmenian: 0x0578, - voicediterationhiragana: 0x309E, - voicediterationkatakana: 0x30FE, - voicedmarkkana: 0x309B, - voicedmarkkanahalfwidth: 0xFF9E, - vokatakana: 0x30FA, - vparen: 0x24B1, - vtilde: 0x1E7D, - vturned: 0x028C, - vuhiragana: 0x3094, - vukatakana: 0x30F4, - w: 0x0077, - wacute: 0x1E83, - waekorean: 0x3159, - wahiragana: 0x308F, - wakatakana: 0x30EF, - wakatakanahalfwidth: 0xFF9C, - wakorean: 0x3158, - wasmallhiragana: 0x308E, - wasmallkatakana: 0x30EE, - wattosquare: 0x3357, - wavedash: 0x301C, - wavyunderscorevertical: 0xFE34, - wawarabic: 0x0648, - wawfinalarabic: 0xFEEE, - wawhamzaabovearabic: 0x0624, - wawhamzaabovefinalarabic: 0xFE86, - wbsquare: 0x33DD, - wcircle: 0x24E6, - wcircumflex: 0x0175, - wdieresis: 0x1E85, - wdotaccent: 0x1E87, - wdotbelow: 0x1E89, - wehiragana: 0x3091, - weierstrass: 0x2118, - wekatakana: 0x30F1, - wekorean: 0x315E, - weokorean: 0x315D, - wgrave: 0x1E81, - whitebullet: 0x25E6, - whitecircle: 0x25CB, - whitecircleinverse: 0x25D9, - whitecornerbracketleft: 0x300E, - whitecornerbracketleftvertical: 0xFE43, - whitecornerbracketright: 0x300F, - whitecornerbracketrightvertical: 0xFE44, - whitediamond: 0x25C7, - whitediamondcontainingblacksmalldiamond: 0x25C8, - whitedownpointingsmalltriangle: 0x25BF, - whitedownpointingtriangle: 0x25BD, - whiteleftpointingsmalltriangle: 0x25C3, - whiteleftpointingtriangle: 0x25C1, - whitelenticularbracketleft: 0x3016, - whitelenticularbracketright: 0x3017, - whiterightpointingsmalltriangle: 0x25B9, - whiterightpointingtriangle: 0x25B7, - whitesmallsquare: 0x25AB, - whitesmilingface: 0x263A, - whitesquare: 0x25A1, - whitestar: 0x2606, - whitetelephone: 0x260F, - whitetortoiseshellbracketleft: 0x3018, - whitetortoiseshellbracketright: 0x3019, - whiteuppointingsmalltriangle: 0x25B5, - whiteuppointingtriangle: 0x25B3, - wihiragana: 0x3090, - wikatakana: 0x30F0, - wikorean: 0x315F, - wmonospace: 0xFF57, - wohiragana: 0x3092, - wokatakana: 0x30F2, - wokatakanahalfwidth: 0xFF66, - won: 0x20A9, - wonmonospace: 0xFFE6, - wowaenthai: 0x0E27, - wparen: 0x24B2, - wring: 0x1E98, - wsuperior: 0x02B7, - wturned: 0x028D, - wynn: 0x01BF, - x: 0x0078, - xabovecmb: 0x033D, - xbopomofo: 0x3112, - xcircle: 0x24E7, - xdieresis: 0x1E8D, - xdotaccent: 0x1E8B, - xeharmenian: 0x056D, - xi: 0x03BE, - xmonospace: 0xFF58, - xparen: 0x24B3, - xsuperior: 0x02E3, - y: 0x0079, - yaadosquare: 0x334E, - yabengali: 0x09AF, - yacute: 0x00FD, - yadeva: 0x092F, - yaekorean: 0x3152, - yagujarati: 0x0AAF, - yagurmukhi: 0x0A2F, - yahiragana: 0x3084, - yakatakana: 0x30E4, - yakatakanahalfwidth: 0xFF94, - yakorean: 0x3151, - yamakkanthai: 0x0E4E, - yasmallhiragana: 0x3083, - yasmallkatakana: 0x30E3, - yasmallkatakanahalfwidth: 0xFF6C, - yatcyrillic: 0x0463, - ycircle: 0x24E8, - ycircumflex: 0x0177, - ydieresis: 0x00FF, - ydotaccent: 0x1E8F, - ydotbelow: 0x1EF5, - yeharabic: 0x064A, - yehbarreearabic: 0x06D2, - yehbarreefinalarabic: 0xFBAF, - yehfinalarabic: 0xFEF2, - yehhamzaabovearabic: 0x0626, - yehhamzaabovefinalarabic: 0xFE8A, - yehhamzaaboveinitialarabic: 0xFE8B, - yehhamzaabovemedialarabic: 0xFE8C, - yehinitialarabic: 0xFEF3, - yehmedialarabic: 0xFEF4, - yehmeeminitialarabic: 0xFCDD, - yehmeemisolatedarabic: 0xFC58, - yehnoonfinalarabic: 0xFC94, - yehthreedotsbelowarabic: 0x06D1, - yekorean: 0x3156, - yen: 0x00A5, - yenmonospace: 0xFFE5, - yeokorean: 0x3155, - yeorinhieuhkorean: 0x3186, - yerahbenyomohebrew: 0x05AA, - yerahbenyomolefthebrew: 0x05AA, - yericyrillic: 0x044B, - yerudieresiscyrillic: 0x04F9, - yesieungkorean: 0x3181, - yesieungpansioskorean: 0x3183, - yesieungsioskorean: 0x3182, - yetivhebrew: 0x059A, - ygrave: 0x1EF3, - yhook: 0x01B4, - yhookabove: 0x1EF7, - yiarmenian: 0x0575, - yicyrillic: 0x0457, - yikorean: 0x3162, - yinyang: 0x262F, - yiwnarmenian: 0x0582, - ymonospace: 0xFF59, - yod: 0x05D9, - yoddagesh: 0xFB39, - yoddageshhebrew: 0xFB39, - yodhebrew: 0x05D9, - yodyodhebrew: 0x05F2, - yodyodpatahhebrew: 0xFB1F, - yohiragana: 0x3088, - yoikorean: 0x3189, - yokatakana: 0x30E8, - yokatakanahalfwidth: 0xFF96, - yokorean: 0x315B, - yosmallhiragana: 0x3087, - yosmallkatakana: 0x30E7, - yosmallkatakanahalfwidth: 0xFF6E, - yotgreek: 0x03F3, - yoyaekorean: 0x3188, - yoyakorean: 0x3187, - yoyakthai: 0x0E22, - yoyingthai: 0x0E0D, - yparen: 0x24B4, - ypogegrammeni: 0x037A, - ypogegrammenigreekcmb: 0x0345, - yr: 0x01A6, - yring: 0x1E99, - ysuperior: 0x02B8, - ytilde: 0x1EF9, - yturned: 0x028E, - yuhiragana: 0x3086, - yuikorean: 0x318C, - yukatakana: 0x30E6, - yukatakanahalfwidth: 0xFF95, - yukorean: 0x3160, - yusbigcyrillic: 0x046B, - yusbigiotifiedcyrillic: 0x046D, - yuslittlecyrillic: 0x0467, - yuslittleiotifiedcyrillic: 0x0469, - yusmallhiragana: 0x3085, - yusmallkatakana: 0x30E5, - yusmallkatakanahalfwidth: 0xFF6D, - yuyekorean: 0x318B, - yuyeokorean: 0x318A, - yyabengali: 0x09DF, - yyadeva: 0x095F, - z: 0x007A, - zaarmenian: 0x0566, - zacute: 0x017A, - zadeva: 0x095B, - zagurmukhi: 0x0A5B, - zaharabic: 0x0638, - zahfinalarabic: 0xFEC6, - zahinitialarabic: 0xFEC7, - zahiragana: 0x3056, - zahmedialarabic: 0xFEC8, - zainarabic: 0x0632, - zainfinalarabic: 0xFEB0, - zakatakana: 0x30B6, - zaqefgadolhebrew: 0x0595, - zaqefqatanhebrew: 0x0594, - zarqahebrew: 0x0598, - zayin: 0x05D6, - zayindagesh: 0xFB36, - zayindageshhebrew: 0xFB36, - zayinhebrew: 0x05D6, - zbopomofo: 0x3117, - zcaron: 0x017E, - zcircle: 0x24E9, - zcircumflex: 0x1E91, - zcurl: 0x0291, - zdot: 0x017C, - zdotaccent: 0x017C, - zdotbelow: 0x1E93, - zecyrillic: 0x0437, - zedescendercyrillic: 0x0499, - zedieresiscyrillic: 0x04DF, - zehiragana: 0x305C, - zekatakana: 0x30BC, - zero: 0x0030, - zeroarabic: 0x0660, - zerobengali: 0x09E6, - zerodeva: 0x0966, - zerogujarati: 0x0AE6, - zerogurmukhi: 0x0A66, - zerohackarabic: 0x0660, - zeroinferior: 0x2080, - zeromonospace: 0xFF10, - zerooldstyle: 0xF730, - zeropersian: 0x06F0, - zerosuperior: 0x2070, - zerothai: 0x0E50, - zerowidthjoiner: 0xFEFF, - zerowidthnonjoiner: 0x200C, - zerowidthspace: 0x200B, - zeta: 0x03B6, - zhbopomofo: 0x3113, - zhearmenian: 0x056A, - zhebrevecyrillic: 0x04C2, - zhecyrillic: 0x0436, - zhedescendercyrillic: 0x0497, - zhedieresiscyrillic: 0x04DD, - zihiragana: 0x3058, - zikatakana: 0x30B8, - zinorhebrew: 0x05AE, - zlinebelow: 0x1E95, - zmonospace: 0xFF5A, - zohiragana: 0x305E, - zokatakana: 0x30BE, - zparen: 0x24B5, - zretroflexhook: 0x0290, - zstroke: 0x01B6, - zuhiragana: 0x305A, - zukatakana: 0x30BA + tcircle: "24E3", + tcircumflexbelow: "1E71", + tcommaaccent: "0163", + tdieresis: "1E97", + tdotaccent: "1E6B", + tdotbelow: "1E6D", + tecyrillic: "0442", + tedescendercyrillic: "04AD", + teharabic: "062A", + tehfinalarabic: "FE96", + tehhahinitialarabic: "FCA2", + tehhahisolatedarabic: "FC0C", + tehinitialarabic: "FE97", + tehiragana: "3066", + tehjeeminitialarabic: "FCA1", + tehjeemisolatedarabic: "FC0B", + tehmarbutaarabic: "0629", + tehmarbutafinalarabic: "FE94", + tehmedialarabic: "FE98", + tehmeeminitialarabic: "FCA4", + tehmeemisolatedarabic: "FC0E", + tehnoonfinalarabic: "FC73", + tekatakana: "30C6", + tekatakanahalfwidth: "FF83", + telephone: "2121", + telephoneblack: "260E", + telishagedolahebrew: "05A0", + telishaqetanahebrew: "05A9", + tencircle: "2469", + tenideographicparen: "3229", + tenparen: "247D", + tenperiod: "2491", + tenroman: "2179", + tesh: "02A7", + tet: "05D8", + tetdagesh: "FB38", + tetdageshhebrew: "FB38", + tethebrew: "05D8", + tetsecyrillic: "04B5", + tevirhebrew: "059B", + tevirlefthebrew: "059B", + thabengali: "09A5", + thadeva: "0925", + thagujarati: "0AA5", + thagurmukhi: "0A25", + thalarabic: "0630", + thalfinalarabic: "FEAC", + thanthakhatlowleftthai: "F898", + thanthakhatlowrightthai: "F897", + thanthakhatthai: "0E4C", + thanthakhatupperleftthai: "F896", + theharabic: "062B", + thehfinalarabic: "FE9A", + thehinitialarabic: "FE9B", + thehmedialarabic: "FE9C", + thereexists: "2203", + therefore: "2234", + theta: "03B8", + theta1: "03D1", + thetasymbolgreek: "03D1", + thieuthacirclekorean: "3279", + thieuthaparenkorean: "3219", + thieuthcirclekorean: "326B", + thieuthkorean: "314C", + thieuthparenkorean: "320B", + thirteencircle: "246C", + thirteenparen: "2480", + thirteenperiod: "2494", + thonangmonthothai: "0E11", + thook: "01AD", + thophuthaothai: "0E12", + thorn: "00FE", + thothahanthai: "0E17", + thothanthai: "0E10", + thothongthai: "0E18", + thothungthai: "0E16", + thousandcyrillic: "0482", + thousandsseparatorarabic: "066C", + thousandsseparatorpersian: "066C", + three: "0033", + threearabic: "0663", + threebengali: "09E9", + threecircle: "2462", + threecircleinversesansserif: "278C", + threedeva: "0969", + threeeighths: "215C", + threegujarati: "0AE9", + threegurmukhi: "0A69", + threehackarabic: "0663", + threehangzhou: "3023", + threeideographicparen: "3222", + threeinferior: "2083", + threemonospace: "FF13", + threenumeratorbengali: "09F6", + threeoldstyle: "F733", + threeparen: "2476", + threeperiod: "248A", + threepersian: "06F3", + threequarters: "00BE", + threequartersemdash: "F6DE", + threeroman: "2172", + threesuperior: "00B3", + threethai: "0E53", + thzsquare: "3394", + tihiragana: "3061", + tikatakana: "30C1", + tikatakanahalfwidth: "FF81", + tikeutacirclekorean: "3270", + tikeutaparenkorean: "3210", + tikeutcirclekorean: "3262", + tikeutkorean: "3137", + tikeutparenkorean: "3202", + tilde: "02DC", + tildebelowcmb: "0330", + tildecmb: "0303", + tildecomb: "0303", + tildedoublecmb: "0360", + tildeoperator: "223C", + tildeoverlaycmb: "0334", + tildeverticalcmb: "033E", + timescircle: "2297", + tipehahebrew: "0596", + tipehalefthebrew: "0596", + tippigurmukhi: "0A70", + titlocyrilliccmb: "0483", + tiwnarmenian: "057F", + tlinebelow: "1E6F", + tmonospace: "FF54", + toarmenian: "0569", + tohiragana: "3068", + tokatakana: "30C8", + tokatakanahalfwidth: "FF84", + tonebarextrahighmod: "02E5", + tonebarextralowmod: "02E9", + tonebarhighmod: "02E6", + tonebarlowmod: "02E8", + tonebarmidmod: "02E7", + tonefive: "01BD", + tonesix: "0185", + tonetwo: "01A8", + tonos: "0384", + tonsquare: "3327", + topatakthai: "0E0F", + tortoiseshellbracketleft: "3014", + tortoiseshellbracketleftsmall: "FE5D", + tortoiseshellbracketleftvertical: "FE39", + tortoiseshellbracketright: "3015", + tortoiseshellbracketrightsmall: "FE5E", + tortoiseshellbracketrightvertical: "FE3A", + totaothai: "0E15", + tpalatalhook: "01AB", + tparen: "24AF", + trademark: "2122", + trademarksans: "F8EA", + trademarkserif: "F6DB", + tretroflexhook: "0288", + triagdn: "25BC", + triaglf: "25C4", + triagrt: "25BA", + triagup: "25B2", + ts: "02A6", + tsadi: "05E6", + tsadidagesh: "FB46", + tsadidageshhebrew: "FB46", + tsadihebrew: "05E6", + tsecyrillic: "0446", + tsere: "05B5", + tsere12: "05B5", + tsere1e: "05B5", + tsere2b: "05B5", + tserehebrew: "05B5", + tserenarrowhebrew: "05B5", + tserequarterhebrew: "05B5", + tserewidehebrew: "05B5", + tshecyrillic: "045B", + tsuperior: "F6F3", + ttabengali: "099F", + ttadeva: "091F", + ttagujarati: "0A9F", + ttagurmukhi: "0A1F", + tteharabic: "0679", + ttehfinalarabic: "FB67", + ttehinitialarabic: "FB68", + ttehmedialarabic: "FB69", + tthabengali: "09A0", + tthadeva: "0920", + tthagujarati: "0AA0", + tthagurmukhi: "0A20", + tturned: "0287", + tuhiragana: "3064", + tukatakana: "30C4", + tukatakanahalfwidth: "FF82", + tusmallhiragana: "3063", + tusmallkatakana: "30C3", + tusmallkatakanahalfwidth: "FF6F", + twelvecircle: "246B", + twelveparen: "247F", + twelveperiod: "2493", + twelveroman: "217B", + twentycircle: "2473", + twentyhangzhou: "5344", + twentyparen: "2487", + twentyperiod: "249B", + two: "0032", + twoarabic: "0662", + twobengali: "09E8", + twocircle: "2461", + twocircleinversesansserif: "278B", + twodeva: "0968", + twodotenleader: "2025", + twodotleader: "2025", + twodotleadervertical: "FE30", + twogujarati: "0AE8", + twogurmukhi: "0A68", + twohackarabic: "0662", + twohangzhou: "3022", + twoideographicparen: "3221", + twoinferior: "2082", + twomonospace: "FF12", + twonumeratorbengali: "09F5", + twooldstyle: "F732", + twoparen: "2475", + twoperiod: "2489", + twopersian: "06F2", + tworoman: "2171", + twostroke: "01BB", + twosuperior: "00B2", + twothai: "0E52", + twothirds: "2154", + u: "0075", + uacute: "00FA", + ubar: "0289", + ubengali: "0989", + ubopomofo: "3128", + ubreve: "016D", + ucaron: "01D4", + ucircle: "24E4", + ucircumflex: "00FB", + ucircumflexbelow: "1E77", + ucyrillic: "0443", + udattadeva: "0951", + udblacute: "0171", + udblgrave: "0215", + udeva: "0909", + udieresis: "00FC", + udieresisacute: "01D8", + udieresisbelow: "1E73", + udieresiscaron: "01DA", + udieresiscyrillic: "04F1", + udieresisgrave: "01DC", + udieresismacron: "01D6", + udotbelow: "1EE5", + ugrave: "00F9", + ugujarati: "0A89", + ugurmukhi: "0A09", + uhiragana: "3046", + uhookabove: "1EE7", + uhorn: "01B0", + uhornacute: "1EE9", + uhorndotbelow: "1EF1", + uhorngrave: "1EEB", + uhornhookabove: "1EED", + uhorntilde: "1EEF", + uhungarumlaut: "0171", + uhungarumlautcyrillic: "04F3", + uinvertedbreve: "0217", + ukatakana: "30A6", + ukatakanahalfwidth: "FF73", + ukcyrillic: "0479", + ukorean: "315C", + umacron: "016B", + umacroncyrillic: "04EF", + umacrondieresis: "1E7B", + umatragurmukhi: "0A41", + umonospace: "FF55", + underscore: "005F", + underscoredbl: "2017", + underscoremonospace: "FF3F", + underscorevertical: "FE33", + underscorewavy: "FE4F", + union: "222A", + universal: "2200", + uogonek: "0173", + uparen: "24B0", + upblock: "2580", + upperdothebrew: "05C4", + upsilon: "03C5", + upsilondieresis: "03CB", + upsilondieresistonos: "03B0", + upsilonlatin: "028A", + upsilontonos: "03CD", + uptackbelowcmb: "031D", + uptackmod: "02D4", + uragurmukhi: "0A73", + uring: "016F", + ushortcyrillic: "045E", + usmallhiragana: "3045", + usmallkatakana: "30A5", + usmallkatakanahalfwidth: "FF69", + ustraightcyrillic: "04AF", + ustraightstrokecyrillic: "04B1", + utilde: "0169", + utildeacute: "1E79", + utildebelow: "1E75", + uubengali: "098A", + uudeva: "090A", + uugujarati: "0A8A", + uugurmukhi: "0A0A", + uumatragurmukhi: "0A42", + uuvowelsignbengali: "09C2", + uuvowelsigndeva: "0942", + uuvowelsigngujarati: "0AC2", + uvowelsignbengali: "09C1", + uvowelsigndeva: "0941", + uvowelsigngujarati: "0AC1", + v: "0076", + vadeva: "0935", + vagujarati: "0AB5", + vagurmukhi: "0A35", + vakatakana: "30F7", + vav: "05D5", + vavdagesh: "FB35", + vavdagesh65: "FB35", + vavdageshhebrew: "FB35", + vavhebrew: "05D5", + vavholam: "FB4B", + vavholamhebrew: "FB4B", + vavvavhebrew: "05F0", + vavyodhebrew: "05F1", + vcircle: "24E5", + vdotbelow: "1E7F", + vecyrillic: "0432", + veharabic: "06A4", + vehfinalarabic: "FB6B", + vehinitialarabic: "FB6C", + vehmedialarabic: "FB6D", + vekatakana: "30F9", + venus: "2640", + verticalbar: "007C", + verticallineabovecmb: "030D", + verticallinebelowcmb: "0329", + verticallinelowmod: "02CC", + verticallinemod: "02C8", + vewarmenian: "057E", + vhook: "028B", + vikatakana: "30F8", + viramabengali: "09CD", + viramadeva: "094D", + viramagujarati: "0ACD", + visargabengali: "0983", + visargadeva: "0903", + visargagujarati: "0A83", + vmonospace: "FF56", + voarmenian: "0578", + voicediterationhiragana: "309E", + voicediterationkatakana: "30FE", + voicedmarkkana: "309B", + voicedmarkkanahalfwidth: "FF9E", + vokatakana: "30FA", + vparen: "24B1", + vtilde: "1E7D", + vturned: "028C", + vuhiragana: "3094", + vukatakana: "30F4", + w: "0077", + wacute: "1E83", + waekorean: "3159", + wahiragana: "308F", + wakatakana: "30EF", + wakatakanahalfwidth: "FF9C", + wakorean: "3158", + wasmallhiragana: "308E", + wasmallkatakana: "30EE", + wattosquare: "3357", + wavedash: "301C", + wavyunderscorevertical: "FE34", + wawarabic: "0648", + wawfinalarabic: "FEEE", + wawhamzaabovearabic: "0624", + wawhamzaabovefinalarabic: "FE86", + wbsquare: "33DD", + wcircle: "24E6", + wcircumflex: "0175", + wdieresis: "1E85", + wdotaccent: "1E87", + wdotbelow: "1E89", + wehiragana: "3091", + weierstrass: "2118", + wekatakana: "30F1", + wekorean: "315E", + weokorean: "315D", + wgrave: "1E81", + whitebullet: "25E6", + whitecircle: "25CB", + whitecircleinverse: "25D9", + whitecornerbracketleft: "300E", + whitecornerbracketleftvertical: "FE43", + whitecornerbracketright: "300F", + whitecornerbracketrightvertical: "FE44", + whitediamond: "25C7", + whitediamondcontainingblacksmalldiamond: "25C8", + whitedownpointingsmalltriangle: "25BF", + whitedownpointingtriangle: "25BD", + whiteleftpointingsmalltriangle: "25C3", + whiteleftpointingtriangle: "25C1", + whitelenticularbracketleft: "3016", + whitelenticularbracketright: "3017", + whiterightpointingsmalltriangle: "25B9", + whiterightpointingtriangle: "25B7", + whitesmallsquare: "25AB", + whitesmilingface: "263A", + whitesquare: "25A1", + whitestar: "2606", + whitetelephone: "260F", + whitetortoiseshellbracketleft: "3018", + whitetortoiseshellbracketright: "3019", + whiteuppointingsmalltriangle: "25B5", + whiteuppointingtriangle: "25B3", + wihiragana: "3090", + wikatakana: "30F0", + wikorean: "315F", + wmonospace: "FF57", + wohiragana: "3092", + wokatakana: "30F2", + wokatakanahalfwidth: "FF66", + won: "20A9", + wonmonospace: "FFE6", + wowaenthai: "0E27", + wparen: "24B2", + wring: "1E98", + wsuperior: "02B7", + wturned: "028D", + wynn: "01BF", + x: "0078", + xabovecmb: "033D", + xbopomofo: "3112", + xcircle: "24E7", + xdieresis: "1E8D", + xdotaccent: "1E8B", + xeharmenian: "056D", + xi: "03BE", + xmonospace: "FF58", + xparen: "24B3", + xsuperior: "02E3", + y: "0079", + yaadosquare: "334E", + yabengali: "09AF", + yacute: "00FD", + yadeva: "092F", + yaekorean: "3152", + yagujarati: "0AAF", + yagurmukhi: "0A2F", + yahiragana: "3084", + yakatakana: "30E4", + yakatakanahalfwidth: "FF94", + yakorean: "3151", + yamakkanthai: "0E4E", + yasmallhiragana: "3083", + yasmallkatakana: "30E3", + yasmallkatakanahalfwidth: "FF6C", + yatcyrillic: "0463", + ycircle: "24E8", + ycircumflex: "0177", + ydieresis: "00FF", + ydotaccent: "1E8F", + ydotbelow: "1EF5", + yeharabic: "064A", + yehbarreearabic: "06D2", + yehbarreefinalarabic: "FBAF", + yehfinalarabic: "FEF2", + yehhamzaabovearabic: "0626", + yehhamzaabovefinalarabic: "FE8A", + yehhamzaaboveinitialarabic: "FE8B", + yehhamzaabovemedialarabic: "FE8C", + yehinitialarabic: "FEF3", + yehmedialarabic: "FEF4", + yehmeeminitialarabic: "FCDD", + yehmeemisolatedarabic: "FC58", + yehnoonfinalarabic: "FC94", + yehthreedotsbelowarabic: "06D1", + yekorean: "3156", + yen: "00A5", + yenmonospace: "FFE5", + yeokorean: "3155", + yeorinhieuhkorean: "3186", + yerahbenyomohebrew: "05AA", + yerahbenyomolefthebrew: "05AA", + yericyrillic: "044B", + yerudieresiscyrillic: "04F9", + yesieungkorean: "3181", + yesieungpansioskorean: "3183", + yesieungsioskorean: "3182", + yetivhebrew: "059A", + ygrave: "1EF3", + yhook: "01B4", + yhookabove: "1EF7", + yiarmenian: "0575", + yicyrillic: "0457", + yikorean: "3162", + yinyang: "262F", + yiwnarmenian: "0582", + ymonospace: "FF59", + yod: "05D9", + yoddagesh: "FB39", + yoddageshhebrew: "FB39", + yodhebrew: "05D9", + yodyodhebrew: "05F2", + yodyodpatahhebrew: "FB1F", + yohiragana: "3088", + yoikorean: "3189", + yokatakana: "30E8", + yokatakanahalfwidth: "FF96", + yokorean: "315B", + yosmallhiragana: "3087", + yosmallkatakana: "30E7", + yosmallkatakanahalfwidth: "FF6E", + yotgreek: "03F3", + yoyaekorean: "3188", + yoyakorean: "3187", + yoyakthai: "0E22", + yoyingthai: "0E0D", + yparen: "24B4", + ypogegrammeni: "037A", + ypogegrammenigreekcmb: "0345", + yr: "01A6", + yring: "1E99", + ysuperior: "02B8", + ytilde: "1EF9", + yturned: "028E", + yuhiragana: "3086", + yuikorean: "318C", + yukatakana: "30E6", + yukatakanahalfwidth: "FF95", + yukorean: "3160", + yusbigcyrillic: "046B", + yusbigiotifiedcyrillic: "046D", + yuslittlecyrillic: "0467", + yuslittleiotifiedcyrillic: "0469", + yusmallhiragana: "3085", + yusmallkatakana: "30E5", + yusmallkatakanahalfwidth: "FF6D", + yuyekorean: "318B", + yuyeokorean: "318A", + yyabengali: "09DF", + yyadeva: "095F", + z: "007A", + zaarmenian: "0566", + zacute: "017A", + zadeva: "095B", + zagurmukhi: "0A5B", + zaharabic: "0638", + zahfinalarabic: "FEC6", + zahinitialarabic: "FEC7", + zahiragana: "3056", + zahmedialarabic: "FEC8", + zainarabic: "0632", + zainfinalarabic: "FEB0", + zakatakana: "30B6", + zaqefgadolhebrew: "0595", + zaqefqatanhebrew: "0594", + zarqahebrew: "0598", + zayin: "05D6", + zayindagesh: "FB36", + zayindageshhebrew: "FB36", + zayinhebrew: "05D6", + zbopomofo: "3117", + zcaron: "017E", + zcircle: "24E9", + zcircumflex: "1E91", + zcurl: "0291", + zdot: "017C", + zdotaccent: "017C", + zdotbelow: "1E93", + zecyrillic: "0437", + zedescendercyrillic: "0499", + zedieresiscyrillic: "04DF", + zehiragana: "305C", + zekatakana: "30BC", + zero: "0030", + zeroarabic: "0660", + zerobengali: "09E6", + zerodeva: "0966", + zerogujarati: "0AE6", + zerogurmukhi: "0A66", + zerohackarabic: "0660", + zeroinferior: "2080", + zeromonospace: "FF10", + zerooldstyle: "F730", + zeropersian: "06F0", + zerosuperior: "2070", + zerothai: "0E50", + zerowidthjoiner: "FEFF", + zerowidthnonjoiner: "200C", + zerowidthspace: "200B", + zeta: "03B6", + zhbopomofo: "3113", + zhearmenian: "056A", + zhebrevecyrillic: "04C2", + zhecyrillic: "0436", + zhedescendercyrillic: "0497", + zhedieresiscyrillic: "04DD", + zihiragana: "3058", + zikatakana: "30B8", + zinorhebrew: "05AE", + zlinebelow: "1E95", + zmonospace: "FF5A", + zohiragana: "305E", + zokatakana: "30BE", + zparen: "24B5", + zretroflexhook: "0290", + zstroke: "01B6", + zuhiragana: "305A", + zukatakana: "30BA" }; // Add missing glyphs from the original Adobe's list -GlyphsUnicode["angbracketleft"] = 0x3008; -GlyphsUnicode["angbracketright"] = 0x3009; -GlyphsUnicode["circlecopyrt"] = 0x00A9; +GlyphsUnicode["angbracketleft"] = "3008"; +GlyphsUnicode["angbracketright"] = "3009"; +GlyphsUnicode["circlecopyrt"] = "00A9"; From 416fc7865fe2963a83b7819f608852556f7ebdb5 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 01:03:21 -0700 Subject: [PATCH 052/439] 2nd attempt to make glyph list integers --- fonts.js | 8 +- glyphlist.js | 8406 +++++++++++++++++++++++++------------------------- 2 files changed, 4205 insertions(+), 4209 deletions(-) diff --git a/fonts.js b/fonts.js index 2db7e745f..5390abba4 100644 --- a/fonts.js +++ b/fonts.js @@ -40,7 +40,7 @@ var Fonts = { unicodeFromCode: function fonts_unicodeFromCode(aCode) { var unicode = GlyphsUnicode[this.active.encoding[aCode]]; - return unicode ? "0x" + unicode : aCode; + return unicode ? unicode : aCode; } }; @@ -175,7 +175,7 @@ Font.prototype = { // see what's happening if (debug) { for (var i = 0; i < charset.length; i++) { - var unicode = new Number("0x" + GlyphsUnicode[charset[i]]); + var unicode = GlyphsUnicode[charset[i]]; if (!unicode) error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); testString += String.fromCharCode(unicode); @@ -1183,10 +1183,6 @@ CFF.prototype = { if (glyph != ".notdef") warn(glyph + " does not have an entry in the glyphs unicode dictionary"); } else { - var b1 = parseInt("0x" + unicode[0] + unicode[1]); - var b2 = parseInt("0x" + unicode[2] + unicode[3]); - unicode = FontsUtils.bytesToInteger([b1, b2]); - charstrings.push({ glyph: glyph, unicode: unicode, diff --git a/glyphlist.js b/glyphlist.js index e147f6c8a..f5a11b522 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1,1510 +1,1510 @@ var GlyphsUnicode = { - A: "0041", - AE: "00C6", - AEacute: "01FC", - AEmacron: "01E2", - AEsmall: "F7E6", - Aacute: "00C1", - Aacutesmall: "F7E1", - Abreve: "0102", - Abreveacute: "1EAE", - Abrevecyrillic: "04D0", - Abrevedotbelow: "1EB6", - Abrevegrave: "1EB0", - Abrevehookabove: "1EB2", - Abrevetilde: "1EB4", - Acaron: "01CD", - Acircle: "24B6", - Acircumflex: "00C2", - Acircumflexacute: "1EA4", - Acircumflexdotbelow: "1EAC", - Acircumflexgrave: "1EA6", - Acircumflexhookabove: "1EA8", - Acircumflexsmall: "F7E2", - Acircumflextilde: "1EAA", - Acute: "F6C9", - Acutesmall: "F7B4", - Acyrillic: "0410", - Adblgrave: "0200", - Adieresis: "00C4", - Adieresiscyrillic: "04D2", - Adieresismacron: "01DE", - Adieresissmall: "F7E4", - Adotbelow: "1EA0", - Adotmacron: "01E0", - Agrave: "00C0", - Agravesmall: "F7E0", - Ahookabove: "1EA2", - Aiecyrillic: "04D4", - Ainvertedbreve: "0202", - Alpha: "0391", - Alphatonos: "0386", - Amacron: "0100", - Amonospace: "FF21", - Aogonek: "0104", - Aring: "00C5", - Aringacute: "01FA", - Aringbelow: "1E00", - Aringsmall: "F7E5", - Asmall: "F761", - Atilde: "00C3", - Atildesmall: "F7E3", - Aybarmenian: "0531", - B: "0042", - Bcircle: "24B7", - Bdotaccent: "1E02", - Bdotbelow: "1E04", - Becyrillic: "0411", - Benarmenian: "0532", - Beta: "0392", - Bhook: "0181", - Blinebelow: "1E06", - Bmonospace: "FF22", - Brevesmall: "F6F4", - Bsmall: "F762", - Btopbar: "0182", - C: "0043", - Caarmenian: "053E", - Cacute: "0106", - Caron: "F6CA", - Caronsmall: "F6F5", - Ccaron: "010C", - Ccedilla: "00C7", - Ccedillaacute: "1E08", - Ccedillasmall: "F7E7", - Ccircle: "24B8", - Ccircumflex: "0108", - Cdot: "010A", - Cdotaccent: "010A", - Cedillasmall: "F7B8", - Chaarmenian: "0549", - Cheabkhasiancyrillic: "04BC", - Checyrillic: "0427", - Chedescenderabkhasiancyrillic: "04BE", - Chedescendercyrillic: "04B6", - Chedieresiscyrillic: "04F4", - Cheharmenian: "0543", - Chekhakassiancyrillic: "04CB", - Cheverticalstrokecyrillic: "04B8", - Chi: "03A7", - Chook: "0187", - Circumflexsmall: "F6F6", - Cmonospace: "FF23", - Coarmenian: "0551", - Csmall: "F763", - D: "0044", - DZ: "01F1", - DZcaron: "01C4", - Daarmenian: "0534", - Dafrican: "0189", - Dcaron: "010E", - Dcedilla: "1E10", - Dcircle: "24B9", - Dcircumflexbelow: "1E12", - Dcroat: "0110", - Ddotaccent: "1E0A", - Ddotbelow: "1E0C", - Decyrillic: "0414", - Deicoptic: "03EE", - Delta: "2206", - Deltagreek: "0394", - Dhook: "018A", - Dieresis: "F6CB", - DieresisAcute: "F6CC", - DieresisGrave: "F6CD", - Dieresissmall: "F7A8", - Digammagreek: "03DC", - Djecyrillic: "0402", - Dlinebelow: "1E0E", - Dmonospace: "FF24", - Dotaccentsmall: "F6F7", - Dslash: "0110", - Dsmall: "F764", - Dtopbar: "018B", - Dz: "01F2", - Dzcaron: "01C5", - Dzeabkhasiancyrillic: "04E0", - Dzecyrillic: "0405", - Dzhecyrillic: "040F", - E: "0045", - Eacute: "00C9", - Eacutesmall: "F7E9", - Ebreve: "0114", - Ecaron: "011A", - Ecedillabreve: "1E1C", - Echarmenian: "0535", - Ecircle: "24BA", - Ecircumflex: "00CA", - Ecircumflexacute: "1EBE", - Ecircumflexbelow: "1E18", - Ecircumflexdotbelow: "1EC6", - Ecircumflexgrave: "1EC0", - Ecircumflexhookabove: "1EC2", - Ecircumflexsmall: "F7EA", - Ecircumflextilde: "1EC4", - Ecyrillic: "0404", - Edblgrave: "0204", - Edieresis: "00CB", - Edieresissmall: "F7EB", - Edot: "0116", - Edotaccent: "0116", - Edotbelow: "1EB8", - Efcyrillic: "0424", - Egrave: "00C8", - Egravesmall: "F7E8", - Eharmenian: "0537", - Ehookabove: "1EBA", - Eightroman: "2167", - Einvertedbreve: "0206", - Eiotifiedcyrillic: "0464", - Elcyrillic: "041B", - Elevenroman: "216A", - Emacron: "0112", - Emacronacute: "1E16", - Emacrongrave: "1E14", - Emcyrillic: "041C", - Emonospace: "FF25", - Encyrillic: "041D", - Endescendercyrillic: "04A2", - Eng: "014A", - Enghecyrillic: "04A4", - Enhookcyrillic: "04C7", - Eogonek: "0118", - Eopen: "0190", - Epsilon: "0395", - Epsilontonos: "0388", - Ercyrillic: "0420", - Ereversed: "018E", - Ereversedcyrillic: "042D", - Escyrillic: "0421", - Esdescendercyrillic: "04AA", - Esh: "01A9", - Esmall: "F765", - Eta: "0397", - Etarmenian: "0538", - Etatonos: "0389", - Eth: "00D0", - Ethsmall: "F7F0", - Etilde: "1EBC", - Etildebelow: "1E1A", - Euro: "20AC", - Ezh: "01B7", - Ezhcaron: "01EE", - Ezhreversed: "01B8", - F: "0046", - Fcircle: "24BB", - Fdotaccent: "1E1E", - Feharmenian: "0556", - Feicoptic: "03E4", - Fhook: "0191", - Fitacyrillic: "0472", - Fiveroman: "2164", - Fmonospace: "FF26", - Fourroman: "2163", - Fsmall: "F766", - G: "0047", - GBsquare: "3387", - Gacute: "01F4", - Gamma: "0393", - Gammaafrican: "0194", - Gangiacoptic: "03EA", - Gbreve: "011E", - Gcaron: "01E6", - Gcedilla: "0122", - Gcircle: "24BC", - Gcircumflex: "011C", - Gcommaaccent: "0122", - Gdot: "0120", - Gdotaccent: "0120", - Gecyrillic: "0413", - Ghadarmenian: "0542", - Ghemiddlehookcyrillic: "0494", - Ghestrokecyrillic: "0492", - Gheupturncyrillic: "0490", - Ghook: "0193", - Gimarmenian: "0533", - Gjecyrillic: "0403", - Gmacron: "1E20", - Gmonospace: "FF27", - Grave: "F6CE", - Gravesmall: "F760", - Gsmall: "F767", - Gsmallhook: "029B", - Gstroke: "01E4", - H: "0048", - H18533: "25CF", - H18543: "25AA", - H18551: "25AB", - H22073: "25A1", - HPsquare: "33CB", - Haabkhasiancyrillic: "04A8", - Hadescendercyrillic: "04B2", - Hardsigncyrillic: "042A", - Hbar: "0126", - Hbrevebelow: "1E2A", - Hcedilla: "1E28", - Hcircle: "24BD", - Hcircumflex: "0124", - Hdieresis: "1E26", - Hdotaccent: "1E22", - Hdotbelow: "1E24", - Hmonospace: "FF28", - Hoarmenian: "0540", - Horicoptic: "03E8", - Hsmall: "F768", - Hungarumlaut: "F6CF", - Hungarumlautsmall: "F6F8", - Hzsquare: "3390", - I: "0049", - IAcyrillic: "042F", - IJ: "0132", - IUcyrillic: "042E", - Iacute: "00CD", - Iacutesmall: "F7ED", - Ibreve: "012C", - Icaron: "01CF", - Icircle: "24BE", - Icircumflex: "00CE", - Icircumflexsmall: "F7EE", - Icyrillic: "0406", - Idblgrave: "0208", - Idieresis: "00CF", - Idieresisacute: "1E2E", - Idieresiscyrillic: "04E4", - Idieresissmall: "F7EF", - Idot: "0130", - Idotaccent: "0130", - Idotbelow: "1ECA", - Iebrevecyrillic: "04D6", - Iecyrillic: "0415", - Ifraktur: "2111", - Igrave: "00CC", - Igravesmall: "F7EC", - Ihookabove: "1EC8", - Iicyrillic: "0418", - Iinvertedbreve: "020A", - Iishortcyrillic: "0419", - Imacron: "012A", - Imacroncyrillic: "04E2", - Imonospace: "FF29", - Iniarmenian: "053B", - Iocyrillic: "0401", - Iogonek: "012E", - Iota: "0399", - Iotaafrican: "0196", - Iotadieresis: "03AA", - Iotatonos: "038A", - Ismall: "F769", - Istroke: "0197", - Itilde: "0128", - Itildebelow: "1E2C", - Izhitsacyrillic: "0474", - Izhitsadblgravecyrillic: "0476", - J: "004A", - Jaarmenian: "0541", - Jcircle: "24BF", - Jcircumflex: "0134", - Jecyrillic: "0408", - Jheharmenian: "054B", - Jmonospace: "FF2A", - Jsmall: "F76A", - K: "004B", - KBsquare: "3385", - KKsquare: "33CD", - Kabashkircyrillic: "04A0", - Kacute: "1E30", - Kacyrillic: "041A", - Kadescendercyrillic: "049A", - Kahookcyrillic: "04C3", - Kappa: "039A", - Kastrokecyrillic: "049E", - Kaverticalstrokecyrillic: "049C", - Kcaron: "01E8", - Kcedilla: "0136", - Kcircle: "24C0", - Kcommaaccent: "0136", - Kdotbelow: "1E32", - Keharmenian: "0554", - Kenarmenian: "053F", - Khacyrillic: "0425", - Kheicoptic: "03E6", - Khook: "0198", - Kjecyrillic: "040C", - Klinebelow: "1E34", - Kmonospace: "FF2B", - Koppacyrillic: "0480", - Koppagreek: "03DE", - Ksicyrillic: "046E", - Ksmall: "F76B", - L: "004C", - LJ: "01C7", - LL: "F6BF", - Lacute: "0139", - Lambda: "039B", - Lcaron: "013D", - Lcedilla: "013B", - Lcircle: "24C1", - Lcircumflexbelow: "1E3C", - Lcommaaccent: "013B", - Ldot: "013F", - Ldotaccent: "013F", - Ldotbelow: "1E36", - Ldotbelowmacron: "1E38", - Liwnarmenian: "053C", - Lj: "01C8", - Ljecyrillic: "0409", - Llinebelow: "1E3A", - Lmonospace: "FF2C", - Lslash: "0141", - Lslashsmall: "F6F9", - Lsmall: "F76C", - M: "004D", - MBsquare: "3386", - Macron: "F6D0", - Macronsmall: "F7AF", - Macute: "1E3E", - Mcircle: "24C2", - Mdotaccent: "1E40", - Mdotbelow: "1E42", - Menarmenian: "0544", - Mmonospace: "FF2D", - Msmall: "F76D", - Mturned: "019C", - Mu: "039C", - N: "004E", - NJ: "01CA", - Nacute: "0143", - Ncaron: "0147", - Ncedilla: "0145", - Ncircle: "24C3", - Ncircumflexbelow: "1E4A", - Ncommaaccent: "0145", - Ndotaccent: "1E44", - Ndotbelow: "1E46", - Nhookleft: "019D", - Nineroman: "2168", - Nj: "01CB", - Njecyrillic: "040A", - Nlinebelow: "1E48", - Nmonospace: "FF2E", - Nowarmenian: "0546", - Nsmall: "F76E", - Ntilde: "00D1", - Ntildesmall: "F7F1", - Nu: "039D", - O: "004F", - OE: "0152", - OEsmall: "F6FA", - Oacute: "00D3", - Oacutesmall: "F7F3", - Obarredcyrillic: "04E8", - Obarreddieresiscyrillic: "04EA", - Obreve: "014E", - Ocaron: "01D1", - Ocenteredtilde: "019F", - Ocircle: "24C4", - Ocircumflex: "00D4", - Ocircumflexacute: "1ED0", - Ocircumflexdotbelow: "1ED8", - Ocircumflexgrave: "1ED2", - Ocircumflexhookabove: "1ED4", - Ocircumflexsmall: "F7F4", - Ocircumflextilde: "1ED6", - Ocyrillic: "041E", - Odblacute: "0150", - Odblgrave: "020C", - Odieresis: "00D6", - Odieresiscyrillic: "04E6", - Odieresissmall: "F7F6", - Odotbelow: "1ECC", - Ogoneksmall: "F6FB", - Ograve: "00D2", - Ogravesmall: "F7F2", - Oharmenian: "0555", - Ohm: "2126", - Ohookabove: "1ECE", - Ohorn: "01A0", - Ohornacute: "1EDA", - Ohorndotbelow: "1EE2", - Ohorngrave: "1EDC", - Ohornhookabove: "1EDE", - Ohorntilde: "1EE0", - Ohungarumlaut: "0150", - Oi: "01A2", - Oinvertedbreve: "020E", - Omacron: "014C", - Omacronacute: "1E52", - Omacrongrave: "1E50", - Omega: "2126", - Omegacyrillic: "0460", - Omegagreek: "03A9", - Omegaroundcyrillic: "047A", - Omegatitlocyrillic: "047C", - Omegatonos: "038F", - Omicron: "039F", - Omicrontonos: "038C", - Omonospace: "FF2F", - Oneroman: "2160", - Oogonek: "01EA", - Oogonekmacron: "01EC", - Oopen: "0186", - Oslash: "00D8", - Oslashacute: "01FE", - Oslashsmall: "F7F8", - Osmall: "F76F", - Ostrokeacute: "01FE", - Otcyrillic: "047E", - Otilde: "00D5", - Otildeacute: "1E4C", - Otildedieresis: "1E4E", - Otildesmall: "F7F5", - P: "0050", - Pacute: "1E54", - Pcircle: "24C5", - Pdotaccent: "1E56", - Pecyrillic: "041F", - Peharmenian: "054A", - Pemiddlehookcyrillic: "04A6", - Phi: "03A6", - Phook: "01A4", - Pi: "03A0", - Piwrarmenian: "0553", - Pmonospace: "FF30", - Psi: "03A8", - Psicyrillic: "0470", - Psmall: "F770", - Q: "0051", - Qcircle: "24C6", - Qmonospace: "FF31", - Qsmall: "F771", - R: "0052", - Raarmenian: "054C", - Racute: "0154", - Rcaron: "0158", - Rcedilla: "0156", - Rcircle: "24C7", - Rcommaaccent: "0156", - Rdblgrave: "0210", - Rdotaccent: "1E58", - Rdotbelow: "1E5A", - Rdotbelowmacron: "1E5C", - Reharmenian: "0550", - Rfraktur: "211C", - Rho: "03A1", - Ringsmall: "F6FC", - Rinvertedbreve: "0212", - Rlinebelow: "1E5E", - Rmonospace: "FF32", - Rsmall: "F772", - Rsmallinverted: "0281", - Rsmallinvertedsuperior: "02B6", - S: "0053", - SF010000: "250C", - SF020000: "2514", - SF030000: "2510", - SF040000: "2518", - SF050000: "253C", - SF060000: "252C", - SF070000: "2534", - SF080000: "251C", - SF090000: "2524", - SF100000: "2500", - SF110000: "2502", - SF190000: "2561", - SF200000: "2562", - SF210000: "2556", - SF220000: "2555", - SF230000: "2563", - SF240000: "2551", - SF250000: "2557", - SF260000: "255D", - SF270000: "255C", - SF280000: "255B", - SF360000: "255E", - SF370000: "255F", - SF380000: "255A", - SF390000: "2554", - SF400000: "2569", - SF410000: "2566", - SF420000: "2560", - SF430000: "2550", - SF440000: "256C", - SF450000: "2567", - SF460000: "2568", - SF470000: "2564", - SF480000: "2565", - SF490000: "2559", - SF500000: "2558", - SF510000: "2552", - SF520000: "2553", - SF530000: "256B", - SF540000: "256A", - Sacute: "015A", - Sacutedotaccent: "1E64", - Sampigreek: "03E0", - Scaron: "0160", - Scarondotaccent: "1E66", - Scaronsmall: "F6FD", - Scedilla: "015E", - Schwa: "018F", - Schwacyrillic: "04D8", - Schwadieresiscyrillic: "04DA", - Scircle: "24C8", - Scircumflex: "015C", - Scommaaccent: "0218", - Sdotaccent: "1E60", - Sdotbelow: "1E62", - Sdotbelowdotaccent: "1E68", - Seharmenian: "054D", - Sevenroman: "2166", - Shaarmenian: "0547", - Shacyrillic: "0428", - Shchacyrillic: "0429", - Sheicoptic: "03E2", - Shhacyrillic: "04BA", - Shimacoptic: "03EC", - Sigma: "03A3", - Sixroman: "2165", - Smonospace: "FF33", - Softsigncyrillic: "042C", - Ssmall: "F773", - Stigmagreek: "03DA", - T: "0054", - Tau: "03A4", - Tbar: "0166", - Tcaron: "0164", - Tcedilla: "0162", - Tcircle: "24C9", - Tcircumflexbelow: "1E70", - Tcommaaccent: "0162", - Tdotaccent: "1E6A", - Tdotbelow: "1E6C", - Tecyrillic: "0422", - Tedescendercyrillic: "04AC", - Tenroman: "2169", - Tetsecyrillic: "04B4", - Theta: "0398", - Thook: "01AC", - Thorn: "00DE", - Thornsmall: "F7FE", - Threeroman: "2162", - Tildesmall: "F6FE", - Tiwnarmenian: "054F", - Tlinebelow: "1E6E", - Tmonospace: "FF34", - Toarmenian: "0539", - Tonefive: "01BC", - Tonesix: "0184", - Tonetwo: "01A7", - Tretroflexhook: "01AE", - Tsecyrillic: "0426", - Tshecyrillic: "040B", - Tsmall: "F774", - Twelveroman: "216B", - Tworoman: "2161", - U: "0055", - Uacute: "00DA", - Uacutesmall: "F7FA", - Ubreve: "016C", - Ucaron: "01D3", - Ucircle: "24CA", - Ucircumflex: "00DB", - Ucircumflexbelow: "1E76", - Ucircumflexsmall: "F7FB", - Ucyrillic: "0423", - Udblacute: "0170", - Udblgrave: "0214", - Udieresis: "00DC", - Udieresisacute: "01D7", - Udieresisbelow: "1E72", - Udieresiscaron: "01D9", - Udieresiscyrillic: "04F0", - Udieresisgrave: "01DB", - Udieresismacron: "01D5", - Udieresissmall: "F7FC", - Udotbelow: "1EE4", - Ugrave: "00D9", - Ugravesmall: "F7F9", - Uhookabove: "1EE6", - Uhorn: "01AF", - Uhornacute: "1EE8", - Uhorndotbelow: "1EF0", - Uhorngrave: "1EEA", - Uhornhookabove: "1EEC", - Uhorntilde: "1EEE", - Uhungarumlaut: "0170", - Uhungarumlautcyrillic: "04F2", - Uinvertedbreve: "0216", - Ukcyrillic: "0478", - Umacron: "016A", - Umacroncyrillic: "04EE", - Umacrondieresis: "1E7A", - Umonospace: "FF35", - Uogonek: "0172", - Upsilon: "03A5", - Upsilon1: "03D2", - Upsilonacutehooksymbolgreek: "03D3", - Upsilonafrican: "01B1", - Upsilondieresis: "03AB", - Upsilondieresishooksymbolgreek: "03D4", - Upsilonhooksymbol: "03D2", - Upsilontonos: "038E", - Uring: "016E", - Ushortcyrillic: "040E", - Usmall: "F775", - Ustraightcyrillic: "04AE", - Ustraightstrokecyrillic: "04B0", - Utilde: "0168", - Utildeacute: "1E78", - Utildebelow: "1E74", - V: "0056", - Vcircle: "24CB", - Vdotbelow: "1E7E", - Vecyrillic: "0412", - Vewarmenian: "054E", - Vhook: "01B2", - Vmonospace: "FF36", - Voarmenian: "0548", - Vsmall: "F776", - Vtilde: "1E7C", - W: "0057", - Wacute: "1E82", - Wcircle: "24CC", - Wcircumflex: "0174", - Wdieresis: "1E84", - Wdotaccent: "1E86", - Wdotbelow: "1E88", - Wgrave: "1E80", - Wmonospace: "FF37", - Wsmall: "F777", - X: "0058", - Xcircle: "24CD", - Xdieresis: "1E8C", - Xdotaccent: "1E8A", - Xeharmenian: "053D", - Xi: "039E", - Xmonospace: "FF38", - Xsmall: "F778", - Y: "0059", - Yacute: "00DD", - Yacutesmall: "F7FD", - Yatcyrillic: "0462", - Ycircle: "24CE", - Ycircumflex: "0176", - Ydieresis: "0178", - Ydieresissmall: "F7FF", - Ydotaccent: "1E8E", - Ydotbelow: "1EF4", - Yericyrillic: "042B", - Yerudieresiscyrillic: "04F8", - Ygrave: "1EF2", - Yhook: "01B3", - Yhookabove: "1EF6", - Yiarmenian: "0545", - Yicyrillic: "0407", - Yiwnarmenian: "0552", - Ymonospace: "FF39", - Ysmall: "F779", - Ytilde: "1EF8", - Yusbigcyrillic: "046A", - Yusbigiotifiedcyrillic: "046C", - Yuslittlecyrillic: "0466", - Yuslittleiotifiedcyrillic: "0468", - Z: "005A", - Zaarmenian: "0536", - Zacute: "0179", - Zcaron: "017D", - Zcaronsmall: "F6FF", - Zcircle: "24CF", - Zcircumflex: "1E90", - Zdot: "017B", - Zdotaccent: "017B", - Zdotbelow: "1E92", - Zecyrillic: "0417", - Zedescendercyrillic: "0498", - Zedieresiscyrillic: "04DE", - Zeta: "0396", - Zhearmenian: "053A", - Zhebrevecyrillic: "04C1", - Zhecyrillic: "0416", - Zhedescendercyrillic: "0496", - Zhedieresiscyrillic: "04DC", - Zlinebelow: "1E94", - Zmonospace: "FF3A", - Zsmall: "F77A", - Zstroke: "01B5", - a: "0061", - aabengali: "0986", - aacute: "00E1", - aadeva: "0906", - aagujarati: "0A86", - aagurmukhi: "0A06", - aamatragurmukhi: "0A3E", - aarusquare: "3303", - aavowelsignbengali: "09BE", - aavowelsigndeva: "093E", - aavowelsigngujarati: "0ABE", - abbreviationmarkarmenian: "055F", - abbreviationsigndeva: "0970", - abengali: "0985", - abopomofo: "311A", - abreve: "0103", - abreveacute: "1EAF", - abrevecyrillic: "04D1", - abrevedotbelow: "1EB7", - abrevegrave: "1EB1", - abrevehookabove: "1EB3", - abrevetilde: "1EB5", - acaron: "01CE", - acircle: "24D0", - acircumflex: "00E2", - acircumflexacute: "1EA5", - acircumflexdotbelow: "1EAD", - acircumflexgrave: "1EA7", - acircumflexhookabove: "1EA9", - acircumflextilde: "1EAB", - acute: "00B4", - acutebelowcmb: "0317", - acutecmb: "0301", - acutecomb: "0301", - acutedeva: "0954", - acutelowmod: "02CF", - acutetonecmb: "0341", - acyrillic: "0430", - adblgrave: "0201", - addakgurmukhi: "0A71", - adeva: "0905", - adieresis: "00E4", - adieresiscyrillic: "04D3", - adieresismacron: "01DF", - adotbelow: "1EA1", - adotmacron: "01E1", - ae: "00E6", - aeacute: "01FD", - aekorean: "3150", - aemacron: "01E3", - afii00208: "2015", - afii08941: "20A4", - afii10017: "0410", - afii10018: "0411", - afii10019: "0412", - afii10020: "0413", - afii10021: "0414", - afii10022: "0415", - afii10023: "0401", - afii10024: "0416", - afii10025: "0417", - afii10026: "0418", - afii10027: "0419", - afii10028: "041A", - afii10029: "041B", - afii10030: "041C", - afii10031: "041D", - afii10032: "041E", - afii10033: "041F", - afii10034: "0420", - afii10035: "0421", - afii10036: "0422", - afii10037: "0423", - afii10038: "0424", - afii10039: "0425", - afii10040: "0426", - afii10041: "0427", - afii10042: "0428", - afii10043: "0429", - afii10044: "042A", - afii10045: "042B", - afii10046: "042C", - afii10047: "042D", - afii10048: "042E", - afii10049: "042F", - afii10050: "0490", - afii10051: "0402", - afii10052: "0403", - afii10053: "0404", - afii10054: "0405", - afii10055: "0406", - afii10056: "0407", - afii10057: "0408", - afii10058: "0409", - afii10059: "040A", - afii10060: "040B", - afii10061: "040C", - afii10062: "040E", - afii10063: "F6C4", - afii10064: "F6C5", - afii10065: "0430", - afii10066: "0431", - afii10067: "0432", - afii10068: "0433", - afii10069: "0434", - afii10070: "0435", - afii10071: "0451", - afii10072: "0436", - afii10073: "0437", - afii10074: "0438", - afii10075: "0439", - afii10076: "043A", - afii10077: "043B", - afii10078: "043C", - afii10079: "043D", - afii10080: "043E", - afii10081: "043F", - afii10082: "0440", - afii10083: "0441", - afii10084: "0442", - afii10085: "0443", - afii10086: "0444", - afii10087: "0445", - afii10088: "0446", - afii10089: "0447", - afii10090: "0448", - afii10091: "0449", - afii10092: "044A", - afii10093: "044B", - afii10094: "044C", - afii10095: "044D", - afii10096: "044E", - afii10097: "044F", - afii10098: "0491", - afii10099: "0452", - afii10100: "0453", - afii10101: "0454", - afii10102: "0455", - afii10103: "0456", - afii10104: "0457", - afii10105: "0458", - afii10106: "0459", - afii10107: "045A", - afii10108: "045B", - afii10109: "045C", - afii10110: "045E", - afii10145: "040F", - afii10146: "0462", - afii10147: "0472", - afii10148: "0474", - afii10192: "F6C6", - afii10193: "045F", - afii10194: "0463", - afii10195: "0473", - afii10196: "0475", - afii10831: "F6C7", - afii10832: "F6C8", - afii10846: "04D9", - afii299: "200E", - afii300: "200F", - afii301: "200D", - afii57381: "066A", - afii57388: "060C", - afii57392: "0660", - afii57393: "0661", - afii57394: "0662", - afii57395: "0663", - afii57396: "0664", - afii57397: "0665", - afii57398: "0666", - afii57399: "0667", - afii57400: "0668", - afii57401: "0669", - afii57403: "061B", - afii57407: "061F", - afii57409: "0621", - afii57410: "0622", - afii57411: "0623", - afii57412: "0624", - afii57413: "0625", - afii57414: "0626", - afii57415: "0627", - afii57416: "0628", - afii57417: "0629", - afii57418: "062A", - afii57419: "062B", - afii57420: "062C", - afii57421: "062D", - afii57422: "062E", - afii57423: "062F", - afii57424: "0630", - afii57425: "0631", - afii57426: "0632", - afii57427: "0633", - afii57428: "0634", - afii57429: "0635", - afii57430: "0636", - afii57431: "0637", - afii57432: "0638", - afii57433: "0639", - afii57434: "063A", - afii57440: "0640", - afii57441: "0641", - afii57442: "0642", - afii57443: "0643", - afii57444: "0644", - afii57445: "0645", - afii57446: "0646", - afii57448: "0648", - afii57449: "0649", - afii57450: "064A", - afii57451: "064B", - afii57452: "064C", - afii57453: "064D", - afii57454: "064E", - afii57455: "064F", - afii57456: "0650", - afii57457: "0651", - afii57458: "0652", - afii57470: "0647", - afii57505: "06A4", - afii57506: "067E", - afii57507: "0686", - afii57508: "0698", - afii57509: "06AF", - afii57511: "0679", - afii57512: "0688", - afii57513: "0691", - afii57514: "06BA", - afii57519: "06D2", - afii57534: "06D5", - afii57636: "20AA", - afii57645: "05BE", - afii57658: "05C3", - afii57664: "05D0", - afii57665: "05D1", - afii57666: "05D2", - afii57667: "05D3", - afii57668: "05D4", - afii57669: "05D5", - afii57670: "05D6", - afii57671: "05D7", - afii57672: "05D8", - afii57673: "05D9", - afii57674: "05DA", - afii57675: "05DB", - afii57676: "05DC", - afii57677: "05DD", - afii57678: "05DE", - afii57679: "05DF", - afii57680: "05E0", - afii57681: "05E1", - afii57682: "05E2", - afii57683: "05E3", - afii57684: "05E4", - afii57685: "05E5", - afii57686: "05E6", - afii57687: "05E7", - afii57688: "05E8", - afii57689: "05E9", - afii57690: "05EA", - afii57694: "FB2A", - afii57695: "FB2B", - afii57700: "FB4B", - afii57705: "FB1F", - afii57716: "05F0", - afii57717: "05F1", - afii57718: "05F2", - afii57723: "FB35", - afii57793: "05B4", - afii57794: "05B5", - afii57795: "05B6", - afii57796: "05BB", - afii57797: "05B8", - afii57798: "05B7", - afii57799: "05B0", - afii57800: "05B2", - afii57801: "05B1", - afii57802: "05B3", - afii57803: "05C2", - afii57804: "05C1", - afii57806: "05B9", - afii57807: "05BC", - afii57839: "05BD", - afii57841: "05BF", - afii57842: "05C0", - afii57929: "02BC", - afii61248: "2105", - afii61289: "2113", - afii61352: "2116", - afii61573: "202C", - afii61574: "202D", - afii61575: "202E", - afii61664: "200C", - afii63167: "066D", - afii64937: "02BD", - agrave: "00E0", - agujarati: "0A85", - agurmukhi: "0A05", - ahiragana: "3042", - ahookabove: "1EA3", - aibengali: "0990", - aibopomofo: "311E", - aideva: "0910", - aiecyrillic: "04D5", - aigujarati: "0A90", - aigurmukhi: "0A10", - aimatragurmukhi: "0A48", - ainarabic: "0639", - ainfinalarabic: "FECA", - aininitialarabic: "FECB", - ainmedialarabic: "FECC", - ainvertedbreve: "0203", - aivowelsignbengali: "09C8", - aivowelsigndeva: "0948", - aivowelsigngujarati: "0AC8", - akatakana: "30A2", - akatakanahalfwidth: "FF71", - akorean: "314F", - alef: "05D0", - alefarabic: "0627", - alefdageshhebrew: "FB30", - aleffinalarabic: "FE8E", - alefhamzaabovearabic: "0623", - alefhamzaabovefinalarabic: "FE84", - alefhamzabelowarabic: "0625", - alefhamzabelowfinalarabic: "FE88", - alefhebrew: "05D0", - aleflamedhebrew: "FB4F", - alefmaddaabovearabic: "0622", - alefmaddaabovefinalarabic: "FE82", - alefmaksuraarabic: "0649", - alefmaksurafinalarabic: "FEF0", - alefmaksurainitialarabic: "FEF3", - alefmaksuramedialarabic: "FEF4", - alefpatahhebrew: "FB2E", - alefqamatshebrew: "FB2F", - aleph: "2135", - allequal: "224C", - alpha: "03B1", - alphatonos: "03AC", - amacron: "0101", - amonospace: "FF41", - ampersand: "0026", - ampersandmonospace: "FF06", - ampersandsmall: "F726", - amsquare: "33C2", - anbopomofo: "3122", - angbopomofo: "3124", - angkhankhuthai: "0E5A", - angle: "2220", - anglebracketleft: "3008", - anglebracketleftvertical: "FE3F", - anglebracketright: "3009", - anglebracketrightvertical: "FE40", - angleleft: "2329", - angleright: "232A", - angstrom: "212B", - anoteleia: "0387", - anudattadeva: "0952", - anusvarabengali: "0982", - anusvaradeva: "0902", - anusvaragujarati: "0A82", - aogonek: "0105", - apaatosquare: "3300", - aparen: "249C", - apostrophearmenian: "055A", - apostrophemod: "02BC", - apple: "F8FF", - approaches: "2250", - approxequal: "2248", - approxequalorimage: "2252", - approximatelyequal: "2245", - araeaekorean: "318E", - araeakorean: "318D", - arc: "2312", - arighthalfring: "1E9A", - aring: "00E5", - aringacute: "01FB", - aringbelow: "1E01", - arrowboth: "2194", - arrowdashdown: "21E3", - arrowdashleft: "21E0", - arrowdashright: "21E2", - arrowdashup: "21E1", - arrowdblboth: "21D4", - arrowdbldown: "21D3", - arrowdblleft: "21D0", - arrowdblright: "21D2", - arrowdblup: "21D1", - arrowdown: "2193", - arrowdownleft: "2199", - arrowdownright: "2198", - arrowdownwhite: "21E9", - arrowheaddownmod: "02C5", - arrowheadleftmod: "02C2", - arrowheadrightmod: "02C3", - arrowheadupmod: "02C4", - arrowhorizex: "F8E7", - arrowleft: "2190", - arrowleftdbl: "21D0", - arrowleftdblstroke: "21CD", - arrowleftoverright: "21C6", - arrowleftwhite: "21E6", - arrowright: "2192", - arrowrightdblstroke: "21CF", - arrowrightheavy: "279E", - arrowrightoverleft: "21C4", - arrowrightwhite: "21E8", - arrowtableft: "21E4", - arrowtabright: "21E5", - arrowup: "2191", - arrowupdn: "2195", - arrowupdnbse: "21A8", - arrowupdownbase: "21A8", - arrowupleft: "2196", - arrowupleftofdown: "21C5", - arrowupright: "2197", - arrowupwhite: "21E7", - arrowvertex: "F8E6", - asciicircum: "005E", - asciicircummonospace: "FF3E", - asciitilde: "007E", - asciitildemonospace: "FF5E", - ascript: "0251", - ascriptturned: "0252", - asmallhiragana: "3041", - asmallkatakana: "30A1", - asmallkatakanahalfwidth: "FF67", - asterisk: "002A", - asteriskaltonearabic: "066D", - asteriskarabic: "066D", - asteriskmath: "2217", - asteriskmonospace: "FF0A", - asterisksmall: "FE61", - asterism: "2042", - asuperior: "F6E9", - asymptoticallyequal: "2243", - at: "0040", - atilde: "00E3", - atmonospace: "FF20", - atsmall: "FE6B", - aturned: "0250", - aubengali: "0994", - aubopomofo: "3120", - audeva: "0914", - augujarati: "0A94", - augurmukhi: "0A14", - aulengthmarkbengali: "09D7", - aumatragurmukhi: "0A4C", - auvowelsignbengali: "09CC", - auvowelsigndeva: "094C", - auvowelsigngujarati: "0ACC", - avagrahadeva: "093D", - aybarmenian: "0561", - ayin: "05E2", - ayinaltonehebrew: "FB20", - ayinhebrew: "05E2", - b: "0062", - babengali: "09AC", - backslash: "005C", - backslashmonospace: "FF3C", - badeva: "092C", - bagujarati: "0AAC", - bagurmukhi: "0A2C", - bahiragana: "3070", - bahtthai: "0E3F", - bakatakana: "30D0", - bar: "007C", - barmonospace: "FF5C", - bbopomofo: "3105", - bcircle: "24D1", - bdotaccent: "1E03", - bdotbelow: "1E05", - beamedsixteenthnotes: "266C", - because: "2235", - becyrillic: "0431", - beharabic: "0628", - behfinalarabic: "FE90", - behinitialarabic: "FE91", - behiragana: "3079", - behmedialarabic: "FE92", - behmeeminitialarabic: "FC9F", - behmeemisolatedarabic: "FC08", - behnoonfinalarabic: "FC6D", - bekatakana: "30D9", - benarmenian: "0562", - bet: "05D1", - beta: "03B2", - betasymbolgreek: "03D0", - betdagesh: "FB31", - betdageshhebrew: "FB31", - bethebrew: "05D1", - betrafehebrew: "FB4C", - bhabengali: "09AD", - bhadeva: "092D", - bhagujarati: "0AAD", - bhagurmukhi: "0A2D", - bhook: "0253", - bihiragana: "3073", - bikatakana: "30D3", - bilabialclick: "0298", - bindigurmukhi: "0A02", - birusquare: "3331", - blackcircle: "25CF", - blackdiamond: "25C6", - blackdownpointingtriangle: "25BC", - blackleftpointingpointer: "25C4", - blackleftpointingtriangle: "25C0", - blacklenticularbracketleft: "3010", - blacklenticularbracketleftvertical: "FE3B", - blacklenticularbracketright: "3011", - blacklenticularbracketrightvertical: "FE3C", - blacklowerlefttriangle: "25E3", - blacklowerrighttriangle: "25E2", - blackrectangle: "25AC", - blackrightpointingpointer: "25BA", - blackrightpointingtriangle: "25B6", - blacksmallsquare: "25AA", - blacksmilingface: "263B", - blacksquare: "25A0", - blackstar: "2605", - blackupperlefttriangle: "25E4", - blackupperrighttriangle: "25E5", - blackuppointingsmalltriangle: "25B4", - blackuppointingtriangle: "25B2", - blank: "2423", - blinebelow: "1E07", - block: "2588", - bmonospace: "FF42", - bobaimaithai: "0E1A", - bohiragana: "307C", - bokatakana: "30DC", - bparen: "249D", - bqsquare: "33C3", - braceex: "F8F4", - braceleft: "007B", - braceleftbt: "F8F3", - braceleftmid: "F8F2", - braceleftmonospace: "FF5B", - braceleftsmall: "FE5B", - bracelefttp: "F8F1", - braceleftvertical: "FE37", - braceright: "007D", - bracerightbt: "F8FE", - bracerightmid: "F8FD", - bracerightmonospace: "FF5D", - bracerightsmall: "FE5C", - bracerighttp: "F8FC", - bracerightvertical: "FE38", - bracketleft: "005B", - bracketleftbt: "F8F0", - bracketleftex: "F8EF", - bracketleftmonospace: "FF3B", - bracketlefttp: "F8EE", - bracketright: "005D", - bracketrightbt: "F8FB", - bracketrightex: "F8FA", - bracketrightmonospace: "FF3D", - bracketrighttp: "F8F9", - breve: "02D8", - brevebelowcmb: "032E", - brevecmb: "0306", - breveinvertedbelowcmb: "032F", - breveinvertedcmb: "0311", - breveinverteddoublecmb: "0361", - bridgebelowcmb: "032A", - bridgeinvertedbelowcmb: "033A", - brokenbar: "00A6", - bstroke: "0180", - bsuperior: "F6EA", - btopbar: "0183", - buhiragana: "3076", - bukatakana: "30D6", - bullet: "2022", - bulletinverse: "25D8", - bulletoperator: "2219", - bullseye: "25CE", - c: "0063", - caarmenian: "056E", - cabengali: "099A", - cacute: "0107", - cadeva: "091A", - cagujarati: "0A9A", - cagurmukhi: "0A1A", - calsquare: "3388", - candrabindubengali: "0981", - candrabinducmb: "0310", - candrabindudeva: "0901", - candrabindugujarati: "0A81", - capslock: "21EA", - careof: "2105", - caron: "02C7", - caronbelowcmb: "032C", - caroncmb: "030C", - carriagereturn: "21B5", - cbopomofo: "3118", - ccaron: "010D", - ccedilla: "00E7", - ccedillaacute: "1E09", - ccircle: "24D2", - ccircumflex: "0109", - ccurl: "0255", - cdot: "010B", - cdotaccent: "010B", - cdsquare: "33C5", - cedilla: "00B8", - cedillacmb: "0327", - cent: "00A2", - centigrade: "2103", - centinferior: "F6DF", - centmonospace: "FFE0", - centoldstyle: "F7A2", - centsuperior: "F6E0", - chaarmenian: "0579", - chabengali: "099B", - chadeva: "091B", - chagujarati: "0A9B", - chagurmukhi: "0A1B", - chbopomofo: "3114", - cheabkhasiancyrillic: "04BD", - checkmark: "2713", - checyrillic: "0447", - chedescenderabkhasiancyrillic: "04BF", - chedescendercyrillic: "04B7", - chedieresiscyrillic: "04F5", - cheharmenian: "0573", - chekhakassiancyrillic: "04CC", - cheverticalstrokecyrillic: "04B9", - chi: "03C7", - chieuchacirclekorean: "3277", - chieuchaparenkorean: "3217", - chieuchcirclekorean: "3269", - chieuchkorean: "314A", - chieuchparenkorean: "3209", - chochangthai: "0E0A", - chochanthai: "0E08", - chochingthai: "0E09", - chochoethai: "0E0C", - chook: "0188", - cieucacirclekorean: "3276", - cieucaparenkorean: "3216", - cieuccirclekorean: "3268", - cieuckorean: "3148", - cieucparenkorean: "3208", - cieucuparenkorean: "321C", - circle: "25CB", - circlemultiply: "2297", - circleot: "2299", - circleplus: "2295", - circlepostalmark: "3036", - circlewithlefthalfblack: "25D0", - circlewithrighthalfblack: "25D1", - circumflex: "02C6", - circumflexbelowcmb: "032D", - circumflexcmb: "0302", - clear: "2327", - clickalveolar: "01C2", - clickdental: "01C0", - clicklateral: "01C1", - clickretroflex: "01C3", - club: "2663", - clubsuitblack: "2663", - clubsuitwhite: "2667", - cmcubedsquare: "33A4", - cmonospace: "FF43", - cmsquaredsquare: "33A0", - coarmenian: "0581", - colon: "003A", - colonmonetary: "20A1", - colonmonospace: "FF1A", - colonsign: "20A1", - colonsmall: "FE55", - colontriangularhalfmod: "02D1", - colontriangularmod: "02D0", - comma: "002C", - commaabovecmb: "0313", - commaaboverightcmb: "0315", - commaaccent: "F6C3", - commaarabic: "060C", - commaarmenian: "055D", - commainferior: "F6E1", - commamonospace: "FF0C", - commareversedabovecmb: "0314", - commareversedmod: "02BD", - commasmall: "FE50", - commasuperior: "F6E2", - commaturnedabovecmb: "0312", - commaturnedmod: "02BB", - compass: "263C", - congruent: "2245", - contourintegral: "222E", - control: "2303", - controlACK: "0006", - controlBEL: "0007", - controlBS: "0008", - controlCAN: "0018", - controlCR: "000D", - controlDC1: "0011", - controlDC2: "0012", - controlDC3: "0013", - controlDC4: "0014", - controlDEL: "007F", - controlDLE: "0010", - controlEM: "0019", - controlENQ: "0005", - controlEOT: "0004", - controlESC: "001B", - controlETB: "0017", - controlETX: "0003", - controlFF: "000C", - controlFS: "001C", - controlGS: "001D", - controlHT: "0009", - controlLF: "000A", - controlNAK: "0015", - controlRS: "001E", - controlSI: "000F", - controlSO: "000E", - controlSOT: "0002", - controlSTX: "0001", - controlSUB: "001A", - controlSYN: "0016", - controlUS: "001F", - controlVT: "000B", - copyright: "00A9", - copyrightsans: "F8E9", - copyrightserif: "F6D9", - cornerbracketleft: "300C", - cornerbracketlefthalfwidth: "FF62", - cornerbracketleftvertical: "FE41", - cornerbracketright: "300D", - cornerbracketrighthalfwidth: "FF63", - cornerbracketrightvertical: "FE42", - corporationsquare: "337F", - cosquare: "33C7", - coverkgsquare: "33C6", - cparen: "249E", - cruzeiro: "20A2", - cstretched: "0297", - curlyand: "22CF", - curlyor: "22CE", - currency: "00A4", - cyrBreve: "F6D1", - cyrFlex: "F6D2", - cyrbreve: "F6D4", - cyrflex: "F6D5", - d: "0064", - daarmenian: "0564", - dabengali: "09A6", - dadarabic: "0636", - dadeva: "0926", - dadfinalarabic: "FEBE", - dadinitialarabic: "FEBF", - dadmedialarabic: "FEC0", - dagesh: "05BC", - dageshhebrew: "05BC", - dagger: "2020", - daggerdbl: "2021", - dagujarati: "0AA6", - dagurmukhi: "0A26", - dahiragana: "3060", - dakatakana: "30C0", - dalarabic: "062F", - dalet: "05D3", - daletdagesh: "FB33", - daletdageshhebrew: "FB33", + A: 0x0041, + AE: 0x00C6, + AEacute: 0x01FC, + AEmacron: 0x01E2, + AEsmall: 0xF7E6, + Aacute: 0x00C1, + Aacutesmall: 0xF7E1, + Abreve: 0x0102, + Abreveacute: 0x1EAE, + Abrevecyrillic: 0x04D0, + Abrevedotbelow: 0x1EB6, + Abrevegrave: 0x1EB0, + Abrevehookabove: 0x1EB2, + Abrevetilde: 0x1EB4, + Acaron: 0x01CD, + Acircle: 0x24B6, + Acircumflex: 0x00C2, + Acircumflexacute: 0x1EA4, + Acircumflexdotbelow: 0x1EAC, + Acircumflexgrave: 0x1EA6, + Acircumflexhookabove: 0x1EA8, + Acircumflexsmall: 0xF7E2, + Acircumflextilde: 0x1EAA, + Acute: 0xF6C9, + Acutesmall: 0xF7B4, + Acyrillic: 0x0410, + Adblgrave: 0x0200, + Adieresis: 0x00C4, + Adieresiscyrillic: 0x04D2, + Adieresismacron: 0x01DE, + Adieresissmall: 0xF7E4, + Adotbelow: 0x1EA0, + Adotmacron: 0x01E0, + Agrave: 0x00C0, + Agravesmall: 0xF7E0, + Ahookabove: 0x1EA2, + Aiecyrillic: 0x04D4, + Ainvertedbreve: 0x0202, + Alpha: 0x0391, + Alphatonos: 0x0386, + Amacron: 0x0100, + Amonospace: 0xFF21, + Aogonek: 0x0104, + Aring: 0x00C5, + Aringacute: 0x01FA, + Aringbelow: 0x1E00, + Aringsmall: 0xF7E5, + Asmall: 0xF761, + Atilde: 0x00C3, + Atildesmall: 0xF7E3, + Aybarmenian: 0x0531, + B: 0x0042, + Bcircle: 0x24B7, + Bdotaccent: 0x1E02, + Bdotbelow: 0x1E04, + Becyrillic: 0x0411, + Benarmenian: 0x0532, + Beta: 0x0392, + Bhook: 0x0181, + Blinebelow: 0x1E06, + Bmonospace: 0xFF22, + Brevesmall: 0xF6F4, + Bsmall: 0xF762, + Btopbar: 0x0182, + C: 0x0043, + Caarmenian: 0x053E, + Cacute: 0x0106, + Caron: 0xF6CA, + Caronsmall: 0xF6F5, + Ccaron: 0x010C, + Ccedilla: 0x00C7, + Ccedillaacute: 0x1E08, + Ccedillasmall: 0xF7E7, + Ccircle: 0x24B8, + Ccircumflex: 0x0108, + Cdot: 0x010A, + Cdotaccent: 0x010A, + Cedillasmall: 0xF7B8, + Chaarmenian: 0x0549, + Cheabkhasiancyrillic: 0x04BC, + Checyrillic: 0x0427, + Chedescenderabkhasiancyrillic: 0x04BE, + Chedescendercyrillic: 0x04B6, + Chedieresiscyrillic: 0x04F4, + Cheharmenian: 0x0543, + Chekhakassiancyrillic: 0x04CB, + Cheverticalstrokecyrillic: 0x04B8, + Chi: 0x03A7, + Chook: 0x0187, + Circumflexsmall: 0xF6F6, + Cmonospace: 0xFF23, + Coarmenian: 0x0551, + Csmall: 0xF763, + D: 0x0044, + DZ: 0x01F1, + DZcaron: 0x01C4, + Daarmenian: 0x0534, + Dafrican: 0x0189, + Dcaron: 0x010E, + Dcedilla: 0x1E10, + Dcircle: 0x24B9, + Dcircumflexbelow: 0x1E12, + Dcroat: 0x0110, + Ddotaccent: 0x1E0A, + Ddotbelow: 0x1E0C, + Decyrillic: 0x0414, + Deicoptic: 0x03EE, + Delta: 0x2206, + Deltagreek: 0x0394, + Dhook: 0x018A, + Dieresis: 0xF6CB, + DieresisAcute: 0xF6CC, + DieresisGrave: 0xF6CD, + Dieresissmall: 0xF7A8, + Digammagreek: 0x03DC, + Djecyrillic: 0x0402, + Dlinebelow: 0x1E0E, + Dmonospace: 0xFF24, + Dotaccentsmall: 0xF6F7, + Dslash: 0x0110, + Dsmall: 0xF764, + Dtopbar: 0x018B, + Dz: 0x01F2, + Dzcaron: 0x01C5, + Dzeabkhasiancyrillic: 0x04E0, + Dzecyrillic: 0x0405, + Dzhecyrillic: 0x040F, + E: 0x0045, + Eacute: 0x00C9, + Eacutesmall: 0xF7E9, + Ebreve: 0x0114, + Ecaron: 0x011A, + Ecedillabreve: 0x1E1C, + Echarmenian: 0x0535, + Ecircle: 0x24BA, + Ecircumflex: 0x00CA, + Ecircumflexacute: 0x1EBE, + Ecircumflexbelow: 0x1E18, + Ecircumflexdotbelow: 0x1EC6, + Ecircumflexgrave: 0x1EC0, + Ecircumflexhookabove: 0x1EC2, + Ecircumflexsmall: 0xF7EA, + Ecircumflextilde: 0x1EC4, + Ecyrillic: 0x0404, + Edblgrave: 0x0204, + Edieresis: 0x00CB, + Edieresissmall: 0xF7EB, + Edot: 0x0116, + Edotaccent: 0x0116, + Edotbelow: 0x1EB8, + Efcyrillic: 0x0424, + Egrave: 0x00C8, + Egravesmall: 0xF7E8, + Eharmenian: 0x0537, + Ehookabove: 0x1EBA, + Eightroman: 0x2167, + Einvertedbreve: 0x0206, + Eiotifiedcyrillic: 0x0464, + Elcyrillic: 0x041B, + Elevenroman: 0x216A, + Emacron: 0x0112, + Emacronacute: 0x1E16, + Emacrongrave: 0x1E14, + Emcyrillic: 0x041C, + Emonospace: 0xFF25, + Encyrillic: 0x041D, + Endescendercyrillic: 0x04A2, + Eng: 0x014A, + Enghecyrillic: 0x04A4, + Enhookcyrillic: 0x04C7, + Eogonek: 0x0118, + Eopen: 0x0190, + Epsilon: 0x0395, + Epsilontonos: 0x0388, + Ercyrillic: 0x0420, + Ereversed: 0x018E, + Ereversedcyrillic: 0x042D, + Escyrillic: 0x0421, + Esdescendercyrillic: 0x04AA, + Esh: 0x01A9, + Esmall: 0xF765, + Eta: 0x0397, + Etarmenian: 0x0538, + Etatonos: 0x0389, + Eth: 0x00D0, + Ethsmall: 0xF7F0, + Etilde: 0x1EBC, + Etildebelow: 0x1E1A, + Euro: 0x20AC, + Ezh: 0x01B7, + Ezhcaron: 0x01EE, + Ezhreversed: 0x01B8, + F: 0x0046, + Fcircle: 0x24BB, + Fdotaccent: 0x1E1E, + Feharmenian: 0x0556, + Feicoptic: 0x03E4, + Fhook: 0x0191, + Fitacyrillic: 0x0472, + Fiveroman: 0x2164, + Fmonospace: 0xFF26, + Fourroman: 0x2163, + Fsmall: 0xF766, + G: 0x0047, + GBsquare: 0x3387, + Gacute: 0x01F4, + Gamma: 0x0393, + Gammaafrican: 0x0194, + Gangiacoptic: 0x03EA, + Gbreve: 0x011E, + Gcaron: 0x01E6, + Gcedilla: 0x0122, + Gcircle: 0x24BC, + Gcircumflex: 0x011C, + Gcommaaccent: 0x0122, + Gdot: 0x0120, + Gdotaccent: 0x0120, + Gecyrillic: 0x0413, + Ghadarmenian: 0x0542, + Ghemiddlehookcyrillic: 0x0494, + Ghestrokecyrillic: 0x0492, + Gheupturncyrillic: 0x0490, + Ghook: 0x0193, + Gimarmenian: 0x0533, + Gjecyrillic: 0x0403, + Gmacron: 0x1E20, + Gmonospace: 0xFF27, + Grave: 0xF6CE, + Gravesmall: 0xF760, + Gsmall: 0xF767, + Gsmallhook: 0x029B, + Gstroke: 0x01E4, + H: 0x0048, + H18533: 0x25CF, + H18543: 0x25AA, + H18551: 0x25AB, + H22073: 0x25A1, + HPsquare: 0x33CB, + Haabkhasiancyrillic: 0x04A8, + Hadescendercyrillic: 0x04B2, + Hardsigncyrillic: 0x042A, + Hbar: 0x0126, + Hbrevebelow: 0x1E2A, + Hcedilla: 0x1E28, + Hcircle: 0x24BD, + Hcircumflex: 0x0124, + Hdieresis: 0x1E26, + Hdotaccent: 0x1E22, + Hdotbelow: 0x1E24, + Hmonospace: 0xFF28, + Hoarmenian: 0x0540, + Horicoptic: 0x03E8, + Hsmall: 0xF768, + Hungarumlaut: 0xF6CF, + Hungarumlautsmall: 0xF6F8, + Hzsquare: 0x3390, + I: 0x0049, + IAcyrillic: 0x042F, + IJ: 0x0132, + IUcyrillic: 0x042E, + Iacute: 0x00CD, + Iacutesmall: 0xF7ED, + Ibreve: 0x012C, + Icaron: 0x01CF, + Icircle: 0x24BE, + Icircumflex: 0x00CE, + Icircumflexsmall: 0xF7EE, + Icyrillic: 0x0406, + Idblgrave: 0x0208, + Idieresis: 0x00CF, + Idieresisacute: 0x1E2E, + Idieresiscyrillic: 0x04E4, + Idieresissmall: 0xF7EF, + Idot: 0x0130, + Idotaccent: 0x0130, + Idotbelow: 0x1ECA, + Iebrevecyrillic: 0x04D6, + Iecyrillic: 0x0415, + Ifraktur: 0x2111, + Igrave: 0x00CC, + Igravesmall: 0xF7EC, + Ihookabove: 0x1EC8, + Iicyrillic: 0x0418, + Iinvertedbreve: 0x020A, + Iishortcyrillic: 0x0419, + Imacron: 0x012A, + Imacroncyrillic: 0x04E2, + Imonospace: 0xFF29, + Iniarmenian: 0x053B, + Iocyrillic: 0x0401, + Iogonek: 0x012E, + Iota: 0x0399, + Iotaafrican: 0x0196, + Iotadieresis: 0x03AA, + Iotatonos: 0x038A, + Ismall: 0xF769, + Istroke: 0x0197, + Itilde: 0x0128, + Itildebelow: 0x1E2C, + Izhitsacyrillic: 0x0474, + Izhitsadblgravecyrillic: 0x0476, + J: 0x004A, + Jaarmenian: 0x0541, + Jcircle: 0x24BF, + Jcircumflex: 0x0134, + Jecyrillic: 0x0408, + Jheharmenian: 0x054B, + Jmonospace: 0xFF2A, + Jsmall: 0xF76A, + K: 0x004B, + KBsquare: 0x3385, + KKsquare: 0x33CD, + Kabashkircyrillic: 0x04A0, + Kacute: 0x1E30, + Kacyrillic: 0x041A, + Kadescendercyrillic: 0x049A, + Kahookcyrillic: 0x04C3, + Kappa: 0x039A, + Kastrokecyrillic: 0x049E, + Kaverticalstrokecyrillic: 0x049C, + Kcaron: 0x01E8, + Kcedilla: 0x0136, + Kcircle: 0x24C0, + Kcommaaccent: 0x0136, + Kdotbelow: 0x1E32, + Keharmenian: 0x0554, + Kenarmenian: 0x053F, + Khacyrillic: 0x0425, + Kheicoptic: 0x03E6, + Khook: 0x0198, + Kjecyrillic: 0x040C, + Klinebelow: 0x1E34, + Kmonospace: 0xFF2B, + Koppacyrillic: 0x0480, + Koppagreek: 0x03DE, + Ksicyrillic: 0x046E, + Ksmall: 0xF76B, + L: 0x004C, + LJ: 0x01C7, + LL: 0xF6BF, + Lacute: 0x0139, + Lambda: 0x039B, + Lcaron: 0x013D, + Lcedilla: 0x013B, + Lcircle: 0x24C1, + Lcircumflexbelow: 0x1E3C, + Lcommaaccent: 0x013B, + Ldot: 0x013F, + Ldotaccent: 0x013F, + Ldotbelow: 0x1E36, + Ldotbelowmacron: 0x1E38, + Liwnarmenian: 0x053C, + Lj: 0x01C8, + Ljecyrillic: 0x0409, + Llinebelow: 0x1E3A, + Lmonospace: 0xFF2C, + Lslash: 0x0141, + Lslashsmall: 0xF6F9, + Lsmall: 0xF76C, + M: 0x004D, + MBsquare: 0x3386, + Macron: 0xF6D0, + Macronsmall: 0xF7AF, + Macute: 0x1E3E, + Mcircle: 0x24C2, + Mdotaccent: 0x1E40, + Mdotbelow: 0x1E42, + Menarmenian: 0x0544, + Mmonospace: 0xFF2D, + Msmall: 0xF76D, + Mturned: 0x019C, + Mu: 0x039C, + N: 0x004E, + NJ: 0x01CA, + Nacute: 0x0143, + Ncaron: 0x0147, + Ncedilla: 0x0145, + Ncircle: 0x24C3, + Ncircumflexbelow: 0x1E4A, + Ncommaaccent: 0x0145, + Ndotaccent: 0x1E44, + Ndotbelow: 0x1E46, + Nhookleft: 0x019D, + Nineroman: 0x2168, + Nj: 0x01CB, + Njecyrillic: 0x040A, + Nlinebelow: 0x1E48, + Nmonospace: 0xFF2E, + Nowarmenian: 0x0546, + Nsmall: 0xF76E, + Ntilde: 0x00D1, + Ntildesmall: 0xF7F1, + Nu: 0x039D, + O: 0x004F, + OE: 0x0152, + OEsmall: 0xF6FA, + Oacute: 0x00D3, + Oacutesmall: 0xF7F3, + Obarredcyrillic: 0x04E8, + Obarreddieresiscyrillic: 0x04EA, + Obreve: 0x014E, + Ocaron: 0x01D1, + Ocenteredtilde: 0x019F, + Ocircle: 0x24C4, + Ocircumflex: 0x00D4, + Ocircumflexacute: 0x1ED0, + Ocircumflexdotbelow: 0x1ED8, + Ocircumflexgrave: 0x1ED2, + Ocircumflexhookabove: 0x1ED4, + Ocircumflexsmall: 0xF7F4, + Ocircumflextilde: 0x1ED6, + Ocyrillic: 0x041E, + Odblacute: 0x0150, + Odblgrave: 0x020C, + Odieresis: 0x00D6, + Odieresiscyrillic: 0x04E6, + Odieresissmall: 0xF7F6, + Odotbelow: 0x1ECC, + Ogoneksmall: 0xF6FB, + Ograve: 0x00D2, + Ogravesmall: 0xF7F2, + Oharmenian: 0x0555, + Ohm: 0x2126, + Ohookabove: 0x1ECE, + Ohorn: 0x01A0, + Ohornacute: 0x1EDA, + Ohorndotbelow: 0x1EE2, + Ohorngrave: 0x1EDC, + Ohornhookabove: 0x1EDE, + Ohorntilde: 0x1EE0, + Ohungarumlaut: 0x0150, + Oi: 0x01A2, + Oinvertedbreve: 0x020E, + Omacron: 0x014C, + Omacronacute: 0x1E52, + Omacrongrave: 0x1E50, + Omega: 0x2126, + Omegacyrillic: 0x0460, + Omegagreek: 0x03A9, + Omegaroundcyrillic: 0x047A, + Omegatitlocyrillic: 0x047C, + Omegatonos: 0x038F, + Omicron: 0x039F, + Omicrontonos: 0x038C, + Omonospace: 0xFF2F, + Oneroman: 0x2160, + Oogonek: 0x01EA, + Oogonekmacron: 0x01EC, + Oopen: 0x0186, + Oslash: 0x00D8, + Oslashacute: 0x01FE, + Oslashsmall: 0xF7F8, + Osmall: 0xF76F, + Ostrokeacute: 0x01FE, + Otcyrillic: 0x047E, + Otilde: 0x00D5, + Otildeacute: 0x1E4C, + Otildedieresis: 0x1E4E, + Otildesmall: 0xF7F5, + P: 0x0050, + Pacute: 0x1E54, + Pcircle: 0x24C5, + Pdotaccent: 0x1E56, + Pecyrillic: 0x041F, + Peharmenian: 0x054A, + Pemiddlehookcyrillic: 0x04A6, + Phi: 0x03A6, + Phook: 0x01A4, + Pi: 0x03A0, + Piwrarmenian: 0x0553, + Pmonospace: 0xFF30, + Psi: 0x03A8, + Psicyrillic: 0x0470, + Psmall: 0xF770, + Q: 0x0051, + Qcircle: 0x24C6, + Qmonospace: 0xFF31, + Qsmall: 0xF771, + R: 0x0052, + Raarmenian: 0x054C, + Racute: 0x0154, + Rcaron: 0x0158, + Rcedilla: 0x0156, + Rcircle: 0x24C7, + Rcommaaccent: 0x0156, + Rdblgrave: 0x0210, + Rdotaccent: 0x1E58, + Rdotbelow: 0x1E5A, + Rdotbelowmacron: 0x1E5C, + Reharmenian: 0x0550, + Rfraktur: 0x211C, + Rho: 0x03A1, + Ringsmall: 0xF6FC, + Rinvertedbreve: 0x0212, + Rlinebelow: 0x1E5E, + Rmonospace: 0xFF32, + Rsmall: 0xF772, + Rsmallinverted: 0x0281, + Rsmallinvertedsuperior: 0x02B6, + S: 0x0053, + SF010000: 0x250C, + SF020000: 0x2514, + SF030000: 0x2510, + SF040000: 0x2518, + SF050000: 0x253C, + SF060000: 0x252C, + SF070000: 0x2534, + SF080000: 0x251C, + SF090000: 0x2524, + SF100000: 0x2500, + SF110000: 0x2502, + SF190000: 0x2561, + SF200000: 0x2562, + SF210000: 0x2556, + SF220000: 0x2555, + SF230000: 0x2563, + SF240000: 0x2551, + SF250000: 0x2557, + SF260000: 0x255D, + SF270000: 0x255C, + SF280000: 0x255B, + SF360000: 0x255E, + SF370000: 0x255F, + SF380000: 0x255A, + SF390000: 0x2554, + SF400000: 0x2569, + SF410000: 0x2566, + SF420000: 0x2560, + SF430000: 0x2550, + SF440000: 0x256C, + SF450000: 0x2567, + SF460000: 0x2568, + SF470000: 0x2564, + SF480000: 0x2565, + SF490000: 0x2559, + SF500000: 0x2558, + SF510000: 0x2552, + SF520000: 0x2553, + SF530000: 0x256B, + SF540000: 0x256A, + Sacute: 0x015A, + Sacutedotaccent: 0x1E64, + Sampigreek: 0x03E0, + Scaron: 0x0160, + Scarondotaccent: 0x1E66, + Scaronsmall: 0xF6FD, + Scedilla: 0x015E, + Schwa: 0x018F, + Schwacyrillic: 0x04D8, + Schwadieresiscyrillic: 0x04DA, + Scircle: 0x24C8, + Scircumflex: 0x015C, + Scommaaccent: 0x0218, + Sdotaccent: 0x1E60, + Sdotbelow: 0x1E62, + Sdotbelowdotaccent: 0x1E68, + Seharmenian: 0x054D, + Sevenroman: 0x2166, + Shaarmenian: 0x0547, + Shacyrillic: 0x0428, + Shchacyrillic: 0x0429, + Sheicoptic: 0x03E2, + Shhacyrillic: 0x04BA, + Shimacoptic: 0x03EC, + Sigma: 0x03A3, + Sixroman: 0x2165, + Smonospace: 0xFF33, + Softsigncyrillic: 0x042C, + Ssmall: 0xF773, + Stigmagreek: 0x03DA, + T: 0x0054, + Tau: 0x03A4, + Tbar: 0x0166, + Tcaron: 0x0164, + Tcedilla: 0x0162, + Tcircle: 0x24C9, + Tcircumflexbelow: 0x1E70, + Tcommaaccent: 0x0162, + Tdotaccent: 0x1E6A, + Tdotbelow: 0x1E6C, + Tecyrillic: 0x0422, + Tedescendercyrillic: 0x04AC, + Tenroman: 0x2169, + Tetsecyrillic: 0x04B4, + Theta: 0x0398, + Thook: 0x01AC, + Thorn: 0x00DE, + Thornsmall: 0xF7FE, + Threeroman: 0x2162, + Tildesmall: 0xF6FE, + Tiwnarmenian: 0x054F, + Tlinebelow: 0x1E6E, + Tmonospace: 0xFF34, + Toarmenian: 0x0539, + Tonefive: 0x01BC, + Tonesix: 0x0184, + Tonetwo: 0x01A7, + Tretroflexhook: 0x01AE, + Tsecyrillic: 0x0426, + Tshecyrillic: 0x040B, + Tsmall: 0xF774, + Twelveroman: 0x216B, + Tworoman: 0x2161, + U: 0x0055, + Uacute: 0x00DA, + Uacutesmall: 0xF7FA, + Ubreve: 0x016C, + Ucaron: 0x01D3, + Ucircle: 0x24CA, + Ucircumflex: 0x00DB, + Ucircumflexbelow: 0x1E76, + Ucircumflexsmall: 0xF7FB, + Ucyrillic: 0x0423, + Udblacute: 0x0170, + Udblgrave: 0x0214, + Udieresis: 0x00DC, + Udieresisacute: 0x01D7, + Udieresisbelow: 0x1E72, + Udieresiscaron: 0x01D9, + Udieresiscyrillic: 0x04F0, + Udieresisgrave: 0x01DB, + Udieresismacron: 0x01D5, + Udieresissmall: 0xF7FC, + Udotbelow: 0x1EE4, + Ugrave: 0x00D9, + Ugravesmall: 0xF7F9, + Uhookabove: 0x1EE6, + Uhorn: 0x01AF, + Uhornacute: 0x1EE8, + Uhorndotbelow: 0x1EF0, + Uhorngrave: 0x1EEA, + Uhornhookabove: 0x1EEC, + Uhorntilde: 0x1EEE, + Uhungarumlaut: 0x0170, + Uhungarumlautcyrillic: 0x04F2, + Uinvertedbreve: 0x0216, + Ukcyrillic: 0x0478, + Umacron: 0x016A, + Umacroncyrillic: 0x04EE, + Umacrondieresis: 0x1E7A, + Umonospace: 0xFF35, + Uogonek: 0x0172, + Upsilon: 0x03A5, + Upsilon1: 0x03D2, + Upsilonacutehooksymbolgreek: 0x03D3, + Upsilonafrican: 0x01B1, + Upsilondieresis: 0x03AB, + Upsilondieresishooksymbolgreek: 0x03D4, + Upsilonhooksymbol: 0x03D2, + Upsilontonos: 0x038E, + Uring: 0x016E, + Ushortcyrillic: 0x040E, + Usmall: 0xF775, + Ustraightcyrillic: 0x04AE, + Ustraightstrokecyrillic: 0x04B0, + Utilde: 0x0168, + Utildeacute: 0x1E78, + Utildebelow: 0x1E74, + V: 0x0056, + Vcircle: 0x24CB, + Vdotbelow: 0x1E7E, + Vecyrillic: 0x0412, + Vewarmenian: 0x054E, + Vhook: 0x01B2, + Vmonospace: 0xFF36, + Voarmenian: 0x0548, + Vsmall: 0xF776, + Vtilde: 0x1E7C, + W: 0x0057, + Wacute: 0x1E82, + Wcircle: 0x24CC, + Wcircumflex: 0x0174, + Wdieresis: 0x1E84, + Wdotaccent: 0x1E86, + Wdotbelow: 0x1E88, + Wgrave: 0x1E80, + Wmonospace: 0xFF37, + Wsmall: 0xF777, + X: 0x0058, + Xcircle: 0x24CD, + Xdieresis: 0x1E8C, + Xdotaccent: 0x1E8A, + Xeharmenian: 0x053D, + Xi: 0x039E, + Xmonospace: 0xFF38, + Xsmall: 0xF778, + Y: 0x0059, + Yacute: 0x00DD, + Yacutesmall: 0xF7FD, + Yatcyrillic: 0x0462, + Ycircle: 0x24CE, + Ycircumflex: 0x0176, + Ydieresis: 0x0178, + Ydieresissmall: 0xF7FF, + Ydotaccent: 0x1E8E, + Ydotbelow: 0x1EF4, + Yericyrillic: 0x042B, + Yerudieresiscyrillic: 0x04F8, + Ygrave: 0x1EF2, + Yhook: 0x01B3, + Yhookabove: 0x1EF6, + Yiarmenian: 0x0545, + Yicyrillic: 0x0407, + Yiwnarmenian: 0x0552, + Ymonospace: 0xFF39, + Ysmall: 0xF779, + Ytilde: 0x1EF8, + Yusbigcyrillic: 0x046A, + Yusbigiotifiedcyrillic: 0x046C, + Yuslittlecyrillic: 0x0466, + Yuslittleiotifiedcyrillic: 0x0468, + Z: 0x005A, + Zaarmenian: 0x0536, + Zacute: 0x0179, + Zcaron: 0x017D, + Zcaronsmall: 0xF6FF, + Zcircle: 0x24CF, + Zcircumflex: 0x1E90, + Zdot: 0x017B, + Zdotaccent: 0x017B, + Zdotbelow: 0x1E92, + Zecyrillic: 0x0417, + Zedescendercyrillic: 0x0498, + Zedieresiscyrillic: 0x04DE, + Zeta: 0x0396, + Zhearmenian: 0x053A, + Zhebrevecyrillic: 0x04C1, + Zhecyrillic: 0x0416, + Zhedescendercyrillic: 0x0496, + Zhedieresiscyrillic: 0x04DC, + Zlinebelow: 0x1E94, + Zmonospace: 0xFF3A, + Zsmall: 0xF77A, + Zstroke: 0x01B5, + a: 0x0061, + aabengali: 0x0986, + aacute: 0x00E1, + aadeva: 0x0906, + aagujarati: 0x0A86, + aagurmukhi: 0x0A06, + aamatragurmukhi: 0x0A3E, + aarusquare: 0x3303, + aavowelsignbengali: 0x09BE, + aavowelsigndeva: 0x093E, + aavowelsigngujarati: 0x0ABE, + abbreviationmarkarmenian: 0x055F, + abbreviationsigndeva: 0x0970, + abengali: 0x0985, + abopomofo: 0x311A, + abreve: 0x0103, + abreveacute: 0x1EAF, + abrevecyrillic: 0x04D1, + abrevedotbelow: 0x1EB7, + abrevegrave: 0x1EB1, + abrevehookabove: 0x1EB3, + abrevetilde: 0x1EB5, + acaron: 0x01CE, + acircle: 0x24D0, + acircumflex: 0x00E2, + acircumflexacute: 0x1EA5, + acircumflexdotbelow: 0x1EAD, + acircumflexgrave: 0x1EA7, + acircumflexhookabove: 0x1EA9, + acircumflextilde: 0x1EAB, + acute: 0x00B4, + acutebelowcmb: 0x0317, + acutecmb: 0x0301, + acutecomb: 0x0301, + acutedeva: 0x0954, + acutelowmod: 0x02CF, + acutetonecmb: 0x0341, + acyrillic: 0x0430, + adblgrave: 0x0201, + addakgurmukhi: 0x0A71, + adeva: 0x0905, + adieresis: 0x00E4, + adieresiscyrillic: 0x04D3, + adieresismacron: 0x01DF, + adotbelow: 0x1EA1, + adotmacron: 0x01E1, + ae: 0x00E6, + aeacute: 0x01FD, + aekorean: 0x3150, + aemacron: 0x01E3, + afii00208: 0x2015, + afii08941: 0x20A4, + afii10017: 0x0410, + afii10018: 0x0411, + afii10019: 0x0412, + afii10020: 0x0413, + afii10021: 0x0414, + afii10022: 0x0415, + afii10023: 0x0401, + afii10024: 0x0416, + afii10025: 0x0417, + afii10026: 0x0418, + afii10027: 0x0419, + afii10028: 0x041A, + afii10029: 0x041B, + afii10030: 0x041C, + afii10031: 0x041D, + afii10032: 0x041E, + afii10033: 0x041F, + afii10034: 0x0420, + afii10035: 0x0421, + afii10036: 0x0422, + afii10037: 0x0423, + afii10038: 0x0424, + afii10039: 0x0425, + afii10040: 0x0426, + afii10041: 0x0427, + afii10042: 0x0428, + afii10043: 0x0429, + afii10044: 0x042A, + afii10045: 0x042B, + afii10046: 0x042C, + afii10047: 0x042D, + afii10048: 0x042E, + afii10049: 0x042F, + afii10050: 0x0490, + afii10051: 0x0402, + afii10052: 0x0403, + afii10053: 0x0404, + afii10054: 0x0405, + afii10055: 0x0406, + afii10056: 0x0407, + afii10057: 0x0408, + afii10058: 0x0409, + afii10059: 0x040A, + afii10060: 0x040B, + afii10061: 0x040C, + afii10062: 0x040E, + afii10063: 0xF6C4, + afii10064: 0xF6C5, + afii10065: 0x0430, + afii10066: 0x0431, + afii10067: 0x0432, + afii10068: 0x0433, + afii10069: 0x0434, + afii10070: 0x0435, + afii10071: 0x0451, + afii10072: 0x0436, + afii10073: 0x0437, + afii10074: 0x0438, + afii10075: 0x0439, + afii10076: 0x043A, + afii10077: 0x043B, + afii10078: 0x043C, + afii10079: 0x043D, + afii10080: 0x043E, + afii10081: 0x043F, + afii10082: 0x0440, + afii10083: 0x0441, + afii10084: 0x0442, + afii10085: 0x0443, + afii10086: 0x0444, + afii10087: 0x0445, + afii10088: 0x0446, + afii10089: 0x0447, + afii10090: 0x0448, + afii10091: 0x0449, + afii10092: 0x044A, + afii10093: 0x044B, + afii10094: 0x044C, + afii10095: 0x044D, + afii10096: 0x044E, + afii10097: 0x044F, + afii10098: 0x0491, + afii10099: 0x0452, + afii10100: 0x0453, + afii10101: 0x0454, + afii10102: 0x0455, + afii10103: 0x0456, + afii10104: 0x0457, + afii10105: 0x0458, + afii10106: 0x0459, + afii10107: 0x045A, + afii10108: 0x045B, + afii10109: 0x045C, + afii10110: 0x045E, + afii10145: 0x040F, + afii10146: 0x0462, + afii10147: 0x0472, + afii10148: 0x0474, + afii10192: 0xF6C6, + afii10193: 0x045F, + afii10194: 0x0463, + afii10195: 0x0473, + afii10196: 0x0475, + afii10831: 0xF6C7, + afii10832: 0xF6C8, + afii10846: 0x04D9, + afii299: 0x200E, + afii300: 0x200F, + afii301: 0x200D, + afii57381: 0x066A, + afii57388: 0x060C, + afii57392: 0x0660, + afii57393: 0x0661, + afii57394: 0x0662, + afii57395: 0x0663, + afii57396: 0x0664, + afii57397: 0x0665, + afii57398: 0x0666, + afii57399: 0x0667, + afii57400: 0x0668, + afii57401: 0x0669, + afii57403: 0x061B, + afii57407: 0x061F, + afii57409: 0x0621, + afii57410: 0x0622, + afii57411: 0x0623, + afii57412: 0x0624, + afii57413: 0x0625, + afii57414: 0x0626, + afii57415: 0x0627, + afii57416: 0x0628, + afii57417: 0x0629, + afii57418: 0x062A, + afii57419: 0x062B, + afii57420: 0x062C, + afii57421: 0x062D, + afii57422: 0x062E, + afii57423: 0x062F, + afii57424: 0x0630, + afii57425: 0x0631, + afii57426: 0x0632, + afii57427: 0x0633, + afii57428: 0x0634, + afii57429: 0x0635, + afii57430: 0x0636, + afii57431: 0x0637, + afii57432: 0x0638, + afii57433: 0x0639, + afii57434: 0x063A, + afii57440: 0x0640, + afii57441: 0x0641, + afii57442: 0x0642, + afii57443: 0x0643, + afii57444: 0x0644, + afii57445: 0x0645, + afii57446: 0x0646, + afii57448: 0x0648, + afii57449: 0x0649, + afii57450: 0x064A, + afii57451: 0x064B, + afii57452: 0x064C, + afii57453: 0x064D, + afii57454: 0x064E, + afii57455: 0x064F, + afii57456: 0x0650, + afii57457: 0x0651, + afii57458: 0x0652, + afii57470: 0x0647, + afii57505: 0x06A4, + afii57506: 0x067E, + afii57507: 0x0686, + afii57508: 0x0698, + afii57509: 0x06AF, + afii57511: 0x0679, + afii57512: 0x0688, + afii57513: 0x0691, + afii57514: 0x06BA, + afii57519: 0x06D2, + afii57534: 0x06D5, + afii57636: 0x20AA, + afii57645: 0x05BE, + afii57658: 0x05C3, + afii57664: 0x05D0, + afii57665: 0x05D1, + afii57666: 0x05D2, + afii57667: 0x05D3, + afii57668: 0x05D4, + afii57669: 0x05D5, + afii57670: 0x05D6, + afii57671: 0x05D7, + afii57672: 0x05D8, + afii57673: 0x05D9, + afii57674: 0x05DA, + afii57675: 0x05DB, + afii57676: 0x05DC, + afii57677: 0x05DD, + afii57678: 0x05DE, + afii57679: 0x05DF, + afii57680: 0x05E0, + afii57681: 0x05E1, + afii57682: 0x05E2, + afii57683: 0x05E3, + afii57684: 0x05E4, + afii57685: 0x05E5, + afii57686: 0x05E6, + afii57687: 0x05E7, + afii57688: 0x05E8, + afii57689: 0x05E9, + afii57690: 0x05EA, + afii57694: 0xFB2A, + afii57695: 0xFB2B, + afii57700: 0xFB4B, + afii57705: 0xFB1F, + afii57716: 0x05F0, + afii57717: 0x05F1, + afii57718: 0x05F2, + afii57723: 0xFB35, + afii57793: 0x05B4, + afii57794: 0x05B5, + afii57795: 0x05B6, + afii57796: 0x05BB, + afii57797: 0x05B8, + afii57798: 0x05B7, + afii57799: 0x05B0, + afii57800: 0x05B2, + afii57801: 0x05B1, + afii57802: 0x05B3, + afii57803: 0x05C2, + afii57804: 0x05C1, + afii57806: 0x05B9, + afii57807: 0x05BC, + afii57839: 0x05BD, + afii57841: 0x05BF, + afii57842: 0x05C0, + afii57929: 0x02BC, + afii61248: 0x2105, + afii61289: 0x2113, + afii61352: 0x2116, + afii61573: 0x202C, + afii61574: 0x202D, + afii61575: 0x202E, + afii61664: 0x200C, + afii63167: 0x066D, + afii64937: 0x02BD, + agrave: 0x00E0, + agujarati: 0x0A85, + agurmukhi: 0x0A05, + ahiragana: 0x3042, + ahookabove: 0x1EA3, + aibengali: 0x0990, + aibopomofo: 0x311E, + aideva: 0x0910, + aiecyrillic: 0x04D5, + aigujarati: 0x0A90, + aigurmukhi: 0x0A10, + aimatragurmukhi: 0x0A48, + ainarabic: 0x0639, + ainfinalarabic: 0xFECA, + aininitialarabic: 0xFECB, + ainmedialarabic: 0xFECC, + ainvertedbreve: 0x0203, + aivowelsignbengali: 0x09C8, + aivowelsigndeva: 0x0948, + aivowelsigngujarati: 0x0AC8, + akatakana: 0x30A2, + akatakanahalfwidth: 0xFF71, + akorean: 0x314F, + alef: 0x05D0, + alefarabic: 0x0627, + alefdageshhebrew: 0xFB30, + aleffinalarabic: 0xFE8E, + alefhamzaabovearabic: 0x0623, + alefhamzaabovefinalarabic: 0xFE84, + alefhamzabelowarabic: 0x0625, + alefhamzabelowfinalarabic: 0xFE88, + alefhebrew: 0x05D0, + aleflamedhebrew: 0xFB4F, + alefmaddaabovearabic: 0x0622, + alefmaddaabovefinalarabic: 0xFE82, + alefmaksuraarabic: 0x0649, + alefmaksurafinalarabic: 0xFEF0, + alefmaksurainitialarabic: 0xFEF3, + alefmaksuramedialarabic: 0xFEF4, + alefpatahhebrew: 0xFB2E, + alefqamatshebrew: 0xFB2F, + aleph: 0x2135, + allequal: 0x224C, + alpha: 0x03B1, + alphatonos: 0x03AC, + amacron: 0x0101, + amonospace: 0xFF41, + ampersand: 0x0026, + ampersandmonospace: 0xFF06, + ampersandsmall: 0xF726, + amsquare: 0x33C2, + anbopomofo: 0x3122, + angbopomofo: 0x3124, + angkhankhuthai: 0x0E5A, + angle: 0x2220, + anglebracketleft: 0x3008, + anglebracketleftvertical: 0xFE3F, + anglebracketright: 0x3009, + anglebracketrightvertical: 0xFE40, + angleleft: 0x2329, + angleright: 0x232A, + angstrom: 0x212B, + anoteleia: 0x0387, + anudattadeva: 0x0952, + anusvarabengali: 0x0982, + anusvaradeva: 0x0902, + anusvaragujarati: 0x0A82, + aogonek: 0x0105, + apaatosquare: 0x3300, + aparen: 0x249C, + apostrophearmenian: 0x055A, + apostrophemod: 0x02BC, + apple: 0xF8FF, + approaches: 0x2250, + approxequal: 0x2248, + approxequalorimage: 0x2252, + approximatelyequal: 0x2245, + araeaekorean: 0x318E, + araeakorean: 0x318D, + arc: 0x2312, + arighthalfring: 0x1E9A, + aring: 0x00E5, + aringacute: 0x01FB, + aringbelow: 0x1E01, + arrowboth: 0x2194, + arrowdashdown: 0x21E3, + arrowdashleft: 0x21E0, + arrowdashright: 0x21E2, + arrowdashup: 0x21E1, + arrowdblboth: 0x21D4, + arrowdbldown: 0x21D3, + arrowdblleft: 0x21D0, + arrowdblright: 0x21D2, + arrowdblup: 0x21D1, + arrowdown: 0x2193, + arrowdownleft: 0x2199, + arrowdownright: 0x2198, + arrowdownwhite: 0x21E9, + arrowheaddownmod: 0x02C5, + arrowheadleftmod: 0x02C2, + arrowheadrightmod: 0x02C3, + arrowheadupmod: 0x02C4, + arrowhorizex: 0xF8E7, + arrowleft: 0x2190, + arrowleftdbl: 0x21D0, + arrowleftdblstroke: 0x21CD, + arrowleftoverright: 0x21C6, + arrowleftwhite: 0x21E6, + arrowright: 0x2192, + arrowrightdblstroke: 0x21CF, + arrowrightheavy: 0x279E, + arrowrightoverleft: 0x21C4, + arrowrightwhite: 0x21E8, + arrowtableft: 0x21E4, + arrowtabright: 0x21E5, + arrowup: 0x2191, + arrowupdn: 0x2195, + arrowupdnbse: 0x21A8, + arrowupdownbase: 0x21A8, + arrowupleft: 0x2196, + arrowupleftofdown: 0x21C5, + arrowupright: 0x2197, + arrowupwhite: 0x21E7, + arrowvertex: 0xF8E6, + asciicircum: 0x005E, + asciicircummonospace: 0xFF3E, + asciitilde: 0x007E, + asciitildemonospace: 0xFF5E, + ascript: 0x0251, + ascriptturned: 0x0252, + asmallhiragana: 0x3041, + asmallkatakana: 0x30A1, + asmallkatakanahalfwidth: 0xFF67, + asterisk: 0x002A, + asteriskaltonearabic: 0x066D, + asteriskarabic: 0x066D, + asteriskmath: 0x2217, + asteriskmonospace: 0xFF0A, + asterisksmall: 0xFE61, + asterism: 0x2042, + asuperior: 0xF6E9, + asymptoticallyequal: 0x2243, + at: 0x0040, + atilde: 0x00E3, + atmonospace: 0xFF20, + atsmall: 0xFE6B, + aturned: 0x0250, + aubengali: 0x0994, + aubopomofo: 0x3120, + audeva: 0x0914, + augujarati: 0x0A94, + augurmukhi: 0x0A14, + aulengthmarkbengali: 0x09D7, + aumatragurmukhi: 0x0A4C, + auvowelsignbengali: 0x09CC, + auvowelsigndeva: 0x094C, + auvowelsigngujarati: 0x0ACC, + avagrahadeva: 0x093D, + aybarmenian: 0x0561, + ayin: 0x05E2, + ayinaltonehebrew: 0xFB20, + ayinhebrew: 0x05E2, + b: 0x0062, + babengali: 0x09AC, + backslash: 0x005C, + backslashmonospace: 0xFF3C, + badeva: 0x092C, + bagujarati: 0x0AAC, + bagurmukhi: 0x0A2C, + bahiragana: 0x3070, + bahtthai: 0x0E3F, + bakatakana: 0x30D0, + bar: 0x007C, + barmonospace: 0xFF5C, + bbopomofo: 0x3105, + bcircle: 0x24D1, + bdotaccent: 0x1E03, + bdotbelow: 0x1E05, + beamedsixteenthnotes: 0x266C, + because: 0x2235, + becyrillic: 0x0431, + beharabic: 0x0628, + behfinalarabic: 0xFE90, + behinitialarabic: 0xFE91, + behiragana: 0x3079, + behmedialarabic: 0xFE92, + behmeeminitialarabic: 0xFC9F, + behmeemisolatedarabic: 0xFC08, + behnoonfinalarabic: 0xFC6D, + bekatakana: 0x30D9, + benarmenian: 0x0562, + bet: 0x05D1, + beta: 0x03B2, + betasymbolgreek: 0x03D0, + betdagesh: 0xFB31, + betdageshhebrew: 0xFB31, + bethebrew: 0x05D1, + betrafehebrew: 0xFB4C, + bhabengali: 0x09AD, + bhadeva: 0x092D, + bhagujarati: 0x0AAD, + bhagurmukhi: 0x0A2D, + bhook: 0x0253, + bihiragana: 0x3073, + bikatakana: 0x30D3, + bilabialclick: 0x0298, + bindigurmukhi: 0x0A02, + birusquare: 0x3331, + blackcircle: 0x25CF, + blackdiamond: 0x25C6, + blackdownpointingtriangle: 0x25BC, + blackleftpointingpointer: 0x25C4, + blackleftpointingtriangle: 0x25C0, + blacklenticularbracketleft: 0x3010, + blacklenticularbracketleftvertical: 0xFE3B, + blacklenticularbracketright: 0x3011, + blacklenticularbracketrightvertical: 0xFE3C, + blacklowerlefttriangle: 0x25E3, + blacklowerrighttriangle: 0x25E2, + blackrectangle: 0x25AC, + blackrightpointingpointer: 0x25BA, + blackrightpointingtriangle: 0x25B6, + blacksmallsquare: 0x25AA, + blacksmilingface: 0x263B, + blacksquare: 0x25A0, + blackstar: 0x2605, + blackupperlefttriangle: 0x25E4, + blackupperrighttriangle: 0x25E5, + blackuppointingsmalltriangle: 0x25B4, + blackuppointingtriangle: 0x25B2, + blank: 0x2423, + blinebelow: 0x1E07, + block: 0x2588, + bmonospace: 0xFF42, + bobaimaithai: 0x0E1A, + bohiragana: 0x307C, + bokatakana: 0x30DC, + bparen: 0x249D, + bqsquare: 0x33C3, + braceex: 0xF8F4, + braceleft: 0x007B, + braceleftbt: 0xF8F3, + braceleftmid: 0xF8F2, + braceleftmonospace: 0xFF5B, + braceleftsmall: 0xFE5B, + bracelefttp: 0xF8F1, + braceleftvertical: 0xFE37, + braceright: 0x007D, + bracerightbt: 0xF8FE, + bracerightmid: 0xF8FD, + bracerightmonospace: 0xFF5D, + bracerightsmall: 0xFE5C, + bracerighttp: 0xF8FC, + bracerightvertical: 0xFE38, + bracketleft: 0x005B, + bracketleftbt: 0xF8F0, + bracketleftex: 0xF8EF, + bracketleftmonospace: 0xFF3B, + bracketlefttp: 0xF8EE, + bracketright: 0x005D, + bracketrightbt: 0xF8FB, + bracketrightex: 0xF8FA, + bracketrightmonospace: 0xFF3D, + bracketrighttp: 0xF8F9, + breve: 0x02D8, + brevebelowcmb: 0x032E, + brevecmb: 0x0306, + breveinvertedbelowcmb: 0x032F, + breveinvertedcmb: 0x0311, + breveinverteddoublecmb: 0x0361, + bridgebelowcmb: 0x032A, + bridgeinvertedbelowcmb: 0x033A, + brokenbar: 0x00A6, + bstroke: 0x0180, + bsuperior: 0xF6EA, + btopbar: 0x0183, + buhiragana: 0x3076, + bukatakana: 0x30D6, + bullet: 0x2022, + bulletinverse: 0x25D8, + bulletoperator: 0x2219, + bullseye: 0x25CE, + c: 0x0063, + caarmenian: 0x056E, + cabengali: 0x099A, + cacute: 0x0107, + cadeva: 0x091A, + cagujarati: 0x0A9A, + cagurmukhi: 0x0A1A, + calsquare: 0x3388, + candrabindubengali: 0x0981, + candrabinducmb: 0x0310, + candrabindudeva: 0x0901, + candrabindugujarati: 0x0A81, + capslock: 0x21EA, + careof: 0x2105, + caron: 0x02C7, + caronbelowcmb: 0x032C, + caroncmb: 0x030C, + carriagereturn: 0x21B5, + cbopomofo: 0x3118, + ccaron: 0x010D, + ccedilla: 0x00E7, + ccedillaacute: 0x1E09, + ccircle: 0x24D2, + ccircumflex: 0x0109, + ccurl: 0x0255, + cdot: 0x010B, + cdotaccent: 0x010B, + cdsquare: 0x33C5, + cedilla: 0x00B8, + cedillacmb: 0x0327, + cent: 0x00A2, + centigrade: 0x2103, + centinferior: 0xF6DF, + centmonospace: 0xFFE0, + centoldstyle: 0xF7A2, + centsuperior: 0xF6E0, + chaarmenian: 0x0579, + chabengali: 0x099B, + chadeva: 0x091B, + chagujarati: 0x0A9B, + chagurmukhi: 0x0A1B, + chbopomofo: 0x3114, + cheabkhasiancyrillic: 0x04BD, + checkmark: 0x2713, + checyrillic: 0x0447, + chedescenderabkhasiancyrillic: 0x04BF, + chedescendercyrillic: 0x04B7, + chedieresiscyrillic: 0x04F5, + cheharmenian: 0x0573, + chekhakassiancyrillic: 0x04CC, + cheverticalstrokecyrillic: 0x04B9, + chi: 0x03C7, + chieuchacirclekorean: 0x3277, + chieuchaparenkorean: 0x3217, + chieuchcirclekorean: 0x3269, + chieuchkorean: 0x314A, + chieuchparenkorean: 0x3209, + chochangthai: 0x0E0A, + chochanthai: 0x0E08, + chochingthai: 0x0E09, + chochoethai: 0x0E0C, + chook: 0x0188, + cieucacirclekorean: 0x3276, + cieucaparenkorean: 0x3216, + cieuccirclekorean: 0x3268, + cieuckorean: 0x3148, + cieucparenkorean: 0x3208, + cieucuparenkorean: 0x321C, + circle: 0x25CB, + circlemultiply: 0x2297, + circleot: 0x2299, + circleplus: 0x2295, + circlepostalmark: 0x3036, + circlewithlefthalfblack: 0x25D0, + circlewithrighthalfblack: 0x25D1, + circumflex: 0x02C6, + circumflexbelowcmb: 0x032D, + circumflexcmb: 0x0302, + clear: 0x2327, + clickalveolar: 0x01C2, + clickdental: 0x01C0, + clicklateral: 0x01C1, + clickretroflex: 0x01C3, + club: 0x2663, + clubsuitblack: 0x2663, + clubsuitwhite: 0x2667, + cmcubedsquare: 0x33A4, + cmonospace: 0xFF43, + cmsquaredsquare: 0x33A0, + coarmenian: 0x0581, + colon: 0x003A, + colonmonetary: 0x20A1, + colonmonospace: 0xFF1A, + colonsign: 0x20A1, + colonsmall: 0xFE55, + colontriangularhalfmod: 0x02D1, + colontriangularmod: 0x02D0, + comma: 0x002C, + commaabovecmb: 0x0313, + commaaboverightcmb: 0x0315, + commaaccent: 0xF6C3, + commaarabic: 0x060C, + commaarmenian: 0x055D, + commainferior: 0xF6E1, + commamonospace: 0xFF0C, + commareversedabovecmb: 0x0314, + commareversedmod: 0x02BD, + commasmall: 0xFE50, + commasuperior: 0xF6E2, + commaturnedabovecmb: 0x0312, + commaturnedmod: 0x02BB, + compass: 0x263C, + congruent: 0x2245, + contourintegral: 0x222E, + control: 0x2303, + controlACK: 0x0006, + controlBEL: 0x0007, + controlBS: 0x0008, + controlCAN: 0x0018, + controlCR: 0x000D, + controlDC1: 0x0011, + controlDC2: 0x0012, + controlDC3: 0x0013, + controlDC4: 0x0014, + controlDEL: 0x007F, + controlDLE: 0x0010, + controlEM: 0x0019, + controlENQ: 0x0005, + controlEOT: 0x0004, + controlESC: 0x001B, + controlETB: 0x0017, + controlETX: 0x0003, + controlFF: 0x000C, + controlFS: 0x001C, + controlGS: 0x001D, + controlHT: 0x0009, + controlLF: 0x000A, + controlNAK: 0x0015, + controlRS: 0x001E, + controlSI: 0x000F, + controlSO: 0x000E, + controlSOT: 0x0002, + controlSTX: 0x0001, + controlSUB: 0x001A, + controlSYN: 0x0016, + controlUS: 0x001F, + controlVT: 0x000B, + copyright: 0x00A9, + copyrightsans: 0xF8E9, + copyrightserif: 0xF6D9, + cornerbracketleft: 0x300C, + cornerbracketlefthalfwidth: 0xFF62, + cornerbracketleftvertical: 0xFE41, + cornerbracketright: 0x300D, + cornerbracketrighthalfwidth: 0xFF63, + cornerbracketrightvertical: 0xFE42, + corporationsquare: 0x337F, + cosquare: 0x33C7, + coverkgsquare: 0x33C6, + cparen: 0x249E, + cruzeiro: 0x20A2, + cstretched: 0x0297, + curlyand: 0x22CF, + curlyor: 0x22CE, + currency: 0x00A4, + cyrBreve: 0xF6D1, + cyrFlex: 0xF6D2, + cyrbreve: 0xF6D4, + cyrflex: 0xF6D5, + d: 0x0064, + daarmenian: 0x0564, + dabengali: 0x09A6, + dadarabic: 0x0636, + dadeva: 0x0926, + dadfinalarabic: 0xFEBE, + dadinitialarabic: 0xFEBF, + dadmedialarabic: 0xFEC0, + dagesh: 0x05BC, + dageshhebrew: 0x05BC, + dagger: 0x2020, + daggerdbl: 0x2021, + dagujarati: 0x0AA6, + dagurmukhi: 0x0A26, + dahiragana: 0x3060, + dakatakana: 0x30C0, + dalarabic: 0x062F, + dalet: 0x05D3, + daletdagesh: 0xFB33, + daletdageshhebrew: 0xFB33, dalethatafpatah: "05D3 05B2", dalethatafpatahhebrew: "05D3 05B2", dalethatafsegol: "05D3 05B1", dalethatafsegolhebrew: "05D3 05B1", - dalethebrew: "05D3", + dalethebrew: 0x05D3, dalethiriq: "05D3 05B4", dalethiriqhebrew: "05D3 05B4", daletholam: "05D3 05B9", @@ -1521,1641 +1521,1641 @@ var GlyphsUnicode = { daletshevahebrew: "05D3 05B0", dalettsere: "05D3 05B5", dalettserehebrew: "05D3 05B5", - dalfinalarabic: "FEAA", - dammaarabic: "064F", - dammalowarabic: "064F", - dammatanaltonearabic: "064C", - dammatanarabic: "064C", - danda: "0964", - dargahebrew: "05A7", - dargalefthebrew: "05A7", - dasiapneumatacyrilliccmb: "0485", - dblGrave: "F6D3", - dblanglebracketleft: "300A", - dblanglebracketleftvertical: "FE3D", - dblanglebracketright: "300B", - dblanglebracketrightvertical: "FE3E", - dblarchinvertedbelowcmb: "032B", - dblarrowleft: "21D4", - dblarrowright: "21D2", - dbldanda: "0965", - dblgrave: "F6D6", - dblgravecmb: "030F", - dblintegral: "222C", - dbllowline: "2017", - dbllowlinecmb: "0333", - dbloverlinecmb: "033F", - dblprimemod: "02BA", - dblverticalbar: "2016", - dblverticallineabovecmb: "030E", - dbopomofo: "3109", - dbsquare: "33C8", - dcaron: "010F", - dcedilla: "1E11", - dcircle: "24D3", - dcircumflexbelow: "1E13", - dcroat: "0111", - ddabengali: "09A1", - ddadeva: "0921", - ddagujarati: "0AA1", - ddagurmukhi: "0A21", - ddalarabic: "0688", - ddalfinalarabic: "FB89", - dddhadeva: "095C", - ddhabengali: "09A2", - ddhadeva: "0922", - ddhagujarati: "0AA2", - ddhagurmukhi: "0A22", - ddotaccent: "1E0B", - ddotbelow: "1E0D", - decimalseparatorarabic: "066B", - decimalseparatorpersian: "066B", - decyrillic: "0434", - degree: "00B0", - dehihebrew: "05AD", - dehiragana: "3067", - deicoptic: "03EF", - dekatakana: "30C7", - deleteleft: "232B", - deleteright: "2326", - delta: "03B4", - deltaturned: "018D", - denominatorminusonenumeratorbengali: "09F8", - dezh: "02A4", - dhabengali: "09A7", - dhadeva: "0927", - dhagujarati: "0AA7", - dhagurmukhi: "0A27", - dhook: "0257", - dialytikatonos: "0385", - dialytikatonoscmb: "0344", - diamond: "2666", - diamondsuitwhite: "2662", - dieresis: "00A8", - dieresisacute: "F6D7", - dieresisbelowcmb: "0324", - dieresiscmb: "0308", - dieresisgrave: "F6D8", - dieresistonos: "0385", - dihiragana: "3062", - dikatakana: "30C2", - dittomark: "3003", - divide: "00F7", - divides: "2223", - divisionslash: "2215", - djecyrillic: "0452", - dkshade: "2593", - dlinebelow: "1E0F", - dlsquare: "3397", - dmacron: "0111", - dmonospace: "FF44", - dnblock: "2584", - dochadathai: "0E0E", - dodekthai: "0E14", - dohiragana: "3069", - dokatakana: "30C9", - dollar: "0024", - dollarinferior: "F6E3", - dollarmonospace: "FF04", - dollaroldstyle: "F724", - dollarsmall: "FE69", - dollarsuperior: "F6E4", - dong: "20AB", - dorusquare: "3326", - dotaccent: "02D9", - dotaccentcmb: "0307", - dotbelowcmb: "0323", - dotbelowcomb: "0323", - dotkatakana: "30FB", - dotlessi: "0131", - dotlessj: "F6BE", - dotlessjstrokehook: "0284", - dotmath: "22C5", - dottedcircle: "25CC", - doubleyodpatah: "FB1F", - doubleyodpatahhebrew: "FB1F", - downtackbelowcmb: "031E", - downtackmod: "02D5", - dparen: "249F", - dsuperior: "F6EB", - dtail: "0256", - dtopbar: "018C", - duhiragana: "3065", - dukatakana: "30C5", - dz: "01F3", - dzaltone: "02A3", - dzcaron: "01C6", - dzcurl: "02A5", - dzeabkhasiancyrillic: "04E1", - dzecyrillic: "0455", - dzhecyrillic: "045F", - e: "0065", - eacute: "00E9", - earth: "2641", - ebengali: "098F", - ebopomofo: "311C", - ebreve: "0115", - ecandradeva: "090D", - ecandragujarati: "0A8D", - ecandravowelsigndeva: "0945", - ecandravowelsigngujarati: "0AC5", - ecaron: "011B", - ecedillabreve: "1E1D", - echarmenian: "0565", - echyiwnarmenian: "0587", - ecircle: "24D4", - ecircumflex: "00EA", - ecircumflexacute: "1EBF", - ecircumflexbelow: "1E19", - ecircumflexdotbelow: "1EC7", - ecircumflexgrave: "1EC1", - ecircumflexhookabove: "1EC3", - ecircumflextilde: "1EC5", - ecyrillic: "0454", - edblgrave: "0205", - edeva: "090F", - edieresis: "00EB", - edot: "0117", - edotaccent: "0117", - edotbelow: "1EB9", - eegurmukhi: "0A0F", - eematragurmukhi: "0A47", - efcyrillic: "0444", - egrave: "00E8", - egujarati: "0A8F", - eharmenian: "0567", - ehbopomofo: "311D", - ehiragana: "3048", - ehookabove: "1EBB", - eibopomofo: "311F", - eight: "0038", - eightarabic: "0668", - eightbengali: "09EE", - eightcircle: "2467", - eightcircleinversesansserif: "2791", - eightdeva: "096E", - eighteencircle: "2471", - eighteenparen: "2485", - eighteenperiod: "2499", - eightgujarati: "0AEE", - eightgurmukhi: "0A6E", - eighthackarabic: "0668", - eighthangzhou: "3028", - eighthnotebeamed: "266B", - eightideographicparen: "3227", - eightinferior: "2088", - eightmonospace: "FF18", - eightoldstyle: "F738", - eightparen: "247B", - eightperiod: "248F", - eightpersian: "06F8", - eightroman: "2177", - eightsuperior: "2078", - eightthai: "0E58", - einvertedbreve: "0207", - eiotifiedcyrillic: "0465", - ekatakana: "30A8", - ekatakanahalfwidth: "FF74", - ekonkargurmukhi: "0A74", - ekorean: "3154", - elcyrillic: "043B", - element: "2208", - elevencircle: "246A", - elevenparen: "247E", - elevenperiod: "2492", - elevenroman: "217A", - ellipsis: "2026", - ellipsisvertical: "22EE", - emacron: "0113", - emacronacute: "1E17", - emacrongrave: "1E15", - emcyrillic: "043C", - emdash: "2014", - emdashvertical: "FE31", - emonospace: "FF45", - emphasismarkarmenian: "055B", - emptyset: "2205", - enbopomofo: "3123", - encyrillic: "043D", - endash: "2013", - endashvertical: "FE32", - endescendercyrillic: "04A3", - eng: "014B", - engbopomofo: "3125", - enghecyrillic: "04A5", - enhookcyrillic: "04C8", - enspace: "2002", - eogonek: "0119", - eokorean: "3153", - eopen: "025B", - eopenclosed: "029A", - eopenreversed: "025C", - eopenreversedclosed: "025E", - eopenreversedhook: "025D", - eparen: "24A0", - epsilon: "03B5", - epsilontonos: "03AD", - equal: "003D", - equalmonospace: "FF1D", - equalsmall: "FE66", - equalsuperior: "207C", - equivalence: "2261", - erbopomofo: "3126", - ercyrillic: "0440", - ereversed: "0258", - ereversedcyrillic: "044D", - escyrillic: "0441", - esdescendercyrillic: "04AB", - esh: "0283", - eshcurl: "0286", - eshortdeva: "090E", - eshortvowelsigndeva: "0946", - eshreversedloop: "01AA", - eshsquatreversed: "0285", - esmallhiragana: "3047", - esmallkatakana: "30A7", - esmallkatakanahalfwidth: "FF6A", - estimated: "212E", - esuperior: "F6EC", - eta: "03B7", - etarmenian: "0568", - etatonos: "03AE", - eth: "00F0", - etilde: "1EBD", - etildebelow: "1E1B", - etnahtafoukhhebrew: "0591", - etnahtafoukhlefthebrew: "0591", - etnahtahebrew: "0591", - etnahtalefthebrew: "0591", - eturned: "01DD", - eukorean: "3161", - euro: "20AC", - evowelsignbengali: "09C7", - evowelsigndeva: "0947", - evowelsigngujarati: "0AC7", - exclam: "0021", - exclamarmenian: "055C", - exclamdbl: "203C", - exclamdown: "00A1", - exclamdownsmall: "F7A1", - exclammonospace: "FF01", - exclamsmall: "F721", - existential: "2203", - ezh: "0292", - ezhcaron: "01EF", - ezhcurl: "0293", - ezhreversed: "01B9", - ezhtail: "01BA", - f: "0066", - fadeva: "095E", - fagurmukhi: "0A5E", - fahrenheit: "2109", - fathaarabic: "064E", - fathalowarabic: "064E", - fathatanarabic: "064B", - fbopomofo: "3108", - fcircle: "24D5", - fdotaccent: "1E1F", - feharabic: "0641", - feharmenian: "0586", - fehfinalarabic: "FED2", - fehinitialarabic: "FED3", - fehmedialarabic: "FED4", - feicoptic: "03E5", - female: "2640", - ff: "FB00", - ffi: "FB03", - ffl: "FB04", - fi: "FB01", - fifteencircle: "246E", - fifteenparen: "2482", - fifteenperiod: "2496", - figuredash: "2012", - filledbox: "25A0", - filledrect: "25AC", - finalkaf: "05DA", - finalkafdagesh: "FB3A", - finalkafdageshhebrew: "FB3A", - finalkafhebrew: "05DA", + dalfinalarabic: 0xFEAA, + dammaarabic: 0x064F, + dammalowarabic: 0x064F, + dammatanaltonearabic: 0x064C, + dammatanarabic: 0x064C, + danda: 0x0964, + dargahebrew: 0x05A7, + dargalefthebrew: 0x05A7, + dasiapneumatacyrilliccmb: 0x0485, + dblGrave: 0xF6D3, + dblanglebracketleft: 0x300A, + dblanglebracketleftvertical: 0xFE3D, + dblanglebracketright: 0x300B, + dblanglebracketrightvertical: 0xFE3E, + dblarchinvertedbelowcmb: 0x032B, + dblarrowleft: 0x21D4, + dblarrowright: 0x21D2, + dbldanda: 0x0965, + dblgrave: 0xF6D6, + dblgravecmb: 0x030F, + dblintegral: 0x222C, + dbllowline: 0x2017, + dbllowlinecmb: 0x0333, + dbloverlinecmb: 0x033F, + dblprimemod: 0x02BA, + dblverticalbar: 0x2016, + dblverticallineabovecmb: 0x030E, + dbopomofo: 0x3109, + dbsquare: 0x33C8, + dcaron: 0x010F, + dcedilla: 0x1E11, + dcircle: 0x24D3, + dcircumflexbelow: 0x1E13, + dcroat: 0x0111, + ddabengali: 0x09A1, + ddadeva: 0x0921, + ddagujarati: 0x0AA1, + ddagurmukhi: 0x0A21, + ddalarabic: 0x0688, + ddalfinalarabic: 0xFB89, + dddhadeva: 0x095C, + ddhabengali: 0x09A2, + ddhadeva: 0x0922, + ddhagujarati: 0x0AA2, + ddhagurmukhi: 0x0A22, + ddotaccent: 0x1E0B, + ddotbelow: 0x1E0D, + decimalseparatorarabic: 0x066B, + decimalseparatorpersian: 0x066B, + decyrillic: 0x0434, + degree: 0x00B0, + dehihebrew: 0x05AD, + dehiragana: 0x3067, + deicoptic: 0x03EF, + dekatakana: 0x30C7, + deleteleft: 0x232B, + deleteright: 0x2326, + delta: 0x03B4, + deltaturned: 0x018D, + denominatorminusonenumeratorbengali: 0x09F8, + dezh: 0x02A4, + dhabengali: 0x09A7, + dhadeva: 0x0927, + dhagujarati: 0x0AA7, + dhagurmukhi: 0x0A27, + dhook: 0x0257, + dialytikatonos: 0x0385, + dialytikatonoscmb: 0x0344, + diamond: 0x2666, + diamondsuitwhite: 0x2662, + dieresis: 0x00A8, + dieresisacute: 0xF6D7, + dieresisbelowcmb: 0x0324, + dieresiscmb: 0x0308, + dieresisgrave: 0xF6D8, + dieresistonos: 0x0385, + dihiragana: 0x3062, + dikatakana: 0x30C2, + dittomark: 0x3003, + divide: 0x00F7, + divides: 0x2223, + divisionslash: 0x2215, + djecyrillic: 0x0452, + dkshade: 0x2593, + dlinebelow: 0x1E0F, + dlsquare: 0x3397, + dmacron: 0x0111, + dmonospace: 0xFF44, + dnblock: 0x2584, + dochadathai: 0x0E0E, + dodekthai: 0x0E14, + dohiragana: 0x3069, + dokatakana: 0x30C9, + dollar: 0x0024, + dollarinferior: 0xF6E3, + dollarmonospace: 0xFF04, + dollaroldstyle: 0xF724, + dollarsmall: 0xFE69, + dollarsuperior: 0xF6E4, + dong: 0x20AB, + dorusquare: 0x3326, + dotaccent: 0x02D9, + dotaccentcmb: 0x0307, + dotbelowcmb: 0x0323, + dotbelowcomb: 0x0323, + dotkatakana: 0x30FB, + dotlessi: 0x0131, + dotlessj: 0xF6BE, + dotlessjstrokehook: 0x0284, + dotmath: 0x22C5, + dottedcircle: 0x25CC, + doubleyodpatah: 0xFB1F, + doubleyodpatahhebrew: 0xFB1F, + downtackbelowcmb: 0x031E, + downtackmod: 0x02D5, + dparen: 0x249F, + dsuperior: 0xF6EB, + dtail: 0x0256, + dtopbar: 0x018C, + duhiragana: 0x3065, + dukatakana: 0x30C5, + dz: 0x01F3, + dzaltone: 0x02A3, + dzcaron: 0x01C6, + dzcurl: 0x02A5, + dzeabkhasiancyrillic: 0x04E1, + dzecyrillic: 0x0455, + dzhecyrillic: 0x045F, + e: 0x0065, + eacute: 0x00E9, + earth: 0x2641, + ebengali: 0x098F, + ebopomofo: 0x311C, + ebreve: 0x0115, + ecandradeva: 0x090D, + ecandragujarati: 0x0A8D, + ecandravowelsigndeva: 0x0945, + ecandravowelsigngujarati: 0x0AC5, + ecaron: 0x011B, + ecedillabreve: 0x1E1D, + echarmenian: 0x0565, + echyiwnarmenian: 0x0587, + ecircle: 0x24D4, + ecircumflex: 0x00EA, + ecircumflexacute: 0x1EBF, + ecircumflexbelow: 0x1E19, + ecircumflexdotbelow: 0x1EC7, + ecircumflexgrave: 0x1EC1, + ecircumflexhookabove: 0x1EC3, + ecircumflextilde: 0x1EC5, + ecyrillic: 0x0454, + edblgrave: 0x0205, + edeva: 0x090F, + edieresis: 0x00EB, + edot: 0x0117, + edotaccent: 0x0117, + edotbelow: 0x1EB9, + eegurmukhi: 0x0A0F, + eematragurmukhi: 0x0A47, + efcyrillic: 0x0444, + egrave: 0x00E8, + egujarati: 0x0A8F, + eharmenian: 0x0567, + ehbopomofo: 0x311D, + ehiragana: 0x3048, + ehookabove: 0x1EBB, + eibopomofo: 0x311F, + eight: 0x0038, + eightarabic: 0x0668, + eightbengali: 0x09EE, + eightcircle: 0x2467, + eightcircleinversesansserif: 0x2791, + eightdeva: 0x096E, + eighteencircle: 0x2471, + eighteenparen: 0x2485, + eighteenperiod: 0x2499, + eightgujarati: 0x0AEE, + eightgurmukhi: 0x0A6E, + eighthackarabic: 0x0668, + eighthangzhou: 0x3028, + eighthnotebeamed: 0x266B, + eightideographicparen: 0x3227, + eightinferior: 0x2088, + eightmonospace: 0xFF18, + eightoldstyle: 0xF738, + eightparen: 0x247B, + eightperiod: 0x248F, + eightpersian: 0x06F8, + eightroman: 0x2177, + eightsuperior: 0x2078, + eightthai: 0x0E58, + einvertedbreve: 0x0207, + eiotifiedcyrillic: 0x0465, + ekatakana: 0x30A8, + ekatakanahalfwidth: 0xFF74, + ekonkargurmukhi: 0x0A74, + ekorean: 0x3154, + elcyrillic: 0x043B, + element: 0x2208, + elevencircle: 0x246A, + elevenparen: 0x247E, + elevenperiod: 0x2492, + elevenroman: 0x217A, + ellipsis: 0x2026, + ellipsisvertical: 0x22EE, + emacron: 0x0113, + emacronacute: 0x1E17, + emacrongrave: 0x1E15, + emcyrillic: 0x043C, + emdash: 0x2014, + emdashvertical: 0xFE31, + emonospace: 0xFF45, + emphasismarkarmenian: 0x055B, + emptyset: 0x2205, + enbopomofo: 0x3123, + encyrillic: 0x043D, + endash: 0x2013, + endashvertical: 0xFE32, + endescendercyrillic: 0x04A3, + eng: 0x014B, + engbopomofo: 0x3125, + enghecyrillic: 0x04A5, + enhookcyrillic: 0x04C8, + enspace: 0x2002, + eogonek: 0x0119, + eokorean: 0x3153, + eopen: 0x025B, + eopenclosed: 0x029A, + eopenreversed: 0x025C, + eopenreversedclosed: 0x025E, + eopenreversedhook: 0x025D, + eparen: 0x24A0, + epsilon: 0x03B5, + epsilontonos: 0x03AD, + equal: 0x003D, + equalmonospace: 0xFF1D, + equalsmall: 0xFE66, + equalsuperior: 0x207C, + equivalence: 0x2261, + erbopomofo: 0x3126, + ercyrillic: 0x0440, + ereversed: 0x0258, + ereversedcyrillic: 0x044D, + escyrillic: 0x0441, + esdescendercyrillic: 0x04AB, + esh: 0x0283, + eshcurl: 0x0286, + eshortdeva: 0x090E, + eshortvowelsigndeva: 0x0946, + eshreversedloop: 0x01AA, + eshsquatreversed: 0x0285, + esmallhiragana: 0x3047, + esmallkatakana: 0x30A7, + esmallkatakanahalfwidth: 0xFF6A, + estimated: 0x212E, + esuperior: 0xF6EC, + eta: 0x03B7, + etarmenian: 0x0568, + etatonos: 0x03AE, + eth: 0x00F0, + etilde: 0x1EBD, + etildebelow: 0x1E1B, + etnahtafoukhhebrew: 0x0591, + etnahtafoukhlefthebrew: 0x0591, + etnahtahebrew: 0x0591, + etnahtalefthebrew: 0x0591, + eturned: 0x01DD, + eukorean: 0x3161, + euro: 0x20AC, + evowelsignbengali: 0x09C7, + evowelsigndeva: 0x0947, + evowelsigngujarati: 0x0AC7, + exclam: 0x0021, + exclamarmenian: 0x055C, + exclamdbl: 0x203C, + exclamdown: 0x00A1, + exclamdownsmall: 0xF7A1, + exclammonospace: 0xFF01, + exclamsmall: 0xF721, + existential: 0x2203, + ezh: 0x0292, + ezhcaron: 0x01EF, + ezhcurl: 0x0293, + ezhreversed: 0x01B9, + ezhtail: 0x01BA, + f: 0x0066, + fadeva: 0x095E, + fagurmukhi: 0x0A5E, + fahrenheit: 0x2109, + fathaarabic: 0x064E, + fathalowarabic: 0x064E, + fathatanarabic: 0x064B, + fbopomofo: 0x3108, + fcircle: 0x24D5, + fdotaccent: 0x1E1F, + feharabic: 0x0641, + feharmenian: 0x0586, + fehfinalarabic: 0xFED2, + fehinitialarabic: 0xFED3, + fehmedialarabic: 0xFED4, + feicoptic: 0x03E5, + female: 0x2640, + ff: 0xFB00, + ffi: 0xFB03, + ffl: 0xFB04, + fi: 0xFB01, + fifteencircle: 0x246E, + fifteenparen: 0x2482, + fifteenperiod: 0x2496, + figuredash: 0x2012, + filledbox: 0x25A0, + filledrect: 0x25AC, + finalkaf: 0x05DA, + finalkafdagesh: 0xFB3A, + finalkafdageshhebrew: 0xFB3A, + finalkafhebrew: 0x05DA, finalkafqamats: "05DA 05B8", finalkafqamatshebrew: "05DA 05B8", finalkafsheva: "05DA 05B0", finalkafshevahebrew: "05DA 05B0", - finalmem: "05DD", - finalmemhebrew: "05DD", - finalnun: "05DF", - finalnunhebrew: "05DF", - finalpe: "05E3", - finalpehebrew: "05E3", - finaltsadi: "05E5", - finaltsadihebrew: "05E5", - firsttonechinese: "02C9", - fisheye: "25C9", - fitacyrillic: "0473", - five: "0035", - fivearabic: "0665", - fivebengali: "09EB", - fivecircle: "2464", - fivecircleinversesansserif: "278E", - fivedeva: "096B", - fiveeighths: "215D", - fivegujarati: "0AEB", - fivegurmukhi: "0A6B", - fivehackarabic: "0665", - fivehangzhou: "3025", - fiveideographicparen: "3224", - fiveinferior: "2085", - fivemonospace: "FF15", - fiveoldstyle: "F735", - fiveparen: "2478", - fiveperiod: "248C", - fivepersian: "06F5", - fiveroman: "2174", - fivesuperior: "2075", - fivethai: "0E55", - fl: "FB02", - florin: "0192", - fmonospace: "FF46", - fmsquare: "3399", - fofanthai: "0E1F", - fofathai: "0E1D", - fongmanthai: "0E4F", - forall: "2200", - four: "0034", - fourarabic: "0664", - fourbengali: "09EA", - fourcircle: "2463", - fourcircleinversesansserif: "278D", - fourdeva: "096A", - fourgujarati: "0AEA", - fourgurmukhi: "0A6A", - fourhackarabic: "0664", - fourhangzhou: "3024", - fourideographicparen: "3223", - fourinferior: "2084", - fourmonospace: "FF14", - fournumeratorbengali: "09F7", - fouroldstyle: "F734", - fourparen: "2477", - fourperiod: "248B", - fourpersian: "06F4", - fourroman: "2173", - foursuperior: "2074", - fourteencircle: "246D", - fourteenparen: "2481", - fourteenperiod: "2495", - fourthai: "0E54", - fourthtonechinese: "02CB", - fparen: "24A1", - fraction: "2044", - franc: "20A3", - g: "0067", - gabengali: "0997", - gacute: "01F5", - gadeva: "0917", - gafarabic: "06AF", - gaffinalarabic: "FB93", - gafinitialarabic: "FB94", - gafmedialarabic: "FB95", - gagujarati: "0A97", - gagurmukhi: "0A17", - gahiragana: "304C", - gakatakana: "30AC", - gamma: "03B3", - gammalatinsmall: "0263", - gammasuperior: "02E0", - gangiacoptic: "03EB", - gbopomofo: "310D", - gbreve: "011F", - gcaron: "01E7", - gcedilla: "0123", - gcircle: "24D6", - gcircumflex: "011D", - gcommaaccent: "0123", - gdot: "0121", - gdotaccent: "0121", - gecyrillic: "0433", - gehiragana: "3052", - gekatakana: "30B2", - geometricallyequal: "2251", - gereshaccenthebrew: "059C", - gereshhebrew: "05F3", - gereshmuqdamhebrew: "059D", - germandbls: "00DF", - gershayimaccenthebrew: "059E", - gershayimhebrew: "05F4", - getamark: "3013", - ghabengali: "0998", - ghadarmenian: "0572", - ghadeva: "0918", - ghagujarati: "0A98", - ghagurmukhi: "0A18", - ghainarabic: "063A", - ghainfinalarabic: "FECE", - ghaininitialarabic: "FECF", - ghainmedialarabic: "FED0", - ghemiddlehookcyrillic: "0495", - ghestrokecyrillic: "0493", - gheupturncyrillic: "0491", - ghhadeva: "095A", - ghhagurmukhi: "0A5A", - ghook: "0260", - ghzsquare: "3393", - gihiragana: "304E", - gikatakana: "30AE", - gimarmenian: "0563", - gimel: "05D2", - gimeldagesh: "FB32", - gimeldageshhebrew: "FB32", - gimelhebrew: "05D2", - gjecyrillic: "0453", - glottalinvertedstroke: "01BE", - glottalstop: "0294", - glottalstopinverted: "0296", - glottalstopmod: "02C0", - glottalstopreversed: "0295", - glottalstopreversedmod: "02C1", - glottalstopreversedsuperior: "02E4", - glottalstopstroke: "02A1", - glottalstopstrokereversed: "02A2", - gmacron: "1E21", - gmonospace: "FF47", - gohiragana: "3054", - gokatakana: "30B4", - gparen: "24A2", - gpasquare: "33AC", - gradient: "2207", - grave: "0060", - gravebelowcmb: "0316", - gravecmb: "0300", - gravecomb: "0300", - gravedeva: "0953", - gravelowmod: "02CE", - gravemonospace: "FF40", - gravetonecmb: "0340", - greater: "003E", - greaterequal: "2265", - greaterequalorless: "22DB", - greatermonospace: "FF1E", - greaterorequivalent: "2273", - greaterorless: "2277", - greateroverequal: "2267", - greatersmall: "FE65", - gscript: "0261", - gstroke: "01E5", - guhiragana: "3050", - guillemotleft: "00AB", - guillemotright: "00BB", - guilsinglleft: "2039", - guilsinglright: "203A", - gukatakana: "30B0", - guramusquare: "3318", - gysquare: "33C9", - h: "0068", - haabkhasiancyrillic: "04A9", - haaltonearabic: "06C1", - habengali: "09B9", - hadescendercyrillic: "04B3", - hadeva: "0939", - hagujarati: "0AB9", - hagurmukhi: "0A39", - haharabic: "062D", - hahfinalarabic: "FEA2", - hahinitialarabic: "FEA3", - hahiragana: "306F", - hahmedialarabic: "FEA4", - haitusquare: "332A", - hakatakana: "30CF", - hakatakanahalfwidth: "FF8A", - halantgurmukhi: "0A4D", - hamzaarabic: "0621", + finalmem: 0x05DD, + finalmemhebrew: 0x05DD, + finalnun: 0x05DF, + finalnunhebrew: 0x05DF, + finalpe: 0x05E3, + finalpehebrew: 0x05E3, + finaltsadi: 0x05E5, + finaltsadihebrew: 0x05E5, + firsttonechinese: 0x02C9, + fisheye: 0x25C9, + fitacyrillic: 0x0473, + five: 0x0035, + fivearabic: 0x0665, + fivebengali: 0x09EB, + fivecircle: 0x2464, + fivecircleinversesansserif: 0x278E, + fivedeva: 0x096B, + fiveeighths: 0x215D, + fivegujarati: 0x0AEB, + fivegurmukhi: 0x0A6B, + fivehackarabic: 0x0665, + fivehangzhou: 0x3025, + fiveideographicparen: 0x3224, + fiveinferior: 0x2085, + fivemonospace: 0xFF15, + fiveoldstyle: 0xF735, + fiveparen: 0x2478, + fiveperiod: 0x248C, + fivepersian: 0x06F5, + fiveroman: 0x2174, + fivesuperior: 0x2075, + fivethai: 0x0E55, + fl: 0xFB02, + florin: 0x0192, + fmonospace: 0xFF46, + fmsquare: 0x3399, + fofanthai: 0x0E1F, + fofathai: 0x0E1D, + fongmanthai: 0x0E4F, + forall: 0x2200, + four: 0x0034, + fourarabic: 0x0664, + fourbengali: 0x09EA, + fourcircle: 0x2463, + fourcircleinversesansserif: 0x278D, + fourdeva: 0x096A, + fourgujarati: 0x0AEA, + fourgurmukhi: 0x0A6A, + fourhackarabic: 0x0664, + fourhangzhou: 0x3024, + fourideographicparen: 0x3223, + fourinferior: 0x2084, + fourmonospace: 0xFF14, + fournumeratorbengali: 0x09F7, + fouroldstyle: 0xF734, + fourparen: 0x2477, + fourperiod: 0x248B, + fourpersian: 0x06F4, + fourroman: 0x2173, + foursuperior: 0x2074, + fourteencircle: 0x246D, + fourteenparen: 0x2481, + fourteenperiod: 0x2495, + fourthai: 0x0E54, + fourthtonechinese: 0x02CB, + fparen: 0x24A1, + fraction: 0x2044, + franc: 0x20A3, + g: 0x0067, + gabengali: 0x0997, + gacute: 0x01F5, + gadeva: 0x0917, + gafarabic: 0x06AF, + gaffinalarabic: 0xFB93, + gafinitialarabic: 0xFB94, + gafmedialarabic: 0xFB95, + gagujarati: 0x0A97, + gagurmukhi: 0x0A17, + gahiragana: 0x304C, + gakatakana: 0x30AC, + gamma: 0x03B3, + gammalatinsmall: 0x0263, + gammasuperior: 0x02E0, + gangiacoptic: 0x03EB, + gbopomofo: 0x310D, + gbreve: 0x011F, + gcaron: 0x01E7, + gcedilla: 0x0123, + gcircle: 0x24D6, + gcircumflex: 0x011D, + gcommaaccent: 0x0123, + gdot: 0x0121, + gdotaccent: 0x0121, + gecyrillic: 0x0433, + gehiragana: 0x3052, + gekatakana: 0x30B2, + geometricallyequal: 0x2251, + gereshaccenthebrew: 0x059C, + gereshhebrew: 0x05F3, + gereshmuqdamhebrew: 0x059D, + germandbls: 0x00DF, + gershayimaccenthebrew: 0x059E, + gershayimhebrew: 0x05F4, + getamark: 0x3013, + ghabengali: 0x0998, + ghadarmenian: 0x0572, + ghadeva: 0x0918, + ghagujarati: 0x0A98, + ghagurmukhi: 0x0A18, + ghainarabic: 0x063A, + ghainfinalarabic: 0xFECE, + ghaininitialarabic: 0xFECF, + ghainmedialarabic: 0xFED0, + ghemiddlehookcyrillic: 0x0495, + ghestrokecyrillic: 0x0493, + gheupturncyrillic: 0x0491, + ghhadeva: 0x095A, + ghhagurmukhi: 0x0A5A, + ghook: 0x0260, + ghzsquare: 0x3393, + gihiragana: 0x304E, + gikatakana: 0x30AE, + gimarmenian: 0x0563, + gimel: 0x05D2, + gimeldagesh: 0xFB32, + gimeldageshhebrew: 0xFB32, + gimelhebrew: 0x05D2, + gjecyrillic: 0x0453, + glottalinvertedstroke: 0x01BE, + glottalstop: 0x0294, + glottalstopinverted: 0x0296, + glottalstopmod: 0x02C0, + glottalstopreversed: 0x0295, + glottalstopreversedmod: 0x02C1, + glottalstopreversedsuperior: 0x02E4, + glottalstopstroke: 0x02A1, + glottalstopstrokereversed: 0x02A2, + gmacron: 0x1E21, + gmonospace: 0xFF47, + gohiragana: 0x3054, + gokatakana: 0x30B4, + gparen: 0x24A2, + gpasquare: 0x33AC, + gradient: 0x2207, + grave: 0x0060, + gravebelowcmb: 0x0316, + gravecmb: 0x0300, + gravecomb: 0x0300, + gravedeva: 0x0953, + gravelowmod: 0x02CE, + gravemonospace: 0xFF40, + gravetonecmb: 0x0340, + greater: 0x003E, + greaterequal: 0x2265, + greaterequalorless: 0x22DB, + greatermonospace: 0xFF1E, + greaterorequivalent: 0x2273, + greaterorless: 0x2277, + greateroverequal: 0x2267, + greatersmall: 0xFE65, + gscript: 0x0261, + gstroke: 0x01E5, + guhiragana: 0x3050, + guillemotleft: 0x00AB, + guillemotright: 0x00BB, + guilsinglleft: 0x2039, + guilsinglright: 0x203A, + gukatakana: 0x30B0, + guramusquare: 0x3318, + gysquare: 0x33C9, + h: 0x0068, + haabkhasiancyrillic: 0x04A9, + haaltonearabic: 0x06C1, + habengali: 0x09B9, + hadescendercyrillic: 0x04B3, + hadeva: 0x0939, + hagujarati: 0x0AB9, + hagurmukhi: 0x0A39, + haharabic: 0x062D, + hahfinalarabic: 0xFEA2, + hahinitialarabic: 0xFEA3, + hahiragana: 0x306F, + hahmedialarabic: 0xFEA4, + haitusquare: 0x332A, + hakatakana: 0x30CF, + hakatakanahalfwidth: 0xFF8A, + halantgurmukhi: 0x0A4D, + hamzaarabic: 0x0621, hamzadammaarabic: "0621 064F", hamzadammatanarabic: "0621 064C", hamzafathaarabic: "0621 064E", hamzafathatanarabic: "0621 064B", - hamzalowarabic: "0621", + hamzalowarabic: 0x0621, hamzalowkasraarabic: "0621 0650", hamzalowkasratanarabic: "0621 064D", hamzasukunarabic: "0621 0652", - hangulfiller: "3164", - hardsigncyrillic: "044A", - harpoonleftbarbup: "21BC", - harpoonrightbarbup: "21C0", - hasquare: "33CA", - hatafpatah: "05B2", - hatafpatah16: "05B2", - hatafpatah23: "05B2", - hatafpatah2f: "05B2", - hatafpatahhebrew: "05B2", - hatafpatahnarrowhebrew: "05B2", - hatafpatahquarterhebrew: "05B2", - hatafpatahwidehebrew: "05B2", - hatafqamats: "05B3", - hatafqamats1b: "05B3", - hatafqamats28: "05B3", - hatafqamats34: "05B3", - hatafqamatshebrew: "05B3", - hatafqamatsnarrowhebrew: "05B3", - hatafqamatsquarterhebrew: "05B3", - hatafqamatswidehebrew: "05B3", - hatafsegol: "05B1", - hatafsegol17: "05B1", - hatafsegol24: "05B1", - hatafsegol30: "05B1", - hatafsegolhebrew: "05B1", - hatafsegolnarrowhebrew: "05B1", - hatafsegolquarterhebrew: "05B1", - hatafsegolwidehebrew: "05B1", - hbar: "0127", - hbopomofo: "310F", - hbrevebelow: "1E2B", - hcedilla: "1E29", - hcircle: "24D7", - hcircumflex: "0125", - hdieresis: "1E27", - hdotaccent: "1E23", - hdotbelow: "1E25", - he: "05D4", - heart: "2665", - heartsuitblack: "2665", - heartsuitwhite: "2661", - hedagesh: "FB34", - hedageshhebrew: "FB34", - hehaltonearabic: "06C1", - heharabic: "0647", - hehebrew: "05D4", - hehfinalaltonearabic: "FBA7", - hehfinalalttwoarabic: "FEEA", - hehfinalarabic: "FEEA", - hehhamzaabovefinalarabic: "FBA5", - hehhamzaaboveisolatedarabic: "FBA4", - hehinitialaltonearabic: "FBA8", - hehinitialarabic: "FEEB", - hehiragana: "3078", - hehmedialaltonearabic: "FBA9", - hehmedialarabic: "FEEC", - heiseierasquare: "337B", - hekatakana: "30D8", - hekatakanahalfwidth: "FF8D", - hekutaarusquare: "3336", - henghook: "0267", - herutusquare: "3339", - het: "05D7", - hethebrew: "05D7", - hhook: "0266", - hhooksuperior: "02B1", - hieuhacirclekorean: "327B", - hieuhaparenkorean: "321B", - hieuhcirclekorean: "326D", - hieuhkorean: "314E", - hieuhparenkorean: "320D", - hihiragana: "3072", - hikatakana: "30D2", - hikatakanahalfwidth: "FF8B", - hiriq: "05B4", - hiriq14: "05B4", - hiriq21: "05B4", - hiriq2d: "05B4", - hiriqhebrew: "05B4", - hiriqnarrowhebrew: "05B4", - hiriqquarterhebrew: "05B4", - hiriqwidehebrew: "05B4", - hlinebelow: "1E96", - hmonospace: "FF48", - hoarmenian: "0570", - hohipthai: "0E2B", - hohiragana: "307B", - hokatakana: "30DB", - hokatakanahalfwidth: "FF8E", - holam: "05B9", - holam19: "05B9", - holam26: "05B9", - holam32: "05B9", - holamhebrew: "05B9", - holamnarrowhebrew: "05B9", - holamquarterhebrew: "05B9", - holamwidehebrew: "05B9", - honokhukthai: "0E2E", - hookabovecomb: "0309", - hookcmb: "0309", - hookpalatalizedbelowcmb: "0321", - hookretroflexbelowcmb: "0322", - hoonsquare: "3342", - horicoptic: "03E9", - horizontalbar: "2015", - horncmb: "031B", - hotsprings: "2668", - house: "2302", - hparen: "24A3", - hsuperior: "02B0", - hturned: "0265", - huhiragana: "3075", - huiitosquare: "3333", - hukatakana: "30D5", - hukatakanahalfwidth: "FF8C", - hungarumlaut: "02DD", - hungarumlautcmb: "030B", - hv: "0195", - hyphen: "002D", - hypheninferior: "F6E5", - hyphenmonospace: "FF0D", - hyphensmall: "FE63", - hyphensuperior: "F6E6", - hyphentwo: "2010", - i: "0069", - iacute: "00ED", - iacyrillic: "044F", - ibengali: "0987", - ibopomofo: "3127", - ibreve: "012D", - icaron: "01D0", - icircle: "24D8", - icircumflex: "00EE", - icyrillic: "0456", - idblgrave: "0209", - ideographearthcircle: "328F", - ideographfirecircle: "328B", - ideographicallianceparen: "323F", - ideographiccallparen: "323A", - ideographiccentrecircle: "32A5", - ideographicclose: "3006", - ideographiccomma: "3001", - ideographiccommaleft: "FF64", - ideographiccongratulationparen: "3237", - ideographiccorrectcircle: "32A3", - ideographicearthparen: "322F", - ideographicenterpriseparen: "323D", - ideographicexcellentcircle: "329D", - ideographicfestivalparen: "3240", - ideographicfinancialcircle: "3296", - ideographicfinancialparen: "3236", - ideographicfireparen: "322B", - ideographichaveparen: "3232", - ideographichighcircle: "32A4", - ideographiciterationmark: "3005", - ideographiclaborcircle: "3298", - ideographiclaborparen: "3238", - ideographicleftcircle: "32A7", - ideographiclowcircle: "32A6", - ideographicmedicinecircle: "32A9", - ideographicmetalparen: "322E", - ideographicmoonparen: "322A", - ideographicnameparen: "3234", - ideographicperiod: "3002", - ideographicprintcircle: "329E", - ideographicreachparen: "3243", - ideographicrepresentparen: "3239", - ideographicresourceparen: "323E", - ideographicrightcircle: "32A8", - ideographicsecretcircle: "3299", - ideographicselfparen: "3242", - ideographicsocietyparen: "3233", - ideographicspace: "3000", - ideographicspecialparen: "3235", - ideographicstockparen: "3231", - ideographicstudyparen: "323B", - ideographicsunparen: "3230", - ideographicsuperviseparen: "323C", - ideographicwaterparen: "322C", - ideographicwoodparen: "322D", - ideographiczero: "3007", - ideographmetalcircle: "328E", - ideographmooncircle: "328A", - ideographnamecircle: "3294", - ideographsuncircle: "3290", - ideographwatercircle: "328C", - ideographwoodcircle: "328D", - ideva: "0907", - idieresis: "00EF", - idieresisacute: "1E2F", - idieresiscyrillic: "04E5", - idotbelow: "1ECB", - iebrevecyrillic: "04D7", - iecyrillic: "0435", - ieungacirclekorean: "3275", - ieungaparenkorean: "3215", - ieungcirclekorean: "3267", - ieungkorean: "3147", - ieungparenkorean: "3207", - igrave: "00EC", - igujarati: "0A87", - igurmukhi: "0A07", - ihiragana: "3044", - ihookabove: "1EC9", - iibengali: "0988", - iicyrillic: "0438", - iideva: "0908", - iigujarati: "0A88", - iigurmukhi: "0A08", - iimatragurmukhi: "0A40", - iinvertedbreve: "020B", - iishortcyrillic: "0439", - iivowelsignbengali: "09C0", - iivowelsigndeva: "0940", - iivowelsigngujarati: "0AC0", - ij: "0133", - ikatakana: "30A4", - ikatakanahalfwidth: "FF72", - ikorean: "3163", - ilde: "02DC", - iluyhebrew: "05AC", - imacron: "012B", - imacroncyrillic: "04E3", - imageorapproximatelyequal: "2253", - imatragurmukhi: "0A3F", - imonospace: "FF49", - increment: "2206", - infinity: "221E", - iniarmenian: "056B", - integral: "222B", - integralbottom: "2321", - integralbt: "2321", - integralex: "F8F5", - integraltop: "2320", - integraltp: "2320", - intersection: "2229", - intisquare: "3305", - invbullet: "25D8", - invcircle: "25D9", - invsmileface: "263B", - iocyrillic: "0451", - iogonek: "012F", - iota: "03B9", - iotadieresis: "03CA", - iotadieresistonos: "0390", - iotalatin: "0269", - iotatonos: "03AF", - iparen: "24A4", - irigurmukhi: "0A72", - ismallhiragana: "3043", - ismallkatakana: "30A3", - ismallkatakanahalfwidth: "FF68", - issharbengali: "09FA", - istroke: "0268", - isuperior: "F6ED", - iterationhiragana: "309D", - iterationkatakana: "30FD", - itilde: "0129", - itildebelow: "1E2D", - iubopomofo: "3129", - iucyrillic: "044E", - ivowelsignbengali: "09BF", - ivowelsigndeva: "093F", - ivowelsigngujarati: "0ABF", - izhitsacyrillic: "0475", - izhitsadblgravecyrillic: "0477", - j: "006A", - jaarmenian: "0571", - jabengali: "099C", - jadeva: "091C", - jagujarati: "0A9C", - jagurmukhi: "0A1C", - jbopomofo: "3110", - jcaron: "01F0", - jcircle: "24D9", - jcircumflex: "0135", - jcrossedtail: "029D", - jdotlessstroke: "025F", - jecyrillic: "0458", - jeemarabic: "062C", - jeemfinalarabic: "FE9E", - jeeminitialarabic: "FE9F", - jeemmedialarabic: "FEA0", - jeharabic: "0698", - jehfinalarabic: "FB8B", - jhabengali: "099D", - jhadeva: "091D", - jhagujarati: "0A9D", - jhagurmukhi: "0A1D", - jheharmenian: "057B", - jis: "3004", - jmonospace: "FF4A", - jparen: "24A5", - jsuperior: "02B2", - k: "006B", - kabashkircyrillic: "04A1", - kabengali: "0995", - kacute: "1E31", - kacyrillic: "043A", - kadescendercyrillic: "049B", - kadeva: "0915", - kaf: "05DB", - kafarabic: "0643", - kafdagesh: "FB3B", - kafdageshhebrew: "FB3B", - kaffinalarabic: "FEDA", - kafhebrew: "05DB", - kafinitialarabic: "FEDB", - kafmedialarabic: "FEDC", - kafrafehebrew: "FB4D", - kagujarati: "0A95", - kagurmukhi: "0A15", - kahiragana: "304B", - kahookcyrillic: "04C4", - kakatakana: "30AB", - kakatakanahalfwidth: "FF76", - kappa: "03BA", - kappasymbolgreek: "03F0", - kapyeounmieumkorean: "3171", - kapyeounphieuphkorean: "3184", - kapyeounpieupkorean: "3178", - kapyeounssangpieupkorean: "3179", - karoriisquare: "330D", - kashidaautoarabic: "0640", - kashidaautonosidebearingarabic: "0640", - kasmallkatakana: "30F5", - kasquare: "3384", - kasraarabic: "0650", - kasratanarabic: "064D", - kastrokecyrillic: "049F", - katahiraprolongmarkhalfwidth: "FF70", - kaverticalstrokecyrillic: "049D", - kbopomofo: "310E", - kcalsquare: "3389", - kcaron: "01E9", - kcedilla: "0137", - kcircle: "24DA", - kcommaaccent: "0137", - kdotbelow: "1E33", - keharmenian: "0584", - kehiragana: "3051", - kekatakana: "30B1", - kekatakanahalfwidth: "FF79", - kenarmenian: "056F", - kesmallkatakana: "30F6", - kgreenlandic: "0138", - khabengali: "0996", - khacyrillic: "0445", - khadeva: "0916", - khagujarati: "0A96", - khagurmukhi: "0A16", - khaharabic: "062E", - khahfinalarabic: "FEA6", - khahinitialarabic: "FEA7", - khahmedialarabic: "FEA8", - kheicoptic: "03E7", - khhadeva: "0959", - khhagurmukhi: "0A59", - khieukhacirclekorean: "3278", - khieukhaparenkorean: "3218", - khieukhcirclekorean: "326A", - khieukhkorean: "314B", - khieukhparenkorean: "320A", - khokhaithai: "0E02", - khokhonthai: "0E05", - khokhuatthai: "0E03", - khokhwaithai: "0E04", - khomutthai: "0E5B", - khook: "0199", - khorakhangthai: "0E06", - khzsquare: "3391", - kihiragana: "304D", - kikatakana: "30AD", - kikatakanahalfwidth: "FF77", - kiroguramusquare: "3315", - kiromeetorusquare: "3316", - kirosquare: "3314", - kiyeokacirclekorean: "326E", - kiyeokaparenkorean: "320E", - kiyeokcirclekorean: "3260", - kiyeokkorean: "3131", - kiyeokparenkorean: "3200", - kiyeoksioskorean: "3133", - kjecyrillic: "045C", - klinebelow: "1E35", - klsquare: "3398", - kmcubedsquare: "33A6", - kmonospace: "FF4B", - kmsquaredsquare: "33A2", - kohiragana: "3053", - kohmsquare: "33C0", - kokaithai: "0E01", - kokatakana: "30B3", - kokatakanahalfwidth: "FF7A", - kooposquare: "331E", - koppacyrillic: "0481", - koreanstandardsymbol: "327F", - koroniscmb: "0343", - kparen: "24A6", - kpasquare: "33AA", - ksicyrillic: "046F", - ktsquare: "33CF", - kturned: "029E", - kuhiragana: "304F", - kukatakana: "30AF", - kukatakanahalfwidth: "FF78", - kvsquare: "33B8", - kwsquare: "33BE", - l: "006C", - labengali: "09B2", - lacute: "013A", - ladeva: "0932", - lagujarati: "0AB2", - lagurmukhi: "0A32", - lakkhangyaothai: "0E45", - lamaleffinalarabic: "FEFC", - lamalefhamzaabovefinalarabic: "FEF8", - lamalefhamzaaboveisolatedarabic: "FEF7", - lamalefhamzabelowfinalarabic: "FEFA", - lamalefhamzabelowisolatedarabic: "FEF9", - lamalefisolatedarabic: "FEFB", - lamalefmaddaabovefinalarabic: "FEF6", - lamalefmaddaaboveisolatedarabic: "FEF5", - lamarabic: "0644", - lambda: "03BB", - lambdastroke: "019B", - lamed: "05DC", - lameddagesh: "FB3C", - lameddageshhebrew: "FB3C", - lamedhebrew: "05DC", + hangulfiller: 0x3164, + hardsigncyrillic: 0x044A, + harpoonleftbarbup: 0x21BC, + harpoonrightbarbup: 0x21C0, + hasquare: 0x33CA, + hatafpatah: 0x05B2, + hatafpatah16: 0x05B2, + hatafpatah23: 0x05B2, + hatafpatah2f: 0x05B2, + hatafpatahhebrew: 0x05B2, + hatafpatahnarrowhebrew: 0x05B2, + hatafpatahquarterhebrew: 0x05B2, + hatafpatahwidehebrew: 0x05B2, + hatafqamats: 0x05B3, + hatafqamats1b: 0x05B3, + hatafqamats28: 0x05B3, + hatafqamats34: 0x05B3, + hatafqamatshebrew: 0x05B3, + hatafqamatsnarrowhebrew: 0x05B3, + hatafqamatsquarterhebrew: 0x05B3, + hatafqamatswidehebrew: 0x05B3, + hatafsegol: 0x05B1, + hatafsegol17: 0x05B1, + hatafsegol24: 0x05B1, + hatafsegol30: 0x05B1, + hatafsegolhebrew: 0x05B1, + hatafsegolnarrowhebrew: 0x05B1, + hatafsegolquarterhebrew: 0x05B1, + hatafsegolwidehebrew: 0x05B1, + hbar: 0x0127, + hbopomofo: 0x310F, + hbrevebelow: 0x1E2B, + hcedilla: 0x1E29, + hcircle: 0x24D7, + hcircumflex: 0x0125, + hdieresis: 0x1E27, + hdotaccent: 0x1E23, + hdotbelow: 0x1E25, + he: 0x05D4, + heart: 0x2665, + heartsuitblack: 0x2665, + heartsuitwhite: 0x2661, + hedagesh: 0xFB34, + hedageshhebrew: 0xFB34, + hehaltonearabic: 0x06C1, + heharabic: 0x0647, + hehebrew: 0x05D4, + hehfinalaltonearabic: 0xFBA7, + hehfinalalttwoarabic: 0xFEEA, + hehfinalarabic: 0xFEEA, + hehhamzaabovefinalarabic: 0xFBA5, + hehhamzaaboveisolatedarabic: 0xFBA4, + hehinitialaltonearabic: 0xFBA8, + hehinitialarabic: 0xFEEB, + hehiragana: 0x3078, + hehmedialaltonearabic: 0xFBA9, + hehmedialarabic: 0xFEEC, + heiseierasquare: 0x337B, + hekatakana: 0x30D8, + hekatakanahalfwidth: 0xFF8D, + hekutaarusquare: 0x3336, + henghook: 0x0267, + herutusquare: 0x3339, + het: 0x05D7, + hethebrew: 0x05D7, + hhook: 0x0266, + hhooksuperior: 0x02B1, + hieuhacirclekorean: 0x327B, + hieuhaparenkorean: 0x321B, + hieuhcirclekorean: 0x326D, + hieuhkorean: 0x314E, + hieuhparenkorean: 0x320D, + hihiragana: 0x3072, + hikatakana: 0x30D2, + hikatakanahalfwidth: 0xFF8B, + hiriq: 0x05B4, + hiriq14: 0x05B4, + hiriq21: 0x05B4, + hiriq2d: 0x05B4, + hiriqhebrew: 0x05B4, + hiriqnarrowhebrew: 0x05B4, + hiriqquarterhebrew: 0x05B4, + hiriqwidehebrew: 0x05B4, + hlinebelow: 0x1E96, + hmonospace: 0xFF48, + hoarmenian: 0x0570, + hohipthai: 0x0E2B, + hohiragana: 0x307B, + hokatakana: 0x30DB, + hokatakanahalfwidth: 0xFF8E, + holam: 0x05B9, + holam19: 0x05B9, + holam26: 0x05B9, + holam32: 0x05B9, + holamhebrew: 0x05B9, + holamnarrowhebrew: 0x05B9, + holamquarterhebrew: 0x05B9, + holamwidehebrew: 0x05B9, + honokhukthai: 0x0E2E, + hookabovecomb: 0x0309, + hookcmb: 0x0309, + hookpalatalizedbelowcmb: 0x0321, + hookretroflexbelowcmb: 0x0322, + hoonsquare: 0x3342, + horicoptic: 0x03E9, + horizontalbar: 0x2015, + horncmb: 0x031B, + hotsprings: 0x2668, + house: 0x2302, + hparen: 0x24A3, + hsuperior: 0x02B0, + hturned: 0x0265, + huhiragana: 0x3075, + huiitosquare: 0x3333, + hukatakana: 0x30D5, + hukatakanahalfwidth: 0xFF8C, + hungarumlaut: 0x02DD, + hungarumlautcmb: 0x030B, + hv: 0x0195, + hyphen: 0x002D, + hypheninferior: 0xF6E5, + hyphenmonospace: 0xFF0D, + hyphensmall: 0xFE63, + hyphensuperior: 0xF6E6, + hyphentwo: 0x2010, + i: 0x0069, + iacute: 0x00ED, + iacyrillic: 0x044F, + ibengali: 0x0987, + ibopomofo: 0x3127, + ibreve: 0x012D, + icaron: 0x01D0, + icircle: 0x24D8, + icircumflex: 0x00EE, + icyrillic: 0x0456, + idblgrave: 0x0209, + ideographearthcircle: 0x328F, + ideographfirecircle: 0x328B, + ideographicallianceparen: 0x323F, + ideographiccallparen: 0x323A, + ideographiccentrecircle: 0x32A5, + ideographicclose: 0x3006, + ideographiccomma: 0x3001, + ideographiccommaleft: 0xFF64, + ideographiccongratulationparen: 0x3237, + ideographiccorrectcircle: 0x32A3, + ideographicearthparen: 0x322F, + ideographicenterpriseparen: 0x323D, + ideographicexcellentcircle: 0x329D, + ideographicfestivalparen: 0x3240, + ideographicfinancialcircle: 0x3296, + ideographicfinancialparen: 0x3236, + ideographicfireparen: 0x322B, + ideographichaveparen: 0x3232, + ideographichighcircle: 0x32A4, + ideographiciterationmark: 0x3005, + ideographiclaborcircle: 0x3298, + ideographiclaborparen: 0x3238, + ideographicleftcircle: 0x32A7, + ideographiclowcircle: 0x32A6, + ideographicmedicinecircle: 0x32A9, + ideographicmetalparen: 0x322E, + ideographicmoonparen: 0x322A, + ideographicnameparen: 0x3234, + ideographicperiod: 0x3002, + ideographicprintcircle: 0x329E, + ideographicreachparen: 0x3243, + ideographicrepresentparen: 0x3239, + ideographicresourceparen: 0x323E, + ideographicrightcircle: 0x32A8, + ideographicsecretcircle: 0x3299, + ideographicselfparen: 0x3242, + ideographicsocietyparen: 0x3233, + ideographicspace: 0x3000, + ideographicspecialparen: 0x3235, + ideographicstockparen: 0x3231, + ideographicstudyparen: 0x323B, + ideographicsunparen: 0x3230, + ideographicsuperviseparen: 0x323C, + ideographicwaterparen: 0x322C, + ideographicwoodparen: 0x322D, + ideographiczero: 0x3007, + ideographmetalcircle: 0x328E, + ideographmooncircle: 0x328A, + ideographnamecircle: 0x3294, + ideographsuncircle: 0x3290, + ideographwatercircle: 0x328C, + ideographwoodcircle: 0x328D, + ideva: 0x0907, + idieresis: 0x00EF, + idieresisacute: 0x1E2F, + idieresiscyrillic: 0x04E5, + idotbelow: 0x1ECB, + iebrevecyrillic: 0x04D7, + iecyrillic: 0x0435, + ieungacirclekorean: 0x3275, + ieungaparenkorean: 0x3215, + ieungcirclekorean: 0x3267, + ieungkorean: 0x3147, + ieungparenkorean: 0x3207, + igrave: 0x00EC, + igujarati: 0x0A87, + igurmukhi: 0x0A07, + ihiragana: 0x3044, + ihookabove: 0x1EC9, + iibengali: 0x0988, + iicyrillic: 0x0438, + iideva: 0x0908, + iigujarati: 0x0A88, + iigurmukhi: 0x0A08, + iimatragurmukhi: 0x0A40, + iinvertedbreve: 0x020B, + iishortcyrillic: 0x0439, + iivowelsignbengali: 0x09C0, + iivowelsigndeva: 0x0940, + iivowelsigngujarati: 0x0AC0, + ij: 0x0133, + ikatakana: 0x30A4, + ikatakanahalfwidth: 0xFF72, + ikorean: 0x3163, + ilde: 0x02DC, + iluyhebrew: 0x05AC, + imacron: 0x012B, + imacroncyrillic: 0x04E3, + imageorapproximatelyequal: 0x2253, + imatragurmukhi: 0x0A3F, + imonospace: 0xFF49, + increment: 0x2206, + infinity: 0x221E, + iniarmenian: 0x056B, + integral: 0x222B, + integralbottom: 0x2321, + integralbt: 0x2321, + integralex: 0xF8F5, + integraltop: 0x2320, + integraltp: 0x2320, + intersection: 0x2229, + intisquare: 0x3305, + invbullet: 0x25D8, + invcircle: 0x25D9, + invsmileface: 0x263B, + iocyrillic: 0x0451, + iogonek: 0x012F, + iota: 0x03B9, + iotadieresis: 0x03CA, + iotadieresistonos: 0x0390, + iotalatin: 0x0269, + iotatonos: 0x03AF, + iparen: 0x24A4, + irigurmukhi: 0x0A72, + ismallhiragana: 0x3043, + ismallkatakana: 0x30A3, + ismallkatakanahalfwidth: 0xFF68, + issharbengali: 0x09FA, + istroke: 0x0268, + isuperior: 0xF6ED, + iterationhiragana: 0x309D, + iterationkatakana: 0x30FD, + itilde: 0x0129, + itildebelow: 0x1E2D, + iubopomofo: 0x3129, + iucyrillic: 0x044E, + ivowelsignbengali: 0x09BF, + ivowelsigndeva: 0x093F, + ivowelsigngujarati: 0x0ABF, + izhitsacyrillic: 0x0475, + izhitsadblgravecyrillic: 0x0477, + j: 0x006A, + jaarmenian: 0x0571, + jabengali: 0x099C, + jadeva: 0x091C, + jagujarati: 0x0A9C, + jagurmukhi: 0x0A1C, + jbopomofo: 0x3110, + jcaron: 0x01F0, + jcircle: 0x24D9, + jcircumflex: 0x0135, + jcrossedtail: 0x029D, + jdotlessstroke: 0x025F, + jecyrillic: 0x0458, + jeemarabic: 0x062C, + jeemfinalarabic: 0xFE9E, + jeeminitialarabic: 0xFE9F, + jeemmedialarabic: 0xFEA0, + jeharabic: 0x0698, + jehfinalarabic: 0xFB8B, + jhabengali: 0x099D, + jhadeva: 0x091D, + jhagujarati: 0x0A9D, + jhagurmukhi: 0x0A1D, + jheharmenian: 0x057B, + jis: 0x3004, + jmonospace: 0xFF4A, + jparen: 0x24A5, + jsuperior: 0x02B2, + k: 0x006B, + kabashkircyrillic: 0x04A1, + kabengali: 0x0995, + kacute: 0x1E31, + kacyrillic: 0x043A, + kadescendercyrillic: 0x049B, + kadeva: 0x0915, + kaf: 0x05DB, + kafarabic: 0x0643, + kafdagesh: 0xFB3B, + kafdageshhebrew: 0xFB3B, + kaffinalarabic: 0xFEDA, + kafhebrew: 0x05DB, + kafinitialarabic: 0xFEDB, + kafmedialarabic: 0xFEDC, + kafrafehebrew: 0xFB4D, + kagujarati: 0x0A95, + kagurmukhi: 0x0A15, + kahiragana: 0x304B, + kahookcyrillic: 0x04C4, + kakatakana: 0x30AB, + kakatakanahalfwidth: 0xFF76, + kappa: 0x03BA, + kappasymbolgreek: 0x03F0, + kapyeounmieumkorean: 0x3171, + kapyeounphieuphkorean: 0x3184, + kapyeounpieupkorean: 0x3178, + kapyeounssangpieupkorean: 0x3179, + karoriisquare: 0x330D, + kashidaautoarabic: 0x0640, + kashidaautonosidebearingarabic: 0x0640, + kasmallkatakana: 0x30F5, + kasquare: 0x3384, + kasraarabic: 0x0650, + kasratanarabic: 0x064D, + kastrokecyrillic: 0x049F, + katahiraprolongmarkhalfwidth: 0xFF70, + kaverticalstrokecyrillic: 0x049D, + kbopomofo: 0x310E, + kcalsquare: 0x3389, + kcaron: 0x01E9, + kcedilla: 0x0137, + kcircle: 0x24DA, + kcommaaccent: 0x0137, + kdotbelow: 0x1E33, + keharmenian: 0x0584, + kehiragana: 0x3051, + kekatakana: 0x30B1, + kekatakanahalfwidth: 0xFF79, + kenarmenian: 0x056F, + kesmallkatakana: 0x30F6, + kgreenlandic: 0x0138, + khabengali: 0x0996, + khacyrillic: 0x0445, + khadeva: 0x0916, + khagujarati: 0x0A96, + khagurmukhi: 0x0A16, + khaharabic: 0x062E, + khahfinalarabic: 0xFEA6, + khahinitialarabic: 0xFEA7, + khahmedialarabic: 0xFEA8, + kheicoptic: 0x03E7, + khhadeva: 0x0959, + khhagurmukhi: 0x0A59, + khieukhacirclekorean: 0x3278, + khieukhaparenkorean: 0x3218, + khieukhcirclekorean: 0x326A, + khieukhkorean: 0x314B, + khieukhparenkorean: 0x320A, + khokhaithai: 0x0E02, + khokhonthai: 0x0E05, + khokhuatthai: 0x0E03, + khokhwaithai: 0x0E04, + khomutthai: 0x0E5B, + khook: 0x0199, + khorakhangthai: 0x0E06, + khzsquare: 0x3391, + kihiragana: 0x304D, + kikatakana: 0x30AD, + kikatakanahalfwidth: 0xFF77, + kiroguramusquare: 0x3315, + kiromeetorusquare: 0x3316, + kirosquare: 0x3314, + kiyeokacirclekorean: 0x326E, + kiyeokaparenkorean: 0x320E, + kiyeokcirclekorean: 0x3260, + kiyeokkorean: 0x3131, + kiyeokparenkorean: 0x3200, + kiyeoksioskorean: 0x3133, + kjecyrillic: 0x045C, + klinebelow: 0x1E35, + klsquare: 0x3398, + kmcubedsquare: 0x33A6, + kmonospace: 0xFF4B, + kmsquaredsquare: 0x33A2, + kohiragana: 0x3053, + kohmsquare: 0x33C0, + kokaithai: 0x0E01, + kokatakana: 0x30B3, + kokatakanahalfwidth: 0xFF7A, + kooposquare: 0x331E, + koppacyrillic: 0x0481, + koreanstandardsymbol: 0x327F, + koroniscmb: 0x0343, + kparen: 0x24A6, + kpasquare: 0x33AA, + ksicyrillic: 0x046F, + ktsquare: 0x33CF, + kturned: 0x029E, + kuhiragana: 0x304F, + kukatakana: 0x30AF, + kukatakanahalfwidth: 0xFF78, + kvsquare: 0x33B8, + kwsquare: 0x33BE, + l: 0x006C, + labengali: 0x09B2, + lacute: 0x013A, + ladeva: 0x0932, + lagujarati: 0x0AB2, + lagurmukhi: 0x0A32, + lakkhangyaothai: 0x0E45, + lamaleffinalarabic: 0xFEFC, + lamalefhamzaabovefinalarabic: 0xFEF8, + lamalefhamzaaboveisolatedarabic: 0xFEF7, + lamalefhamzabelowfinalarabic: 0xFEFA, + lamalefhamzabelowisolatedarabic: 0xFEF9, + lamalefisolatedarabic: 0xFEFB, + lamalefmaddaabovefinalarabic: 0xFEF6, + lamalefmaddaaboveisolatedarabic: 0xFEF5, + lamarabic: 0x0644, + lambda: 0x03BB, + lambdastroke: 0x019B, + lamed: 0x05DC, + lameddagesh: 0xFB3C, + lameddageshhebrew: 0xFB3C, + lamedhebrew: 0x05DC, lamedholam: "05DC 05B9", lamedholamdagesh: "05DC 05B9 05BC", lamedholamdageshhebrew: "05DC 05B9 05BC", lamedholamhebrew: "05DC 05B9", - lamfinalarabic: "FEDE", - lamhahinitialarabic: "FCCA", - laminitialarabic: "FEDF", - lamjeeminitialarabic: "FCC9", - lamkhahinitialarabic: "FCCB", - lamlamhehisolatedarabic: "FDF2", - lammedialarabic: "FEE0", - lammeemhahinitialarabic: "FD88", - lammeeminitialarabic: "FCCC", + lamfinalarabic: 0xFEDE, + lamhahinitialarabic: 0xFCCA, + laminitialarabic: 0xFEDF, + lamjeeminitialarabic: 0xFCC9, + lamkhahinitialarabic: 0xFCCB, + lamlamhehisolatedarabic: 0xFDF2, + lammedialarabic: 0xFEE0, + lammeemhahinitialarabic: 0xFD88, + lammeeminitialarabic: 0xFCCC, lammeemjeeminitialarabic: "FEDF FEE4 FEA0", lammeemkhahinitialarabic: "FEDF FEE4 FEA8", - largecircle: "25EF", - lbar: "019A", - lbelt: "026C", - lbopomofo: "310C", - lcaron: "013E", - lcedilla: "013C", - lcircle: "24DB", - lcircumflexbelow: "1E3D", - lcommaaccent: "013C", - ldot: "0140", - ldotaccent: "0140", - ldotbelow: "1E37", - ldotbelowmacron: "1E39", - leftangleabovecmb: "031A", - lefttackbelowcmb: "0318", - less: "003C", - lessequal: "2264", - lessequalorgreater: "22DA", - lessmonospace: "FF1C", - lessorequivalent: "2272", - lessorgreater: "2276", - lessoverequal: "2266", - lesssmall: "FE64", - lezh: "026E", - lfblock: "258C", - lhookretroflex: "026D", - lira: "20A4", - liwnarmenian: "056C", - lj: "01C9", - ljecyrillic: "0459", - ll: "F6C0", - lladeva: "0933", - llagujarati: "0AB3", - llinebelow: "1E3B", - llladeva: "0934", - llvocalicbengali: "09E1", - llvocalicdeva: "0961", - llvocalicvowelsignbengali: "09E3", - llvocalicvowelsigndeva: "0963", - lmiddletilde: "026B", - lmonospace: "FF4C", - lmsquare: "33D0", - lochulathai: "0E2C", - logicaland: "2227", - logicalnot: "00AC", - logicalnotreversed: "2310", - logicalor: "2228", - lolingthai: "0E25", - longs: "017F", - lowlinecenterline: "FE4E", - lowlinecmb: "0332", - lowlinedashed: "FE4D", - lozenge: "25CA", - lparen: "24A7", - lslash: "0142", - lsquare: "2113", - lsuperior: "F6EE", - ltshade: "2591", - luthai: "0E26", - lvocalicbengali: "098C", - lvocalicdeva: "090C", - lvocalicvowelsignbengali: "09E2", - lvocalicvowelsigndeva: "0962", - lxsquare: "33D3", - m: "006D", - mabengali: "09AE", - macron: "00AF", - macronbelowcmb: "0331", - macroncmb: "0304", - macronlowmod: "02CD", - macronmonospace: "FFE3", - macute: "1E3F", - madeva: "092E", - magujarati: "0AAE", - magurmukhi: "0A2E", - mahapakhhebrew: "05A4", - mahapakhlefthebrew: "05A4", - mahiragana: "307E", - maichattawalowleftthai: "F895", - maichattawalowrightthai: "F894", - maichattawathai: "0E4B", - maichattawaupperleftthai: "F893", - maieklowleftthai: "F88C", - maieklowrightthai: "F88B", - maiekthai: "0E48", - maiekupperleftthai: "F88A", - maihanakatleftthai: "F884", - maihanakatthai: "0E31", - maitaikhuleftthai: "F889", - maitaikhuthai: "0E47", - maitholowleftthai: "F88F", - maitholowrightthai: "F88E", - maithothai: "0E49", - maithoupperleftthai: "F88D", - maitrilowleftthai: "F892", - maitrilowrightthai: "F891", - maitrithai: "0E4A", - maitriupperleftthai: "F890", - maiyamokthai: "0E46", - makatakana: "30DE", - makatakanahalfwidth: "FF8F", - male: "2642", - mansyonsquare: "3347", - maqafhebrew: "05BE", - mars: "2642", - masoracirclehebrew: "05AF", - masquare: "3383", - mbopomofo: "3107", - mbsquare: "33D4", - mcircle: "24DC", - mcubedsquare: "33A5", - mdotaccent: "1E41", - mdotbelow: "1E43", - meemarabic: "0645", - meemfinalarabic: "FEE2", - meeminitialarabic: "FEE3", - meemmedialarabic: "FEE4", - meemmeeminitialarabic: "FCD1", - meemmeemisolatedarabic: "FC48", - meetorusquare: "334D", - mehiragana: "3081", - meizierasquare: "337E", - mekatakana: "30E1", - mekatakanahalfwidth: "FF92", - mem: "05DE", - memdagesh: "FB3E", - memdageshhebrew: "FB3E", - memhebrew: "05DE", - menarmenian: "0574", - merkhahebrew: "05A5", - merkhakefulahebrew: "05A6", - merkhakefulalefthebrew: "05A6", - merkhalefthebrew: "05A5", - mhook: "0271", - mhzsquare: "3392", - middledotkatakanahalfwidth: "FF65", - middot: "00B7", - mieumacirclekorean: "3272", - mieumaparenkorean: "3212", - mieumcirclekorean: "3264", - mieumkorean: "3141", - mieumpansioskorean: "3170", - mieumparenkorean: "3204", - mieumpieupkorean: "316E", - mieumsioskorean: "316F", - mihiragana: "307F", - mikatakana: "30DF", - mikatakanahalfwidth: "FF90", - minus: "2212", - minusbelowcmb: "0320", - minuscircle: "2296", - minusmod: "02D7", - minusplus: "2213", - minute: "2032", - miribaarusquare: "334A", - mirisquare: "3349", - mlonglegturned: "0270", - mlsquare: "3396", - mmcubedsquare: "33A3", - mmonospace: "FF4D", - mmsquaredsquare: "339F", - mohiragana: "3082", - mohmsquare: "33C1", - mokatakana: "30E2", - mokatakanahalfwidth: "FF93", - molsquare: "33D6", - momathai: "0E21", - moverssquare: "33A7", - moverssquaredsquare: "33A8", - mparen: "24A8", - mpasquare: "33AB", - mssquare: "33B3", - msuperior: "F6EF", - mturned: "026F", - mu: "00B5", - mu1: "00B5", - muasquare: "3382", - muchgreater: "226B", - muchless: "226A", - mufsquare: "338C", - mugreek: "03BC", - mugsquare: "338D", - muhiragana: "3080", - mukatakana: "30E0", - mukatakanahalfwidth: "FF91", - mulsquare: "3395", - multiply: "00D7", - mumsquare: "339B", - munahhebrew: "05A3", - munahlefthebrew: "05A3", - musicalnote: "266A", - musicalnotedbl: "266B", - musicflatsign: "266D", - musicsharpsign: "266F", - mussquare: "33B2", - muvsquare: "33B6", - muwsquare: "33BC", - mvmegasquare: "33B9", - mvsquare: "33B7", - mwmegasquare: "33BF", - mwsquare: "33BD", - n: "006E", - nabengali: "09A8", - nabla: "2207", - nacute: "0144", - nadeva: "0928", - nagujarati: "0AA8", - nagurmukhi: "0A28", - nahiragana: "306A", - nakatakana: "30CA", - nakatakanahalfwidth: "FF85", - napostrophe: "0149", - nasquare: "3381", - nbopomofo: "310B", - nbspace: "00A0", - ncaron: "0148", - ncedilla: "0146", - ncircle: "24DD", - ncircumflexbelow: "1E4B", - ncommaaccent: "0146", - ndotaccent: "1E45", - ndotbelow: "1E47", - nehiragana: "306D", - nekatakana: "30CD", - nekatakanahalfwidth: "FF88", - newsheqelsign: "20AA", - nfsquare: "338B", - ngabengali: "0999", - ngadeva: "0919", - ngagujarati: "0A99", - ngagurmukhi: "0A19", - ngonguthai: "0E07", - nhiragana: "3093", - nhookleft: "0272", - nhookretroflex: "0273", - nieunacirclekorean: "326F", - nieunaparenkorean: "320F", - nieuncieuckorean: "3135", - nieuncirclekorean: "3261", - nieunhieuhkorean: "3136", - nieunkorean: "3134", - nieunpansioskorean: "3168", - nieunparenkorean: "3201", - nieunsioskorean: "3167", - nieuntikeutkorean: "3166", - nihiragana: "306B", - nikatakana: "30CB", - nikatakanahalfwidth: "FF86", - nikhahitleftthai: "F899", - nikhahitthai: "0E4D", - nine: "0039", - ninearabic: "0669", - ninebengali: "09EF", - ninecircle: "2468", - ninecircleinversesansserif: "2792", - ninedeva: "096F", - ninegujarati: "0AEF", - ninegurmukhi: "0A6F", - ninehackarabic: "0669", - ninehangzhou: "3029", - nineideographicparen: "3228", - nineinferior: "2089", - ninemonospace: "FF19", - nineoldstyle: "F739", - nineparen: "247C", - nineperiod: "2490", - ninepersian: "06F9", - nineroman: "2178", - ninesuperior: "2079", - nineteencircle: "2472", - nineteenparen: "2486", - nineteenperiod: "249A", - ninethai: "0E59", - nj: "01CC", - njecyrillic: "045A", - nkatakana: "30F3", - nkatakanahalfwidth: "FF9D", - nlegrightlong: "019E", - nlinebelow: "1E49", - nmonospace: "FF4E", - nmsquare: "339A", - nnabengali: "09A3", - nnadeva: "0923", - nnagujarati: "0AA3", - nnagurmukhi: "0A23", - nnnadeva: "0929", - nohiragana: "306E", - nokatakana: "30CE", - nokatakanahalfwidth: "FF89", - nonbreakingspace: "00A0", - nonenthai: "0E13", - nonuthai: "0E19", - noonarabic: "0646", - noonfinalarabic: "FEE6", - noonghunnaarabic: "06BA", - noonghunnafinalarabic: "FB9F", + largecircle: 0x25EF, + lbar: 0x019A, + lbelt: 0x026C, + lbopomofo: 0x310C, + lcaron: 0x013E, + lcedilla: 0x013C, + lcircle: 0x24DB, + lcircumflexbelow: 0x1E3D, + lcommaaccent: 0x013C, + ldot: 0x0140, + ldotaccent: 0x0140, + ldotbelow: 0x1E37, + ldotbelowmacron: 0x1E39, + leftangleabovecmb: 0x031A, + lefttackbelowcmb: 0x0318, + less: 0x003C, + lessequal: 0x2264, + lessequalorgreater: 0x22DA, + lessmonospace: 0xFF1C, + lessorequivalent: 0x2272, + lessorgreater: 0x2276, + lessoverequal: 0x2266, + lesssmall: 0xFE64, + lezh: 0x026E, + lfblock: 0x258C, + lhookretroflex: 0x026D, + lira: 0x20A4, + liwnarmenian: 0x056C, + lj: 0x01C9, + ljecyrillic: 0x0459, + ll: 0xF6C0, + lladeva: 0x0933, + llagujarati: 0x0AB3, + llinebelow: 0x1E3B, + llladeva: 0x0934, + llvocalicbengali: 0x09E1, + llvocalicdeva: 0x0961, + llvocalicvowelsignbengali: 0x09E3, + llvocalicvowelsigndeva: 0x0963, + lmiddletilde: 0x026B, + lmonospace: 0xFF4C, + lmsquare: 0x33D0, + lochulathai: 0x0E2C, + logicaland: 0x2227, + logicalnot: 0x00AC, + logicalnotreversed: 0x2310, + logicalor: 0x2228, + lolingthai: 0x0E25, + longs: 0x017F, + lowlinecenterline: 0xFE4E, + lowlinecmb: 0x0332, + lowlinedashed: 0xFE4D, + lozenge: 0x25CA, + lparen: 0x24A7, + lslash: 0x0142, + lsquare: 0x2113, + lsuperior: 0xF6EE, + ltshade: 0x2591, + luthai: 0x0E26, + lvocalicbengali: 0x098C, + lvocalicdeva: 0x090C, + lvocalicvowelsignbengali: 0x09E2, + lvocalicvowelsigndeva: 0x0962, + lxsquare: 0x33D3, + m: 0x006D, + mabengali: 0x09AE, + macron: 0x00AF, + macronbelowcmb: 0x0331, + macroncmb: 0x0304, + macronlowmod: 0x02CD, + macronmonospace: 0xFFE3, + macute: 0x1E3F, + madeva: 0x092E, + magujarati: 0x0AAE, + magurmukhi: 0x0A2E, + mahapakhhebrew: 0x05A4, + mahapakhlefthebrew: 0x05A4, + mahiragana: 0x307E, + maichattawalowleftthai: 0xF895, + maichattawalowrightthai: 0xF894, + maichattawathai: 0x0E4B, + maichattawaupperleftthai: 0xF893, + maieklowleftthai: 0xF88C, + maieklowrightthai: 0xF88B, + maiekthai: 0x0E48, + maiekupperleftthai: 0xF88A, + maihanakatleftthai: 0xF884, + maihanakatthai: 0x0E31, + maitaikhuleftthai: 0xF889, + maitaikhuthai: 0x0E47, + maitholowleftthai: 0xF88F, + maitholowrightthai: 0xF88E, + maithothai: 0x0E49, + maithoupperleftthai: 0xF88D, + maitrilowleftthai: 0xF892, + maitrilowrightthai: 0xF891, + maitrithai: 0x0E4A, + maitriupperleftthai: 0xF890, + maiyamokthai: 0x0E46, + makatakana: 0x30DE, + makatakanahalfwidth: 0xFF8F, + male: 0x2642, + mansyonsquare: 0x3347, + maqafhebrew: 0x05BE, + mars: 0x2642, + masoracirclehebrew: 0x05AF, + masquare: 0x3383, + mbopomofo: 0x3107, + mbsquare: 0x33D4, + mcircle: 0x24DC, + mcubedsquare: 0x33A5, + mdotaccent: 0x1E41, + mdotbelow: 0x1E43, + meemarabic: 0x0645, + meemfinalarabic: 0xFEE2, + meeminitialarabic: 0xFEE3, + meemmedialarabic: 0xFEE4, + meemmeeminitialarabic: 0xFCD1, + meemmeemisolatedarabic: 0xFC48, + meetorusquare: 0x334D, + mehiragana: 0x3081, + meizierasquare: 0x337E, + mekatakana: 0x30E1, + mekatakanahalfwidth: 0xFF92, + mem: 0x05DE, + memdagesh: 0xFB3E, + memdageshhebrew: 0xFB3E, + memhebrew: 0x05DE, + menarmenian: 0x0574, + merkhahebrew: 0x05A5, + merkhakefulahebrew: 0x05A6, + merkhakefulalefthebrew: 0x05A6, + merkhalefthebrew: 0x05A5, + mhook: 0x0271, + mhzsquare: 0x3392, + middledotkatakanahalfwidth: 0xFF65, + middot: 0x00B7, + mieumacirclekorean: 0x3272, + mieumaparenkorean: 0x3212, + mieumcirclekorean: 0x3264, + mieumkorean: 0x3141, + mieumpansioskorean: 0x3170, + mieumparenkorean: 0x3204, + mieumpieupkorean: 0x316E, + mieumsioskorean: 0x316F, + mihiragana: 0x307F, + mikatakana: 0x30DF, + mikatakanahalfwidth: 0xFF90, + minus: 0x2212, + minusbelowcmb: 0x0320, + minuscircle: 0x2296, + minusmod: 0x02D7, + minusplus: 0x2213, + minute: 0x2032, + miribaarusquare: 0x334A, + mirisquare: 0x3349, + mlonglegturned: 0x0270, + mlsquare: 0x3396, + mmcubedsquare: 0x33A3, + mmonospace: 0xFF4D, + mmsquaredsquare: 0x339F, + mohiragana: 0x3082, + mohmsquare: 0x33C1, + mokatakana: 0x30E2, + mokatakanahalfwidth: 0xFF93, + molsquare: 0x33D6, + momathai: 0x0E21, + moverssquare: 0x33A7, + moverssquaredsquare: 0x33A8, + mparen: 0x24A8, + mpasquare: 0x33AB, + mssquare: 0x33B3, + msuperior: 0xF6EF, + mturned: 0x026F, + mu: 0x00B5, + mu1: 0x00B5, + muasquare: 0x3382, + muchgreater: 0x226B, + muchless: 0x226A, + mufsquare: 0x338C, + mugreek: 0x03BC, + mugsquare: 0x338D, + muhiragana: 0x3080, + mukatakana: 0x30E0, + mukatakanahalfwidth: 0xFF91, + mulsquare: 0x3395, + multiply: 0x00D7, + mumsquare: 0x339B, + munahhebrew: 0x05A3, + munahlefthebrew: 0x05A3, + musicalnote: 0x266A, + musicalnotedbl: 0x266B, + musicflatsign: 0x266D, + musicsharpsign: 0x266F, + mussquare: 0x33B2, + muvsquare: 0x33B6, + muwsquare: 0x33BC, + mvmegasquare: 0x33B9, + mvsquare: 0x33B7, + mwmegasquare: 0x33BF, + mwsquare: 0x33BD, + n: 0x006E, + nabengali: 0x09A8, + nabla: 0x2207, + nacute: 0x0144, + nadeva: 0x0928, + nagujarati: 0x0AA8, + nagurmukhi: 0x0A28, + nahiragana: 0x306A, + nakatakana: 0x30CA, + nakatakanahalfwidth: 0xFF85, + napostrophe: 0x0149, + nasquare: 0x3381, + nbopomofo: 0x310B, + nbspace: 0x00A0, + ncaron: 0x0148, + ncedilla: 0x0146, + ncircle: 0x24DD, + ncircumflexbelow: 0x1E4B, + ncommaaccent: 0x0146, + ndotaccent: 0x1E45, + ndotbelow: 0x1E47, + nehiragana: 0x306D, + nekatakana: 0x30CD, + nekatakanahalfwidth: 0xFF88, + newsheqelsign: 0x20AA, + nfsquare: 0x338B, + ngabengali: 0x0999, + ngadeva: 0x0919, + ngagujarati: 0x0A99, + ngagurmukhi: 0x0A19, + ngonguthai: 0x0E07, + nhiragana: 0x3093, + nhookleft: 0x0272, + nhookretroflex: 0x0273, + nieunacirclekorean: 0x326F, + nieunaparenkorean: 0x320F, + nieuncieuckorean: 0x3135, + nieuncirclekorean: 0x3261, + nieunhieuhkorean: 0x3136, + nieunkorean: 0x3134, + nieunpansioskorean: 0x3168, + nieunparenkorean: 0x3201, + nieunsioskorean: 0x3167, + nieuntikeutkorean: 0x3166, + nihiragana: 0x306B, + nikatakana: 0x30CB, + nikatakanahalfwidth: 0xFF86, + nikhahitleftthai: 0xF899, + nikhahitthai: 0x0E4D, + nine: 0x0039, + ninearabic: 0x0669, + ninebengali: 0x09EF, + ninecircle: 0x2468, + ninecircleinversesansserif: 0x2792, + ninedeva: 0x096F, + ninegujarati: 0x0AEF, + ninegurmukhi: 0x0A6F, + ninehackarabic: 0x0669, + ninehangzhou: 0x3029, + nineideographicparen: 0x3228, + nineinferior: 0x2089, + ninemonospace: 0xFF19, + nineoldstyle: 0xF739, + nineparen: 0x247C, + nineperiod: 0x2490, + ninepersian: 0x06F9, + nineroman: 0x2178, + ninesuperior: 0x2079, + nineteencircle: 0x2472, + nineteenparen: 0x2486, + nineteenperiod: 0x249A, + ninethai: 0x0E59, + nj: 0x01CC, + njecyrillic: 0x045A, + nkatakana: 0x30F3, + nkatakanahalfwidth: 0xFF9D, + nlegrightlong: 0x019E, + nlinebelow: 0x1E49, + nmonospace: 0xFF4E, + nmsquare: 0x339A, + nnabengali: 0x09A3, + nnadeva: 0x0923, + nnagujarati: 0x0AA3, + nnagurmukhi: 0x0A23, + nnnadeva: 0x0929, + nohiragana: 0x306E, + nokatakana: 0x30CE, + nokatakanahalfwidth: 0xFF89, + nonbreakingspace: 0x00A0, + nonenthai: 0x0E13, + nonuthai: 0x0E19, + noonarabic: 0x0646, + noonfinalarabic: 0xFEE6, + noonghunnaarabic: 0x06BA, + noonghunnafinalarabic: 0xFB9F, noonhehinitialarabic: "FEE7 FEEC", - nooninitialarabic: "FEE7", - noonjeeminitialarabic: "FCD2", - noonjeemisolatedarabic: "FC4B", - noonmedialarabic: "FEE8", - noonmeeminitialarabic: "FCD5", - noonmeemisolatedarabic: "FC4E", - noonnoonfinalarabic: "FC8D", - notcontains: "220C", - notelement: "2209", - notelementof: "2209", - notequal: "2260", - notgreater: "226F", - notgreaternorequal: "2271", - notgreaternorless: "2279", - notidentical: "2262", - notless: "226E", - notlessnorequal: "2270", - notparallel: "2226", - notprecedes: "2280", - notsubset: "2284", - notsucceeds: "2281", - notsuperset: "2285", - nowarmenian: "0576", - nparen: "24A9", - nssquare: "33B1", - nsuperior: "207F", - ntilde: "00F1", - nu: "03BD", - nuhiragana: "306C", - nukatakana: "30CC", - nukatakanahalfwidth: "FF87", - nuktabengali: "09BC", - nuktadeva: "093C", - nuktagujarati: "0ABC", - nuktagurmukhi: "0A3C", - numbersign: "0023", - numbersignmonospace: "FF03", - numbersignsmall: "FE5F", - numeralsigngreek: "0374", - numeralsignlowergreek: "0375", - numero: "2116", - nun: "05E0", - nundagesh: "FB40", - nundageshhebrew: "FB40", - nunhebrew: "05E0", - nvsquare: "33B5", - nwsquare: "33BB", - nyabengali: "099E", - nyadeva: "091E", - nyagujarati: "0A9E", - nyagurmukhi: "0A1E", - o: "006F", - oacute: "00F3", - oangthai: "0E2D", - obarred: "0275", - obarredcyrillic: "04E9", - obarreddieresiscyrillic: "04EB", - obengali: "0993", - obopomofo: "311B", - obreve: "014F", - ocandradeva: "0911", - ocandragujarati: "0A91", - ocandravowelsigndeva: "0949", - ocandravowelsigngujarati: "0AC9", - ocaron: "01D2", - ocircle: "24DE", - ocircumflex: "00F4", - ocircumflexacute: "1ED1", - ocircumflexdotbelow: "1ED9", - ocircumflexgrave: "1ED3", - ocircumflexhookabove: "1ED5", - ocircumflextilde: "1ED7", - ocyrillic: "043E", - odblacute: "0151", - odblgrave: "020D", - odeva: "0913", - odieresis: "00F6", - odieresiscyrillic: "04E7", - odotbelow: "1ECD", - oe: "0153", - oekorean: "315A", - ogonek: "02DB", - ogonekcmb: "0328", - ograve: "00F2", - ogujarati: "0A93", - oharmenian: "0585", - ohiragana: "304A", - ohookabove: "1ECF", - ohorn: "01A1", - ohornacute: "1EDB", - ohorndotbelow: "1EE3", - ohorngrave: "1EDD", - ohornhookabove: "1EDF", - ohorntilde: "1EE1", - ohungarumlaut: "0151", - oi: "01A3", - oinvertedbreve: "020F", - okatakana: "30AA", - okatakanahalfwidth: "FF75", - okorean: "3157", - olehebrew: "05AB", - omacron: "014D", - omacronacute: "1E53", - omacrongrave: "1E51", - omdeva: "0950", - omega: "03C9", - omega1: "03D6", - omegacyrillic: "0461", - omegalatinclosed: "0277", - omegaroundcyrillic: "047B", - omegatitlocyrillic: "047D", - omegatonos: "03CE", - omgujarati: "0AD0", - omicron: "03BF", - omicrontonos: "03CC", - omonospace: "FF4F", - one: "0031", - onearabic: "0661", - onebengali: "09E7", - onecircle: "2460", - onecircleinversesansserif: "278A", - onedeva: "0967", - onedotenleader: "2024", - oneeighth: "215B", - onefitted: "F6DC", - onegujarati: "0AE7", - onegurmukhi: "0A67", - onehackarabic: "0661", - onehalf: "00BD", - onehangzhou: "3021", - oneideographicparen: "3220", - oneinferior: "2081", - onemonospace: "FF11", - onenumeratorbengali: "09F4", - oneoldstyle: "F731", - oneparen: "2474", - oneperiod: "2488", - onepersian: "06F1", - onequarter: "00BC", - oneroman: "2170", - onesuperior: "00B9", - onethai: "0E51", - onethird: "2153", - oogonek: "01EB", - oogonekmacron: "01ED", - oogurmukhi: "0A13", - oomatragurmukhi: "0A4B", - oopen: "0254", - oparen: "24AA", - openbullet: "25E6", - option: "2325", - ordfeminine: "00AA", - ordmasculine: "00BA", - orthogonal: "221F", - oshortdeva: "0912", - oshortvowelsigndeva: "094A", - oslash: "00F8", - oslashacute: "01FF", - osmallhiragana: "3049", - osmallkatakana: "30A9", - osmallkatakanahalfwidth: "FF6B", - ostrokeacute: "01FF", - osuperior: "F6F0", - otcyrillic: "047F", - otilde: "00F5", - otildeacute: "1E4D", - otildedieresis: "1E4F", - oubopomofo: "3121", - overline: "203E", - overlinecenterline: "FE4A", - overlinecmb: "0305", - overlinedashed: "FE49", - overlinedblwavy: "FE4C", - overlinewavy: "FE4B", - overscore: "00AF", - ovowelsignbengali: "09CB", - ovowelsigndeva: "094B", - ovowelsigngujarati: "0ACB", - p: "0070", - paampssquare: "3380", - paasentosquare: "332B", - pabengali: "09AA", - pacute: "1E55", - padeva: "092A", - pagedown: "21DF", - pageup: "21DE", - pagujarati: "0AAA", - pagurmukhi: "0A2A", - pahiragana: "3071", - paiyannoithai: "0E2F", - pakatakana: "30D1", - palatalizationcyrilliccmb: "0484", - palochkacyrillic: "04C0", - pansioskorean: "317F", - paragraph: "00B6", - parallel: "2225", - parenleft: "0028", - parenleftaltonearabic: "FD3E", - parenleftbt: "F8ED", - parenleftex: "F8EC", - parenleftinferior: "208D", - parenleftmonospace: "FF08", - parenleftsmall: "FE59", - parenleftsuperior: "207D", - parenlefttp: "F8EB", - parenleftvertical: "FE35", - parenright: "0029", - parenrightaltonearabic: "FD3F", - parenrightbt: "F8F8", - parenrightex: "F8F7", - parenrightinferior: "208E", - parenrightmonospace: "FF09", - parenrightsmall: "FE5A", - parenrightsuperior: "207E", - parenrighttp: "F8F6", - parenrightvertical: "FE36", - partialdiff: "2202", - paseqhebrew: "05C0", - pashtahebrew: "0599", - pasquare: "33A9", - patah: "05B7", - patah11: "05B7", - patah1d: "05B7", - patah2a: "05B7", - patahhebrew: "05B7", - patahnarrowhebrew: "05B7", - patahquarterhebrew: "05B7", - patahwidehebrew: "05B7", - pazerhebrew: "05A1", - pbopomofo: "3106", - pcircle: "24DF", - pdotaccent: "1E57", - pe: "05E4", - pecyrillic: "043F", - pedagesh: "FB44", - pedageshhebrew: "FB44", - peezisquare: "333B", - pefinaldageshhebrew: "FB43", - peharabic: "067E", - peharmenian: "057A", - pehebrew: "05E4", - pehfinalarabic: "FB57", - pehinitialarabic: "FB58", - pehiragana: "307A", - pehmedialarabic: "FB59", - pekatakana: "30DA", - pemiddlehookcyrillic: "04A7", - perafehebrew: "FB4E", - percent: "0025", - percentarabic: "066A", - percentmonospace: "FF05", - percentsmall: "FE6A", - period: "002E", - periodarmenian: "0589", - periodcentered: "00B7", - periodhalfwidth: "FF61", - periodinferior: "F6E7", - periodmonospace: "FF0E", - periodsmall: "FE52", - periodsuperior: "F6E8", - perispomenigreekcmb: "0342", - perpendicular: "22A5", - perthousand: "2030", - peseta: "20A7", - pfsquare: "338A", - phabengali: "09AB", - phadeva: "092B", - phagujarati: "0AAB", - phagurmukhi: "0A2B", - phi: "03C6", - phi1: "03D5", - phieuphacirclekorean: "327A", - phieuphaparenkorean: "321A", - phieuphcirclekorean: "326C", - phieuphkorean: "314D", - phieuphparenkorean: "320C", - philatin: "0278", - phinthuthai: "0E3A", - phisymbolgreek: "03D5", - phook: "01A5", - phophanthai: "0E1E", - phophungthai: "0E1C", - phosamphaothai: "0E20", - pi: "03C0", - pieupacirclekorean: "3273", - pieupaparenkorean: "3213", - pieupcieuckorean: "3176", - pieupcirclekorean: "3265", - pieupkiyeokkorean: "3172", - pieupkorean: "3142", - pieupparenkorean: "3205", - pieupsioskiyeokkorean: "3174", - pieupsioskorean: "3144", - pieupsiostikeutkorean: "3175", - pieupthieuthkorean: "3177", - pieuptikeutkorean: "3173", - pihiragana: "3074", - pikatakana: "30D4", - pisymbolgreek: "03D6", - piwrarmenian: "0583", - plus: "002B", - plusbelowcmb: "031F", - pluscircle: "2295", - plusminus: "00B1", - plusmod: "02D6", - plusmonospace: "FF0B", - plussmall: "FE62", - plussuperior: "207A", - pmonospace: "FF50", - pmsquare: "33D8", - pohiragana: "307D", - pointingindexdownwhite: "261F", - pointingindexleftwhite: "261C", - pointingindexrightwhite: "261E", - pointingindexupwhite: "261D", - pokatakana: "30DD", - poplathai: "0E1B", - postalmark: "3012", - postalmarkface: "3020", - pparen: "24AB", - precedes: "227A", - prescription: "211E", - primemod: "02B9", - primereversed: "2035", - product: "220F", - projective: "2305", - prolongedkana: "30FC", - propellor: "2318", - propersubset: "2282", - propersuperset: "2283", - proportion: "2237", - proportional: "221D", - psi: "03C8", - psicyrillic: "0471", - psilipneumatacyrilliccmb: "0486", - pssquare: "33B0", - puhiragana: "3077", - pukatakana: "30D7", - pvsquare: "33B4", - pwsquare: "33BA", - q: "0071", - qadeva: "0958", - qadmahebrew: "05A8", - qafarabic: "0642", - qaffinalarabic: "FED6", - qafinitialarabic: "FED7", - qafmedialarabic: "FED8", - qamats: "05B8", - qamats10: "05B8", - qamats1a: "05B8", - qamats1c: "05B8", - qamats27: "05B8", - qamats29: "05B8", - qamats33: "05B8", - qamatsde: "05B8", - qamatshebrew: "05B8", - qamatsnarrowhebrew: "05B8", - qamatsqatanhebrew: "05B8", - qamatsqatannarrowhebrew: "05B8", - qamatsqatanquarterhebrew: "05B8", - qamatsqatanwidehebrew: "05B8", - qamatsquarterhebrew: "05B8", - qamatswidehebrew: "05B8", - qarneyparahebrew: "059F", - qbopomofo: "3111", - qcircle: "24E0", - qhook: "02A0", - qmonospace: "FF51", - qof: "05E7", - qofdagesh: "FB47", - qofdageshhebrew: "FB47", + nooninitialarabic: 0xFEE7, + noonjeeminitialarabic: 0xFCD2, + noonjeemisolatedarabic: 0xFC4B, + noonmedialarabic: 0xFEE8, + noonmeeminitialarabic: 0xFCD5, + noonmeemisolatedarabic: 0xFC4E, + noonnoonfinalarabic: 0xFC8D, + notcontains: 0x220C, + notelement: 0x2209, + notelementof: 0x2209, + notequal: 0x2260, + notgreater: 0x226F, + notgreaternorequal: 0x2271, + notgreaternorless: 0x2279, + notidentical: 0x2262, + notless: 0x226E, + notlessnorequal: 0x2270, + notparallel: 0x2226, + notprecedes: 0x2280, + notsubset: 0x2284, + notsucceeds: 0x2281, + notsuperset: 0x2285, + nowarmenian: 0x0576, + nparen: 0x24A9, + nssquare: 0x33B1, + nsuperior: 0x207F, + ntilde: 0x00F1, + nu: 0x03BD, + nuhiragana: 0x306C, + nukatakana: 0x30CC, + nukatakanahalfwidth: 0xFF87, + nuktabengali: 0x09BC, + nuktadeva: 0x093C, + nuktagujarati: 0x0ABC, + nuktagurmukhi: 0x0A3C, + numbersign: 0x0023, + numbersignmonospace: 0xFF03, + numbersignsmall: 0xFE5F, + numeralsigngreek: 0x0374, + numeralsignlowergreek: 0x0375, + numero: 0x2116, + nun: 0x05E0, + nundagesh: 0xFB40, + nundageshhebrew: 0xFB40, + nunhebrew: 0x05E0, + nvsquare: 0x33B5, + nwsquare: 0x33BB, + nyabengali: 0x099E, + nyadeva: 0x091E, + nyagujarati: 0x0A9E, + nyagurmukhi: 0x0A1E, + o: 0x006F, + oacute: 0x00F3, + oangthai: 0x0E2D, + obarred: 0x0275, + obarredcyrillic: 0x04E9, + obarreddieresiscyrillic: 0x04EB, + obengali: 0x0993, + obopomofo: 0x311B, + obreve: 0x014F, + ocandradeva: 0x0911, + ocandragujarati: 0x0A91, + ocandravowelsigndeva: 0x0949, + ocandravowelsigngujarati: 0x0AC9, + ocaron: 0x01D2, + ocircle: 0x24DE, + ocircumflex: 0x00F4, + ocircumflexacute: 0x1ED1, + ocircumflexdotbelow: 0x1ED9, + ocircumflexgrave: 0x1ED3, + ocircumflexhookabove: 0x1ED5, + ocircumflextilde: 0x1ED7, + ocyrillic: 0x043E, + odblacute: 0x0151, + odblgrave: 0x020D, + odeva: 0x0913, + odieresis: 0x00F6, + odieresiscyrillic: 0x04E7, + odotbelow: 0x1ECD, + oe: 0x0153, + oekorean: 0x315A, + ogonek: 0x02DB, + ogonekcmb: 0x0328, + ograve: 0x00F2, + ogujarati: 0x0A93, + oharmenian: 0x0585, + ohiragana: 0x304A, + ohookabove: 0x1ECF, + ohorn: 0x01A1, + ohornacute: 0x1EDB, + ohorndotbelow: 0x1EE3, + ohorngrave: 0x1EDD, + ohornhookabove: 0x1EDF, + ohorntilde: 0x1EE1, + ohungarumlaut: 0x0151, + oi: 0x01A3, + oinvertedbreve: 0x020F, + okatakana: 0x30AA, + okatakanahalfwidth: 0xFF75, + okorean: 0x3157, + olehebrew: 0x05AB, + omacron: 0x014D, + omacronacute: 0x1E53, + omacrongrave: 0x1E51, + omdeva: 0x0950, + omega: 0x03C9, + omega1: 0x03D6, + omegacyrillic: 0x0461, + omegalatinclosed: 0x0277, + omegaroundcyrillic: 0x047B, + omegatitlocyrillic: 0x047D, + omegatonos: 0x03CE, + omgujarati: 0x0AD0, + omicron: 0x03BF, + omicrontonos: 0x03CC, + omonospace: 0xFF4F, + one: 0x0031, + onearabic: 0x0661, + onebengali: 0x09E7, + onecircle: 0x2460, + onecircleinversesansserif: 0x278A, + onedeva: 0x0967, + onedotenleader: 0x2024, + oneeighth: 0x215B, + onefitted: 0xF6DC, + onegujarati: 0x0AE7, + onegurmukhi: 0x0A67, + onehackarabic: 0x0661, + onehalf: 0x00BD, + onehangzhou: 0x3021, + oneideographicparen: 0x3220, + oneinferior: 0x2081, + onemonospace: 0xFF11, + onenumeratorbengali: 0x09F4, + oneoldstyle: 0xF731, + oneparen: 0x2474, + oneperiod: 0x2488, + onepersian: 0x06F1, + onequarter: 0x00BC, + oneroman: 0x2170, + onesuperior: 0x00B9, + onethai: 0x0E51, + onethird: 0x2153, + oogonek: 0x01EB, + oogonekmacron: 0x01ED, + oogurmukhi: 0x0A13, + oomatragurmukhi: 0x0A4B, + oopen: 0x0254, + oparen: 0x24AA, + openbullet: 0x25E6, + option: 0x2325, + ordfeminine: 0x00AA, + ordmasculine: 0x00BA, + orthogonal: 0x221F, + oshortdeva: 0x0912, + oshortvowelsigndeva: 0x094A, + oslash: 0x00F8, + oslashacute: 0x01FF, + osmallhiragana: 0x3049, + osmallkatakana: 0x30A9, + osmallkatakanahalfwidth: 0xFF6B, + ostrokeacute: 0x01FF, + osuperior: 0xF6F0, + otcyrillic: 0x047F, + otilde: 0x00F5, + otildeacute: 0x1E4D, + otildedieresis: 0x1E4F, + oubopomofo: 0x3121, + overline: 0x203E, + overlinecenterline: 0xFE4A, + overlinecmb: 0x0305, + overlinedashed: 0xFE49, + overlinedblwavy: 0xFE4C, + overlinewavy: 0xFE4B, + overscore: 0x00AF, + ovowelsignbengali: 0x09CB, + ovowelsigndeva: 0x094B, + ovowelsigngujarati: 0x0ACB, + p: 0x0070, + paampssquare: 0x3380, + paasentosquare: 0x332B, + pabengali: 0x09AA, + pacute: 0x1E55, + padeva: 0x092A, + pagedown: 0x21DF, + pageup: 0x21DE, + pagujarati: 0x0AAA, + pagurmukhi: 0x0A2A, + pahiragana: 0x3071, + paiyannoithai: 0x0E2F, + pakatakana: 0x30D1, + palatalizationcyrilliccmb: 0x0484, + palochkacyrillic: 0x04C0, + pansioskorean: 0x317F, + paragraph: 0x00B6, + parallel: 0x2225, + parenleft: 0x0028, + parenleftaltonearabic: 0xFD3E, + parenleftbt: 0xF8ED, + parenleftex: 0xF8EC, + parenleftinferior: 0x208D, + parenleftmonospace: 0xFF08, + parenleftsmall: 0xFE59, + parenleftsuperior: 0x207D, + parenlefttp: 0xF8EB, + parenleftvertical: 0xFE35, + parenright: 0x0029, + parenrightaltonearabic: 0xFD3F, + parenrightbt: 0xF8F8, + parenrightex: 0xF8F7, + parenrightinferior: 0x208E, + parenrightmonospace: 0xFF09, + parenrightsmall: 0xFE5A, + parenrightsuperior: 0x207E, + parenrighttp: 0xF8F6, + parenrightvertical: 0xFE36, + partialdiff: 0x2202, + paseqhebrew: 0x05C0, + pashtahebrew: 0x0599, + pasquare: 0x33A9, + patah: 0x05B7, + patah11: 0x05B7, + patah1d: 0x05B7, + patah2a: 0x05B7, + patahhebrew: 0x05B7, + patahnarrowhebrew: 0x05B7, + patahquarterhebrew: 0x05B7, + patahwidehebrew: 0x05B7, + pazerhebrew: 0x05A1, + pbopomofo: 0x3106, + pcircle: 0x24DF, + pdotaccent: 0x1E57, + pe: 0x05E4, + pecyrillic: 0x043F, + pedagesh: 0xFB44, + pedageshhebrew: 0xFB44, + peezisquare: 0x333B, + pefinaldageshhebrew: 0xFB43, + peharabic: 0x067E, + peharmenian: 0x057A, + pehebrew: 0x05E4, + pehfinalarabic: 0xFB57, + pehinitialarabic: 0xFB58, + pehiragana: 0x307A, + pehmedialarabic: 0xFB59, + pekatakana: 0x30DA, + pemiddlehookcyrillic: 0x04A7, + perafehebrew: 0xFB4E, + percent: 0x0025, + percentarabic: 0x066A, + percentmonospace: 0xFF05, + percentsmall: 0xFE6A, + period: 0x002E, + periodarmenian: 0x0589, + periodcentered: 0x00B7, + periodhalfwidth: 0xFF61, + periodinferior: 0xF6E7, + periodmonospace: 0xFF0E, + periodsmall: 0xFE52, + periodsuperior: 0xF6E8, + perispomenigreekcmb: 0x0342, + perpendicular: 0x22A5, + perthousand: 0x2030, + peseta: 0x20A7, + pfsquare: 0x338A, + phabengali: 0x09AB, + phadeva: 0x092B, + phagujarati: 0x0AAB, + phagurmukhi: 0x0A2B, + phi: 0x03C6, + phi1: 0x03D5, + phieuphacirclekorean: 0x327A, + phieuphaparenkorean: 0x321A, + phieuphcirclekorean: 0x326C, + phieuphkorean: 0x314D, + phieuphparenkorean: 0x320C, + philatin: 0x0278, + phinthuthai: 0x0E3A, + phisymbolgreek: 0x03D5, + phook: 0x01A5, + phophanthai: 0x0E1E, + phophungthai: 0x0E1C, + phosamphaothai: 0x0E20, + pi: 0x03C0, + pieupacirclekorean: 0x3273, + pieupaparenkorean: 0x3213, + pieupcieuckorean: 0x3176, + pieupcirclekorean: 0x3265, + pieupkiyeokkorean: 0x3172, + pieupkorean: 0x3142, + pieupparenkorean: 0x3205, + pieupsioskiyeokkorean: 0x3174, + pieupsioskorean: 0x3144, + pieupsiostikeutkorean: 0x3175, + pieupthieuthkorean: 0x3177, + pieuptikeutkorean: 0x3173, + pihiragana: 0x3074, + pikatakana: 0x30D4, + pisymbolgreek: 0x03D6, + piwrarmenian: 0x0583, + plus: 0x002B, + plusbelowcmb: 0x031F, + pluscircle: 0x2295, + plusminus: 0x00B1, + plusmod: 0x02D6, + plusmonospace: 0xFF0B, + plussmall: 0xFE62, + plussuperior: 0x207A, + pmonospace: 0xFF50, + pmsquare: 0x33D8, + pohiragana: 0x307D, + pointingindexdownwhite: 0x261F, + pointingindexleftwhite: 0x261C, + pointingindexrightwhite: 0x261E, + pointingindexupwhite: 0x261D, + pokatakana: 0x30DD, + poplathai: 0x0E1B, + postalmark: 0x3012, + postalmarkface: 0x3020, + pparen: 0x24AB, + precedes: 0x227A, + prescription: 0x211E, + primemod: 0x02B9, + primereversed: 0x2035, + product: 0x220F, + projective: 0x2305, + prolongedkana: 0x30FC, + propellor: 0x2318, + propersubset: 0x2282, + propersuperset: 0x2283, + proportion: 0x2237, + proportional: 0x221D, + psi: 0x03C8, + psicyrillic: 0x0471, + psilipneumatacyrilliccmb: 0x0486, + pssquare: 0x33B0, + puhiragana: 0x3077, + pukatakana: 0x30D7, + pvsquare: 0x33B4, + pwsquare: 0x33BA, + q: 0x0071, + qadeva: 0x0958, + qadmahebrew: 0x05A8, + qafarabic: 0x0642, + qaffinalarabic: 0xFED6, + qafinitialarabic: 0xFED7, + qafmedialarabic: 0xFED8, + qamats: 0x05B8, + qamats10: 0x05B8, + qamats1a: 0x05B8, + qamats1c: 0x05B8, + qamats27: 0x05B8, + qamats29: 0x05B8, + qamats33: 0x05B8, + qamatsde: 0x05B8, + qamatshebrew: 0x05B8, + qamatsnarrowhebrew: 0x05B8, + qamatsqatanhebrew: 0x05B8, + qamatsqatannarrowhebrew: 0x05B8, + qamatsqatanquarterhebrew: 0x05B8, + qamatsqatanwidehebrew: 0x05B8, + qamatsquarterhebrew: 0x05B8, + qamatswidehebrew: 0x05B8, + qarneyparahebrew: 0x059F, + qbopomofo: 0x3111, + qcircle: 0x24E0, + qhook: 0x02A0, + qmonospace: 0xFF51, + qof: 0x05E7, + qofdagesh: 0xFB47, + qofdageshhebrew: 0xFB47, qofhatafpatah: "05E7 05B2", qofhatafpatahhebrew: "05E7 05B2", qofhatafsegol: "05E7 05B1", qofhatafsegolhebrew: "05E7 05B1", - qofhebrew: "05E7", + qofhebrew: 0x05E7, qofhiriq: "05E7 05B4", qofhiriqhebrew: "05E7 05B4", qofholam: "05E7 05B9", @@ -3172,89 +3172,89 @@ var GlyphsUnicode = { qofshevahebrew: "05E7 05B0", qoftsere: "05E7 05B5", qoftserehebrew: "05E7 05B5", - qparen: "24AC", - quarternote: "2669", - qubuts: "05BB", - qubuts18: "05BB", - qubuts25: "05BB", - qubuts31: "05BB", - qubutshebrew: "05BB", - qubutsnarrowhebrew: "05BB", - qubutsquarterhebrew: "05BB", - qubutswidehebrew: "05BB", - question: "003F", - questionarabic: "061F", - questionarmenian: "055E", - questiondown: "00BF", - questiondownsmall: "F7BF", - questiongreek: "037E", - questionmonospace: "FF1F", - questionsmall: "F73F", - quotedbl: "0022", - quotedblbase: "201E", - quotedblleft: "201C", - quotedblmonospace: "FF02", - quotedblprime: "301E", - quotedblprimereversed: "301D", - quotedblright: "201D", - quoteleft: "2018", - quoteleftreversed: "201B", - quotereversed: "201B", - quoteright: "2019", - quoterightn: "0149", - quotesinglbase: "201A", - quotesingle: "0027", - quotesinglemonospace: "FF07", - r: "0072", - raarmenian: "057C", - rabengali: "09B0", - racute: "0155", - radeva: "0930", - radical: "221A", - radicalex: "F8E5", - radoverssquare: "33AE", - radoverssquaredsquare: "33AF", - radsquare: "33AD", - rafe: "05BF", - rafehebrew: "05BF", - ragujarati: "0AB0", - ragurmukhi: "0A30", - rahiragana: "3089", - rakatakana: "30E9", - rakatakanahalfwidth: "FF97", - ralowerdiagonalbengali: "09F1", - ramiddlediagonalbengali: "09F0", - ramshorn: "0264", - ratio: "2236", - rbopomofo: "3116", - rcaron: "0159", - rcedilla: "0157", - rcircle: "24E1", - rcommaaccent: "0157", - rdblgrave: "0211", - rdotaccent: "1E59", - rdotbelow: "1E5B", - rdotbelowmacron: "1E5D", - referencemark: "203B", - reflexsubset: "2286", - reflexsuperset: "2287", - registered: "00AE", - registersans: "F8E8", - registerserif: "F6DA", - reharabic: "0631", - reharmenian: "0580", - rehfinalarabic: "FEAE", - rehiragana: "308C", + qparen: 0x24AC, + quarternote: 0x2669, + qubuts: 0x05BB, + qubuts18: 0x05BB, + qubuts25: 0x05BB, + qubuts31: 0x05BB, + qubutshebrew: 0x05BB, + qubutsnarrowhebrew: 0x05BB, + qubutsquarterhebrew: 0x05BB, + qubutswidehebrew: 0x05BB, + question: 0x003F, + questionarabic: 0x061F, + questionarmenian: 0x055E, + questiondown: 0x00BF, + questiondownsmall: 0xF7BF, + questiongreek: 0x037E, + questionmonospace: 0xFF1F, + questionsmall: 0xF73F, + quotedbl: 0x0022, + quotedblbase: 0x201E, + quotedblleft: 0x201C, + quotedblmonospace: 0xFF02, + quotedblprime: 0x301E, + quotedblprimereversed: 0x301D, + quotedblright: 0x201D, + quoteleft: 0x2018, + quoteleftreversed: 0x201B, + quotereversed: 0x201B, + quoteright: 0x2019, + quoterightn: 0x0149, + quotesinglbase: 0x201A, + quotesingle: 0x0027, + quotesinglemonospace: 0xFF07, + r: 0x0072, + raarmenian: 0x057C, + rabengali: 0x09B0, + racute: 0x0155, + radeva: 0x0930, + radical: 0x221A, + radicalex: 0xF8E5, + radoverssquare: 0x33AE, + radoverssquaredsquare: 0x33AF, + radsquare: 0x33AD, + rafe: 0x05BF, + rafehebrew: 0x05BF, + ragujarati: 0x0AB0, + ragurmukhi: 0x0A30, + rahiragana: 0x3089, + rakatakana: 0x30E9, + rakatakanahalfwidth: 0xFF97, + ralowerdiagonalbengali: 0x09F1, + ramiddlediagonalbengali: 0x09F0, + ramshorn: 0x0264, + ratio: 0x2236, + rbopomofo: 0x3116, + rcaron: 0x0159, + rcedilla: 0x0157, + rcircle: 0x24E1, + rcommaaccent: 0x0157, + rdblgrave: 0x0211, + rdotaccent: 0x1E59, + rdotbelow: 0x1E5B, + rdotbelowmacron: 0x1E5D, + referencemark: 0x203B, + reflexsubset: 0x2286, + reflexsuperset: 0x2287, + registered: 0x00AE, + registersans: 0xF8E8, + registerserif: 0xF6DA, + reharabic: 0x0631, + reharmenian: 0x0580, + rehfinalarabic: 0xFEAE, + rehiragana: 0x308C, rehyehaleflamarabic: "0631 FEF3 FE8E 0644", - rekatakana: "30EC", - rekatakanahalfwidth: "FF9A", - resh: "05E8", - reshdageshhebrew: "FB48", + rekatakana: 0x30EC, + rekatakanahalfwidth: 0xFF9A, + resh: 0x05E8, + reshdageshhebrew: 0xFB48, reshhatafpatah: "05E8 05B2", reshhatafpatahhebrew: "05E8 05B2", reshhatafsegol: "05E8 05B1", reshhatafsegolhebrew: "05E8 05B1", - reshhebrew: "05E8", + reshhebrew: 0x05E8, reshhiriq: "05E8 05B4", reshhiriqhebrew: "05E8 05B4", reshholam: "05E8 05B9", @@ -3271,1019 +3271,1019 @@ var GlyphsUnicode = { reshshevahebrew: "05E8 05B0", reshtsere: "05E8 05B5", reshtserehebrew: "05E8 05B5", - reversedtilde: "223D", - reviahebrew: "0597", - reviamugrashhebrew: "0597", - revlogicalnot: "2310", - rfishhook: "027E", - rfishhookreversed: "027F", - rhabengali: "09DD", - rhadeva: "095D", - rho: "03C1", - rhook: "027D", - rhookturned: "027B", - rhookturnedsuperior: "02B5", - rhosymbolgreek: "03F1", - rhotichookmod: "02DE", - rieulacirclekorean: "3271", - rieulaparenkorean: "3211", - rieulcirclekorean: "3263", - rieulhieuhkorean: "3140", - rieulkiyeokkorean: "313A", - rieulkiyeoksioskorean: "3169", - rieulkorean: "3139", - rieulmieumkorean: "313B", - rieulpansioskorean: "316C", - rieulparenkorean: "3203", - rieulphieuphkorean: "313F", - rieulpieupkorean: "313C", - rieulpieupsioskorean: "316B", - rieulsioskorean: "313D", - rieulthieuthkorean: "313E", - rieultikeutkorean: "316A", - rieulyeorinhieuhkorean: "316D", - rightangle: "221F", - righttackbelowcmb: "0319", - righttriangle: "22BF", - rihiragana: "308A", - rikatakana: "30EA", - rikatakanahalfwidth: "FF98", - ring: "02DA", - ringbelowcmb: "0325", - ringcmb: "030A", - ringhalfleft: "02BF", - ringhalfleftarmenian: "0559", - ringhalfleftbelowcmb: "031C", - ringhalfleftcentered: "02D3", - ringhalfright: "02BE", - ringhalfrightbelowcmb: "0339", - ringhalfrightcentered: "02D2", - rinvertedbreve: "0213", - rittorusquare: "3351", - rlinebelow: "1E5F", - rlongleg: "027C", - rlonglegturned: "027A", - rmonospace: "FF52", - rohiragana: "308D", - rokatakana: "30ED", - rokatakanahalfwidth: "FF9B", - roruathai: "0E23", - rparen: "24AD", - rrabengali: "09DC", - rradeva: "0931", - rragurmukhi: "0A5C", - rreharabic: "0691", - rrehfinalarabic: "FB8D", - rrvocalicbengali: "09E0", - rrvocalicdeva: "0960", - rrvocalicgujarati: "0AE0", - rrvocalicvowelsignbengali: "09C4", - rrvocalicvowelsigndeva: "0944", - rrvocalicvowelsigngujarati: "0AC4", - rsuperior: "F6F1", - rtblock: "2590", - rturned: "0279", - rturnedsuperior: "02B4", - ruhiragana: "308B", - rukatakana: "30EB", - rukatakanahalfwidth: "FF99", - rupeemarkbengali: "09F2", - rupeesignbengali: "09F3", - rupiah: "F6DD", - ruthai: "0E24", - rvocalicbengali: "098B", - rvocalicdeva: "090B", - rvocalicgujarati: "0A8B", - rvocalicvowelsignbengali: "09C3", - rvocalicvowelsigndeva: "0943", - rvocalicvowelsigngujarati: "0AC3", - s: "0073", - sabengali: "09B8", - sacute: "015B", - sacutedotaccent: "1E65", - sadarabic: "0635", - sadeva: "0938", - sadfinalarabic: "FEBA", - sadinitialarabic: "FEBB", - sadmedialarabic: "FEBC", - sagujarati: "0AB8", - sagurmukhi: "0A38", - sahiragana: "3055", - sakatakana: "30B5", - sakatakanahalfwidth: "FF7B", - sallallahoualayhewasallamarabic: "FDFA", - samekh: "05E1", - samekhdagesh: "FB41", - samekhdageshhebrew: "FB41", - samekhhebrew: "05E1", - saraaathai: "0E32", - saraaethai: "0E41", - saraaimaimalaithai: "0E44", - saraaimaimuanthai: "0E43", - saraamthai: "0E33", - saraathai: "0E30", - saraethai: "0E40", - saraiileftthai: "F886", - saraiithai: "0E35", - saraileftthai: "F885", - saraithai: "0E34", - saraothai: "0E42", - saraueeleftthai: "F888", - saraueethai: "0E37", - saraueleftthai: "F887", - sarauethai: "0E36", - sarauthai: "0E38", - sarauuthai: "0E39", - sbopomofo: "3119", - scaron: "0161", - scarondotaccent: "1E67", - scedilla: "015F", - schwa: "0259", - schwacyrillic: "04D9", - schwadieresiscyrillic: "04DB", - schwahook: "025A", - scircle: "24E2", - scircumflex: "015D", - scommaaccent: "0219", - sdotaccent: "1E61", - sdotbelow: "1E63", - sdotbelowdotaccent: "1E69", - seagullbelowcmb: "033C", - second: "2033", - secondtonechinese: "02CA", - section: "00A7", - seenarabic: "0633", - seenfinalarabic: "FEB2", - seeninitialarabic: "FEB3", - seenmedialarabic: "FEB4", - segol: "05B6", - segol13: "05B6", - segol1f: "05B6", - segol2c: "05B6", - segolhebrew: "05B6", - segolnarrowhebrew: "05B6", - segolquarterhebrew: "05B6", - segoltahebrew: "0592", - segolwidehebrew: "05B6", - seharmenian: "057D", - sehiragana: "305B", - sekatakana: "30BB", - sekatakanahalfwidth: "FF7E", - semicolon: "003B", - semicolonarabic: "061B", - semicolonmonospace: "FF1B", - semicolonsmall: "FE54", - semivoicedmarkkana: "309C", - semivoicedmarkkanahalfwidth: "FF9F", - sentisquare: "3322", - sentosquare: "3323", - seven: "0037", - sevenarabic: "0667", - sevenbengali: "09ED", - sevencircle: "2466", - sevencircleinversesansserif: "2790", - sevendeva: "096D", - seveneighths: "215E", - sevengujarati: "0AED", - sevengurmukhi: "0A6D", - sevenhackarabic: "0667", - sevenhangzhou: "3027", - sevenideographicparen: "3226", - seveninferior: "2087", - sevenmonospace: "FF17", - sevenoldstyle: "F737", - sevenparen: "247A", - sevenperiod: "248E", - sevenpersian: "06F7", - sevenroman: "2176", - sevensuperior: "2077", - seventeencircle: "2470", - seventeenparen: "2484", - seventeenperiod: "2498", - seventhai: "0E57", - sfthyphen: "00AD", - shaarmenian: "0577", - shabengali: "09B6", - shacyrillic: "0448", - shaddaarabic: "0651", - shaddadammaarabic: "FC61", - shaddadammatanarabic: "FC5E", - shaddafathaarabic: "FC60", + reversedtilde: 0x223D, + reviahebrew: 0x0597, + reviamugrashhebrew: 0x0597, + revlogicalnot: 0x2310, + rfishhook: 0x027E, + rfishhookreversed: 0x027F, + rhabengali: 0x09DD, + rhadeva: 0x095D, + rho: 0x03C1, + rhook: 0x027D, + rhookturned: 0x027B, + rhookturnedsuperior: 0x02B5, + rhosymbolgreek: 0x03F1, + rhotichookmod: 0x02DE, + rieulacirclekorean: 0x3271, + rieulaparenkorean: 0x3211, + rieulcirclekorean: 0x3263, + rieulhieuhkorean: 0x3140, + rieulkiyeokkorean: 0x313A, + rieulkiyeoksioskorean: 0x3169, + rieulkorean: 0x3139, + rieulmieumkorean: 0x313B, + rieulpansioskorean: 0x316C, + rieulparenkorean: 0x3203, + rieulphieuphkorean: 0x313F, + rieulpieupkorean: 0x313C, + rieulpieupsioskorean: 0x316B, + rieulsioskorean: 0x313D, + rieulthieuthkorean: 0x313E, + rieultikeutkorean: 0x316A, + rieulyeorinhieuhkorean: 0x316D, + rightangle: 0x221F, + righttackbelowcmb: 0x0319, + righttriangle: 0x22BF, + rihiragana: 0x308A, + rikatakana: 0x30EA, + rikatakanahalfwidth: 0xFF98, + ring: 0x02DA, + ringbelowcmb: 0x0325, + ringcmb: 0x030A, + ringhalfleft: 0x02BF, + ringhalfleftarmenian: 0x0559, + ringhalfleftbelowcmb: 0x031C, + ringhalfleftcentered: 0x02D3, + ringhalfright: 0x02BE, + ringhalfrightbelowcmb: 0x0339, + ringhalfrightcentered: 0x02D2, + rinvertedbreve: 0x0213, + rittorusquare: 0x3351, + rlinebelow: 0x1E5F, + rlongleg: 0x027C, + rlonglegturned: 0x027A, + rmonospace: 0xFF52, + rohiragana: 0x308D, + rokatakana: 0x30ED, + rokatakanahalfwidth: 0xFF9B, + roruathai: 0x0E23, + rparen: 0x24AD, + rrabengali: 0x09DC, + rradeva: 0x0931, + rragurmukhi: 0x0A5C, + rreharabic: 0x0691, + rrehfinalarabic: 0xFB8D, + rrvocalicbengali: 0x09E0, + rrvocalicdeva: 0x0960, + rrvocalicgujarati: 0x0AE0, + rrvocalicvowelsignbengali: 0x09C4, + rrvocalicvowelsigndeva: 0x0944, + rrvocalicvowelsigngujarati: 0x0AC4, + rsuperior: 0xF6F1, + rtblock: 0x2590, + rturned: 0x0279, + rturnedsuperior: 0x02B4, + ruhiragana: 0x308B, + rukatakana: 0x30EB, + rukatakanahalfwidth: 0xFF99, + rupeemarkbengali: 0x09F2, + rupeesignbengali: 0x09F3, + rupiah: 0xF6DD, + ruthai: 0x0E24, + rvocalicbengali: 0x098B, + rvocalicdeva: 0x090B, + rvocalicgujarati: 0x0A8B, + rvocalicvowelsignbengali: 0x09C3, + rvocalicvowelsigndeva: 0x0943, + rvocalicvowelsigngujarati: 0x0AC3, + s: 0x0073, + sabengali: 0x09B8, + sacute: 0x015B, + sacutedotaccent: 0x1E65, + sadarabic: 0x0635, + sadeva: 0x0938, + sadfinalarabic: 0xFEBA, + sadinitialarabic: 0xFEBB, + sadmedialarabic: 0xFEBC, + sagujarati: 0x0AB8, + sagurmukhi: 0x0A38, + sahiragana: 0x3055, + sakatakana: 0x30B5, + sakatakanahalfwidth: 0xFF7B, + sallallahoualayhewasallamarabic: 0xFDFA, + samekh: 0x05E1, + samekhdagesh: 0xFB41, + samekhdageshhebrew: 0xFB41, + samekhhebrew: 0x05E1, + saraaathai: 0x0E32, + saraaethai: 0x0E41, + saraaimaimalaithai: 0x0E44, + saraaimaimuanthai: 0x0E43, + saraamthai: 0x0E33, + saraathai: 0x0E30, + saraethai: 0x0E40, + saraiileftthai: 0xF886, + saraiithai: 0x0E35, + saraileftthai: 0xF885, + saraithai: 0x0E34, + saraothai: 0x0E42, + saraueeleftthai: 0xF888, + saraueethai: 0x0E37, + saraueleftthai: 0xF887, + sarauethai: 0x0E36, + sarauthai: 0x0E38, + sarauuthai: 0x0E39, + sbopomofo: 0x3119, + scaron: 0x0161, + scarondotaccent: 0x1E67, + scedilla: 0x015F, + schwa: 0x0259, + schwacyrillic: 0x04D9, + schwadieresiscyrillic: 0x04DB, + schwahook: 0x025A, + scircle: 0x24E2, + scircumflex: 0x015D, + scommaaccent: 0x0219, + sdotaccent: 0x1E61, + sdotbelow: 0x1E63, + sdotbelowdotaccent: 0x1E69, + seagullbelowcmb: 0x033C, + second: 0x2033, + secondtonechinese: 0x02CA, + section: 0x00A7, + seenarabic: 0x0633, + seenfinalarabic: 0xFEB2, + seeninitialarabic: 0xFEB3, + seenmedialarabic: 0xFEB4, + segol: 0x05B6, + segol13: 0x05B6, + segol1f: 0x05B6, + segol2c: 0x05B6, + segolhebrew: 0x05B6, + segolnarrowhebrew: 0x05B6, + segolquarterhebrew: 0x05B6, + segoltahebrew: 0x0592, + segolwidehebrew: 0x05B6, + seharmenian: 0x057D, + sehiragana: 0x305B, + sekatakana: 0x30BB, + sekatakanahalfwidth: 0xFF7E, + semicolon: 0x003B, + semicolonarabic: 0x061B, + semicolonmonospace: 0xFF1B, + semicolonsmall: 0xFE54, + semivoicedmarkkana: 0x309C, + semivoicedmarkkanahalfwidth: 0xFF9F, + sentisquare: 0x3322, + sentosquare: 0x3323, + seven: 0x0037, + sevenarabic: 0x0667, + sevenbengali: 0x09ED, + sevencircle: 0x2466, + sevencircleinversesansserif: 0x2790, + sevendeva: 0x096D, + seveneighths: 0x215E, + sevengujarati: 0x0AED, + sevengurmukhi: 0x0A6D, + sevenhackarabic: 0x0667, + sevenhangzhou: 0x3027, + sevenideographicparen: 0x3226, + seveninferior: 0x2087, + sevenmonospace: 0xFF17, + sevenoldstyle: 0xF737, + sevenparen: 0x247A, + sevenperiod: 0x248E, + sevenpersian: 0x06F7, + sevenroman: 0x2176, + sevensuperior: 0x2077, + seventeencircle: 0x2470, + seventeenparen: 0x2484, + seventeenperiod: 0x2498, + seventhai: 0x0E57, + sfthyphen: 0x00AD, + shaarmenian: 0x0577, + shabengali: 0x09B6, + shacyrillic: 0x0448, + shaddaarabic: 0x0651, + shaddadammaarabic: 0xFC61, + shaddadammatanarabic: 0xFC5E, + shaddafathaarabic: 0xFC60, shaddafathatanarabic: "0651 064B", - shaddakasraarabic: "FC62", - shaddakasratanarabic: "FC5F", - shade: "2592", - shadedark: "2593", - shadelight: "2591", - shademedium: "2592", - shadeva: "0936", - shagujarati: "0AB6", - shagurmukhi: "0A36", - shalshelethebrew: "0593", - shbopomofo: "3115", - shchacyrillic: "0449", - sheenarabic: "0634", - sheenfinalarabic: "FEB6", - sheeninitialarabic: "FEB7", - sheenmedialarabic: "FEB8", - sheicoptic: "03E3", - sheqel: "20AA", - sheqelhebrew: "20AA", - sheva: "05B0", - sheva115: "05B0", - sheva15: "05B0", - sheva22: "05B0", - sheva2e: "05B0", - shevahebrew: "05B0", - shevanarrowhebrew: "05B0", - shevaquarterhebrew: "05B0", - shevawidehebrew: "05B0", - shhacyrillic: "04BB", - shimacoptic: "03ED", - shin: "05E9", - shindagesh: "FB49", - shindageshhebrew: "FB49", - shindageshshindot: "FB2C", - shindageshshindothebrew: "FB2C", - shindageshsindot: "FB2D", - shindageshsindothebrew: "FB2D", - shindothebrew: "05C1", - shinhebrew: "05E9", - shinshindot: "FB2A", - shinshindothebrew: "FB2A", - shinsindot: "FB2B", - shinsindothebrew: "FB2B", - shook: "0282", - sigma: "03C3", - sigma1: "03C2", - sigmafinal: "03C2", - sigmalunatesymbolgreek: "03F2", - sihiragana: "3057", - sikatakana: "30B7", - sikatakanahalfwidth: "FF7C", - siluqhebrew: "05BD", - siluqlefthebrew: "05BD", - similar: "223C", - sindothebrew: "05C2", - siosacirclekorean: "3274", - siosaparenkorean: "3214", - sioscieuckorean: "317E", - sioscirclekorean: "3266", - sioskiyeokkorean: "317A", - sioskorean: "3145", - siosnieunkorean: "317B", - siosparenkorean: "3206", - siospieupkorean: "317D", - siostikeutkorean: "317C", - six: "0036", - sixarabic: "0666", - sixbengali: "09EC", - sixcircle: "2465", - sixcircleinversesansserif: "278F", - sixdeva: "096C", - sixgujarati: "0AEC", - sixgurmukhi: "0A6C", - sixhackarabic: "0666", - sixhangzhou: "3026", - sixideographicparen: "3225", - sixinferior: "2086", - sixmonospace: "FF16", - sixoldstyle: "F736", - sixparen: "2479", - sixperiod: "248D", - sixpersian: "06F6", - sixroman: "2175", - sixsuperior: "2076", - sixteencircle: "246F", - sixteencurrencydenominatorbengali: "09F9", - sixteenparen: "2483", - sixteenperiod: "2497", - sixthai: "0E56", - slash: "002F", - slashmonospace: "FF0F", - slong: "017F", - slongdotaccent: "1E9B", - smileface: "263A", - smonospace: "FF53", - sofpasuqhebrew: "05C3", - softhyphen: "00AD", - softsigncyrillic: "044C", - sohiragana: "305D", - sokatakana: "30BD", - sokatakanahalfwidth: "FF7F", - soliduslongoverlaycmb: "0338", - solidusshortoverlaycmb: "0337", - sorusithai: "0E29", - sosalathai: "0E28", - sosothai: "0E0B", - sosuathai: "0E2A", - space: "0020", - spacehackarabic: "0020", - spade: "2660", - spadesuitblack: "2660", - spadesuitwhite: "2664", - sparen: "24AE", - squarebelowcmb: "033B", - squarecc: "33C4", - squarecm: "339D", - squarediagonalcrosshatchfill: "25A9", - squarehorizontalfill: "25A4", - squarekg: "338F", - squarekm: "339E", - squarekmcapital: "33CE", - squareln: "33D1", - squarelog: "33D2", - squaremg: "338E", - squaremil: "33D5", - squaremm: "339C", - squaremsquared: "33A1", - squareorthogonalcrosshatchfill: "25A6", - squareupperlefttolowerrightfill: "25A7", - squareupperrighttolowerleftfill: "25A8", - squareverticalfill: "25A5", - squarewhitewithsmallblack: "25A3", - srsquare: "33DB", - ssabengali: "09B7", - ssadeva: "0937", - ssagujarati: "0AB7", - ssangcieuckorean: "3149", - ssanghieuhkorean: "3185", - ssangieungkorean: "3180", - ssangkiyeokkorean: "3132", - ssangnieunkorean: "3165", - ssangpieupkorean: "3143", - ssangsioskorean: "3146", - ssangtikeutkorean: "3138", - ssuperior: "F6F2", - sterling: "00A3", - sterlingmonospace: "FFE1", - strokelongoverlaycmb: "0336", - strokeshortoverlaycmb: "0335", - subset: "2282", - subsetnotequal: "228A", - subsetorequal: "2286", - succeeds: "227B", - suchthat: "220B", - suhiragana: "3059", - sukatakana: "30B9", - sukatakanahalfwidth: "FF7D", - sukunarabic: "0652", - summation: "2211", - sun: "263C", - superset: "2283", - supersetnotequal: "228B", - supersetorequal: "2287", - svsquare: "33DC", - syouwaerasquare: "337C", - t: "0074", - tabengali: "09A4", - tackdown: "22A4", - tackleft: "22A3", - tadeva: "0924", - tagujarati: "0AA4", - tagurmukhi: "0A24", - taharabic: "0637", - tahfinalarabic: "FEC2", - tahinitialarabic: "FEC3", - tahiragana: "305F", - tahmedialarabic: "FEC4", - taisyouerasquare: "337D", - takatakana: "30BF", - takatakanahalfwidth: "FF80", - tatweelarabic: "0640", - tau: "03C4", - tav: "05EA", - tavdages: "FB4A", - tavdagesh: "FB4A", - tavdageshhebrew: "FB4A", - tavhebrew: "05EA", - tbar: "0167", - tbopomofo: "310A", - tcaron: "0165", - tccurl: "02A8", - tcedilla: "0163", - tcheharabic: "0686", - tchehfinalarabic: "FB7B", - tchehinitialarabic: "FB7C", - tchehmedialarabic: "FB7D", + shaddakasraarabic: 0xFC62, + shaddakasratanarabic: 0xFC5F, + shade: 0x2592, + shadedark: 0x2593, + shadelight: 0x2591, + shademedium: 0x2592, + shadeva: 0x0936, + shagujarati: 0x0AB6, + shagurmukhi: 0x0A36, + shalshelethebrew: 0x0593, + shbopomofo: 0x3115, + shchacyrillic: 0x0449, + sheenarabic: 0x0634, + sheenfinalarabic: 0xFEB6, + sheeninitialarabic: 0xFEB7, + sheenmedialarabic: 0xFEB8, + sheicoptic: 0x03E3, + sheqel: 0x20AA, + sheqelhebrew: 0x20AA, + sheva: 0x05B0, + sheva115: 0x05B0, + sheva15: 0x05B0, + sheva22: 0x05B0, + sheva2e: 0x05B0, + shevahebrew: 0x05B0, + shevanarrowhebrew: 0x05B0, + shevaquarterhebrew: 0x05B0, + shevawidehebrew: 0x05B0, + shhacyrillic: 0x04BB, + shimacoptic: 0x03ED, + shin: 0x05E9, + shindagesh: 0xFB49, + shindageshhebrew: 0xFB49, + shindageshshindot: 0xFB2C, + shindageshshindothebrew: 0xFB2C, + shindageshsindot: 0xFB2D, + shindageshsindothebrew: 0xFB2D, + shindothebrew: 0x05C1, + shinhebrew: 0x05E9, + shinshindot: 0xFB2A, + shinshindothebrew: 0xFB2A, + shinsindot: 0xFB2B, + shinsindothebrew: 0xFB2B, + shook: 0x0282, + sigma: 0x03C3, + sigma1: 0x03C2, + sigmafinal: 0x03C2, + sigmalunatesymbolgreek: 0x03F2, + sihiragana: 0x3057, + sikatakana: 0x30B7, + sikatakanahalfwidth: 0xFF7C, + siluqhebrew: 0x05BD, + siluqlefthebrew: 0x05BD, + similar: 0x223C, + sindothebrew: 0x05C2, + siosacirclekorean: 0x3274, + siosaparenkorean: 0x3214, + sioscieuckorean: 0x317E, + sioscirclekorean: 0x3266, + sioskiyeokkorean: 0x317A, + sioskorean: 0x3145, + siosnieunkorean: 0x317B, + siosparenkorean: 0x3206, + siospieupkorean: 0x317D, + siostikeutkorean: 0x317C, + six: 0x0036, + sixarabic: 0x0666, + sixbengali: 0x09EC, + sixcircle: 0x2465, + sixcircleinversesansserif: 0x278F, + sixdeva: 0x096C, + sixgujarati: 0x0AEC, + sixgurmukhi: 0x0A6C, + sixhackarabic: 0x0666, + sixhangzhou: 0x3026, + sixideographicparen: 0x3225, + sixinferior: 0x2086, + sixmonospace: 0xFF16, + sixoldstyle: 0xF736, + sixparen: 0x2479, + sixperiod: 0x248D, + sixpersian: 0x06F6, + sixroman: 0x2175, + sixsuperior: 0x2076, + sixteencircle: 0x246F, + sixteencurrencydenominatorbengali: 0x09F9, + sixteenparen: 0x2483, + sixteenperiod: 0x2497, + sixthai: 0x0E56, + slash: 0x002F, + slashmonospace: 0xFF0F, + slong: 0x017F, + slongdotaccent: 0x1E9B, + smileface: 0x263A, + smonospace: 0xFF53, + sofpasuqhebrew: 0x05C3, + softhyphen: 0x00AD, + softsigncyrillic: 0x044C, + sohiragana: 0x305D, + sokatakana: 0x30BD, + sokatakanahalfwidth: 0xFF7F, + soliduslongoverlaycmb: 0x0338, + solidusshortoverlaycmb: 0x0337, + sorusithai: 0x0E29, + sosalathai: 0x0E28, + sosothai: 0x0E0B, + sosuathai: 0x0E2A, + space: 0x0020, + spacehackarabic: 0x0020, + spade: 0x2660, + spadesuitblack: 0x2660, + spadesuitwhite: 0x2664, + sparen: 0x24AE, + squarebelowcmb: 0x033B, + squarecc: 0x33C4, + squarecm: 0x339D, + squarediagonalcrosshatchfill: 0x25A9, + squarehorizontalfill: 0x25A4, + squarekg: 0x338F, + squarekm: 0x339E, + squarekmcapital: 0x33CE, + squareln: 0x33D1, + squarelog: 0x33D2, + squaremg: 0x338E, + squaremil: 0x33D5, + squaremm: 0x339C, + squaremsquared: 0x33A1, + squareorthogonalcrosshatchfill: 0x25A6, + squareupperlefttolowerrightfill: 0x25A7, + squareupperrighttolowerleftfill: 0x25A8, + squareverticalfill: 0x25A5, + squarewhitewithsmallblack: 0x25A3, + srsquare: 0x33DB, + ssabengali: 0x09B7, + ssadeva: 0x0937, + ssagujarati: 0x0AB7, + ssangcieuckorean: 0x3149, + ssanghieuhkorean: 0x3185, + ssangieungkorean: 0x3180, + ssangkiyeokkorean: 0x3132, + ssangnieunkorean: 0x3165, + ssangpieupkorean: 0x3143, + ssangsioskorean: 0x3146, + ssangtikeutkorean: 0x3138, + ssuperior: 0xF6F2, + sterling: 0x00A3, + sterlingmonospace: 0xFFE1, + strokelongoverlaycmb: 0x0336, + strokeshortoverlaycmb: 0x0335, + subset: 0x2282, + subsetnotequal: 0x228A, + subsetorequal: 0x2286, + succeeds: 0x227B, + suchthat: 0x220B, + suhiragana: 0x3059, + sukatakana: 0x30B9, + sukatakanahalfwidth: 0xFF7D, + sukunarabic: 0x0652, + summation: 0x2211, + sun: 0x263C, + superset: 0x2283, + supersetnotequal: 0x228B, + supersetorequal: 0x2287, + svsquare: 0x33DC, + syouwaerasquare: 0x337C, + t: 0x0074, + tabengali: 0x09A4, + tackdown: 0x22A4, + tackleft: 0x22A3, + tadeva: 0x0924, + tagujarati: 0x0AA4, + tagurmukhi: 0x0A24, + taharabic: 0x0637, + tahfinalarabic: 0xFEC2, + tahinitialarabic: 0xFEC3, + tahiragana: 0x305F, + tahmedialarabic: 0xFEC4, + taisyouerasquare: 0x337D, + takatakana: 0x30BF, + takatakanahalfwidth: 0xFF80, + tatweelarabic: 0x0640, + tau: 0x03C4, + tav: 0x05EA, + tavdages: 0xFB4A, + tavdagesh: 0xFB4A, + tavdageshhebrew: 0xFB4A, + tavhebrew: 0x05EA, + tbar: 0x0167, + tbopomofo: 0x310A, + tcaron: 0x0165, + tccurl: 0x02A8, + tcedilla: 0x0163, + tcheharabic: 0x0686, + tchehfinalarabic: 0xFB7B, + tchehinitialarabic: 0xFB7C, + tchehmedialarabic: 0xFB7D, tchehmeeminitialarabic: "FB7C FEE4", - tcircle: "24E3", - tcircumflexbelow: "1E71", - tcommaaccent: "0163", - tdieresis: "1E97", - tdotaccent: "1E6B", - tdotbelow: "1E6D", - tecyrillic: "0442", - tedescendercyrillic: "04AD", - teharabic: "062A", - tehfinalarabic: "FE96", - tehhahinitialarabic: "FCA2", - tehhahisolatedarabic: "FC0C", - tehinitialarabic: "FE97", - tehiragana: "3066", - tehjeeminitialarabic: "FCA1", - tehjeemisolatedarabic: "FC0B", - tehmarbutaarabic: "0629", - tehmarbutafinalarabic: "FE94", - tehmedialarabic: "FE98", - tehmeeminitialarabic: "FCA4", - tehmeemisolatedarabic: "FC0E", - tehnoonfinalarabic: "FC73", - tekatakana: "30C6", - tekatakanahalfwidth: "FF83", - telephone: "2121", - telephoneblack: "260E", - telishagedolahebrew: "05A0", - telishaqetanahebrew: "05A9", - tencircle: "2469", - tenideographicparen: "3229", - tenparen: "247D", - tenperiod: "2491", - tenroman: "2179", - tesh: "02A7", - tet: "05D8", - tetdagesh: "FB38", - tetdageshhebrew: "FB38", - tethebrew: "05D8", - tetsecyrillic: "04B5", - tevirhebrew: "059B", - tevirlefthebrew: "059B", - thabengali: "09A5", - thadeva: "0925", - thagujarati: "0AA5", - thagurmukhi: "0A25", - thalarabic: "0630", - thalfinalarabic: "FEAC", - thanthakhatlowleftthai: "F898", - thanthakhatlowrightthai: "F897", - thanthakhatthai: "0E4C", - thanthakhatupperleftthai: "F896", - theharabic: "062B", - thehfinalarabic: "FE9A", - thehinitialarabic: "FE9B", - thehmedialarabic: "FE9C", - thereexists: "2203", - therefore: "2234", - theta: "03B8", - theta1: "03D1", - thetasymbolgreek: "03D1", - thieuthacirclekorean: "3279", - thieuthaparenkorean: "3219", - thieuthcirclekorean: "326B", - thieuthkorean: "314C", - thieuthparenkorean: "320B", - thirteencircle: "246C", - thirteenparen: "2480", - thirteenperiod: "2494", - thonangmonthothai: "0E11", - thook: "01AD", - thophuthaothai: "0E12", - thorn: "00FE", - thothahanthai: "0E17", - thothanthai: "0E10", - thothongthai: "0E18", - thothungthai: "0E16", - thousandcyrillic: "0482", - thousandsseparatorarabic: "066C", - thousandsseparatorpersian: "066C", - three: "0033", - threearabic: "0663", - threebengali: "09E9", - threecircle: "2462", - threecircleinversesansserif: "278C", - threedeva: "0969", - threeeighths: "215C", - threegujarati: "0AE9", - threegurmukhi: "0A69", - threehackarabic: "0663", - threehangzhou: "3023", - threeideographicparen: "3222", - threeinferior: "2083", - threemonospace: "FF13", - threenumeratorbengali: "09F6", - threeoldstyle: "F733", - threeparen: "2476", - threeperiod: "248A", - threepersian: "06F3", - threequarters: "00BE", - threequartersemdash: "F6DE", - threeroman: "2172", - threesuperior: "00B3", - threethai: "0E53", - thzsquare: "3394", - tihiragana: "3061", - tikatakana: "30C1", - tikatakanahalfwidth: "FF81", - tikeutacirclekorean: "3270", - tikeutaparenkorean: "3210", - tikeutcirclekorean: "3262", - tikeutkorean: "3137", - tikeutparenkorean: "3202", - tilde: "02DC", - tildebelowcmb: "0330", - tildecmb: "0303", - tildecomb: "0303", - tildedoublecmb: "0360", - tildeoperator: "223C", - tildeoverlaycmb: "0334", - tildeverticalcmb: "033E", - timescircle: "2297", - tipehahebrew: "0596", - tipehalefthebrew: "0596", - tippigurmukhi: "0A70", - titlocyrilliccmb: "0483", - tiwnarmenian: "057F", - tlinebelow: "1E6F", - tmonospace: "FF54", - toarmenian: "0569", - tohiragana: "3068", - tokatakana: "30C8", - tokatakanahalfwidth: "FF84", - tonebarextrahighmod: "02E5", - tonebarextralowmod: "02E9", - tonebarhighmod: "02E6", - tonebarlowmod: "02E8", - tonebarmidmod: "02E7", - tonefive: "01BD", - tonesix: "0185", - tonetwo: "01A8", - tonos: "0384", - tonsquare: "3327", - topatakthai: "0E0F", - tortoiseshellbracketleft: "3014", - tortoiseshellbracketleftsmall: "FE5D", - tortoiseshellbracketleftvertical: "FE39", - tortoiseshellbracketright: "3015", - tortoiseshellbracketrightsmall: "FE5E", - tortoiseshellbracketrightvertical: "FE3A", - totaothai: "0E15", - tpalatalhook: "01AB", - tparen: "24AF", - trademark: "2122", - trademarksans: "F8EA", - trademarkserif: "F6DB", - tretroflexhook: "0288", - triagdn: "25BC", - triaglf: "25C4", - triagrt: "25BA", - triagup: "25B2", - ts: "02A6", - tsadi: "05E6", - tsadidagesh: "FB46", - tsadidageshhebrew: "FB46", - tsadihebrew: "05E6", - tsecyrillic: "0446", - tsere: "05B5", - tsere12: "05B5", - tsere1e: "05B5", - tsere2b: "05B5", - tserehebrew: "05B5", - tserenarrowhebrew: "05B5", - tserequarterhebrew: "05B5", - tserewidehebrew: "05B5", - tshecyrillic: "045B", - tsuperior: "F6F3", - ttabengali: "099F", - ttadeva: "091F", - ttagujarati: "0A9F", - ttagurmukhi: "0A1F", - tteharabic: "0679", - ttehfinalarabic: "FB67", - ttehinitialarabic: "FB68", - ttehmedialarabic: "FB69", - tthabengali: "09A0", - tthadeva: "0920", - tthagujarati: "0AA0", - tthagurmukhi: "0A20", - tturned: "0287", - tuhiragana: "3064", - tukatakana: "30C4", - tukatakanahalfwidth: "FF82", - tusmallhiragana: "3063", - tusmallkatakana: "30C3", - tusmallkatakanahalfwidth: "FF6F", - twelvecircle: "246B", - twelveparen: "247F", - twelveperiod: "2493", - twelveroman: "217B", - twentycircle: "2473", - twentyhangzhou: "5344", - twentyparen: "2487", - twentyperiod: "249B", - two: "0032", - twoarabic: "0662", - twobengali: "09E8", - twocircle: "2461", - twocircleinversesansserif: "278B", - twodeva: "0968", - twodotenleader: "2025", - twodotleader: "2025", - twodotleadervertical: "FE30", - twogujarati: "0AE8", - twogurmukhi: "0A68", - twohackarabic: "0662", - twohangzhou: "3022", - twoideographicparen: "3221", - twoinferior: "2082", - twomonospace: "FF12", - twonumeratorbengali: "09F5", - twooldstyle: "F732", - twoparen: "2475", - twoperiod: "2489", - twopersian: "06F2", - tworoman: "2171", - twostroke: "01BB", - twosuperior: "00B2", - twothai: "0E52", - twothirds: "2154", - u: "0075", - uacute: "00FA", - ubar: "0289", - ubengali: "0989", - ubopomofo: "3128", - ubreve: "016D", - ucaron: "01D4", - ucircle: "24E4", - ucircumflex: "00FB", - ucircumflexbelow: "1E77", - ucyrillic: "0443", - udattadeva: "0951", - udblacute: "0171", - udblgrave: "0215", - udeva: "0909", - udieresis: "00FC", - udieresisacute: "01D8", - udieresisbelow: "1E73", - udieresiscaron: "01DA", - udieresiscyrillic: "04F1", - udieresisgrave: "01DC", - udieresismacron: "01D6", - udotbelow: "1EE5", - ugrave: "00F9", - ugujarati: "0A89", - ugurmukhi: "0A09", - uhiragana: "3046", - uhookabove: "1EE7", - uhorn: "01B0", - uhornacute: "1EE9", - uhorndotbelow: "1EF1", - uhorngrave: "1EEB", - uhornhookabove: "1EED", - uhorntilde: "1EEF", - uhungarumlaut: "0171", - uhungarumlautcyrillic: "04F3", - uinvertedbreve: "0217", - ukatakana: "30A6", - ukatakanahalfwidth: "FF73", - ukcyrillic: "0479", - ukorean: "315C", - umacron: "016B", - umacroncyrillic: "04EF", - umacrondieresis: "1E7B", - umatragurmukhi: "0A41", - umonospace: "FF55", - underscore: "005F", - underscoredbl: "2017", - underscoremonospace: "FF3F", - underscorevertical: "FE33", - underscorewavy: "FE4F", - union: "222A", - universal: "2200", - uogonek: "0173", - uparen: "24B0", - upblock: "2580", - upperdothebrew: "05C4", - upsilon: "03C5", - upsilondieresis: "03CB", - upsilondieresistonos: "03B0", - upsilonlatin: "028A", - upsilontonos: "03CD", - uptackbelowcmb: "031D", - uptackmod: "02D4", - uragurmukhi: "0A73", - uring: "016F", - ushortcyrillic: "045E", - usmallhiragana: "3045", - usmallkatakana: "30A5", - usmallkatakanahalfwidth: "FF69", - ustraightcyrillic: "04AF", - ustraightstrokecyrillic: "04B1", - utilde: "0169", - utildeacute: "1E79", - utildebelow: "1E75", - uubengali: "098A", - uudeva: "090A", - uugujarati: "0A8A", - uugurmukhi: "0A0A", - uumatragurmukhi: "0A42", - uuvowelsignbengali: "09C2", - uuvowelsigndeva: "0942", - uuvowelsigngujarati: "0AC2", - uvowelsignbengali: "09C1", - uvowelsigndeva: "0941", - uvowelsigngujarati: "0AC1", - v: "0076", - vadeva: "0935", - vagujarati: "0AB5", - vagurmukhi: "0A35", - vakatakana: "30F7", - vav: "05D5", - vavdagesh: "FB35", - vavdagesh65: "FB35", - vavdageshhebrew: "FB35", - vavhebrew: "05D5", - vavholam: "FB4B", - vavholamhebrew: "FB4B", - vavvavhebrew: "05F0", - vavyodhebrew: "05F1", - vcircle: "24E5", - vdotbelow: "1E7F", - vecyrillic: "0432", - veharabic: "06A4", - vehfinalarabic: "FB6B", - vehinitialarabic: "FB6C", - vehmedialarabic: "FB6D", - vekatakana: "30F9", - venus: "2640", - verticalbar: "007C", - verticallineabovecmb: "030D", - verticallinebelowcmb: "0329", - verticallinelowmod: "02CC", - verticallinemod: "02C8", - vewarmenian: "057E", - vhook: "028B", - vikatakana: "30F8", - viramabengali: "09CD", - viramadeva: "094D", - viramagujarati: "0ACD", - visargabengali: "0983", - visargadeva: "0903", - visargagujarati: "0A83", - vmonospace: "FF56", - voarmenian: "0578", - voicediterationhiragana: "309E", - voicediterationkatakana: "30FE", - voicedmarkkana: "309B", - voicedmarkkanahalfwidth: "FF9E", - vokatakana: "30FA", - vparen: "24B1", - vtilde: "1E7D", - vturned: "028C", - vuhiragana: "3094", - vukatakana: "30F4", - w: "0077", - wacute: "1E83", - waekorean: "3159", - wahiragana: "308F", - wakatakana: "30EF", - wakatakanahalfwidth: "FF9C", - wakorean: "3158", - wasmallhiragana: "308E", - wasmallkatakana: "30EE", - wattosquare: "3357", - wavedash: "301C", - wavyunderscorevertical: "FE34", - wawarabic: "0648", - wawfinalarabic: "FEEE", - wawhamzaabovearabic: "0624", - wawhamzaabovefinalarabic: "FE86", - wbsquare: "33DD", - wcircle: "24E6", - wcircumflex: "0175", - wdieresis: "1E85", - wdotaccent: "1E87", - wdotbelow: "1E89", - wehiragana: "3091", - weierstrass: "2118", - wekatakana: "30F1", - wekorean: "315E", - weokorean: "315D", - wgrave: "1E81", - whitebullet: "25E6", - whitecircle: "25CB", - whitecircleinverse: "25D9", - whitecornerbracketleft: "300E", - whitecornerbracketleftvertical: "FE43", - whitecornerbracketright: "300F", - whitecornerbracketrightvertical: "FE44", - whitediamond: "25C7", - whitediamondcontainingblacksmalldiamond: "25C8", - whitedownpointingsmalltriangle: "25BF", - whitedownpointingtriangle: "25BD", - whiteleftpointingsmalltriangle: "25C3", - whiteleftpointingtriangle: "25C1", - whitelenticularbracketleft: "3016", - whitelenticularbracketright: "3017", - whiterightpointingsmalltriangle: "25B9", - whiterightpointingtriangle: "25B7", - whitesmallsquare: "25AB", - whitesmilingface: "263A", - whitesquare: "25A1", - whitestar: "2606", - whitetelephone: "260F", - whitetortoiseshellbracketleft: "3018", - whitetortoiseshellbracketright: "3019", - whiteuppointingsmalltriangle: "25B5", - whiteuppointingtriangle: "25B3", - wihiragana: "3090", - wikatakana: "30F0", - wikorean: "315F", - wmonospace: "FF57", - wohiragana: "3092", - wokatakana: "30F2", - wokatakanahalfwidth: "FF66", - won: "20A9", - wonmonospace: "FFE6", - wowaenthai: "0E27", - wparen: "24B2", - wring: "1E98", - wsuperior: "02B7", - wturned: "028D", - wynn: "01BF", - x: "0078", - xabovecmb: "033D", - xbopomofo: "3112", - xcircle: "24E7", - xdieresis: "1E8D", - xdotaccent: "1E8B", - xeharmenian: "056D", - xi: "03BE", - xmonospace: "FF58", - xparen: "24B3", - xsuperior: "02E3", - y: "0079", - yaadosquare: "334E", - yabengali: "09AF", - yacute: "00FD", - yadeva: "092F", - yaekorean: "3152", - yagujarati: "0AAF", - yagurmukhi: "0A2F", - yahiragana: "3084", - yakatakana: "30E4", - yakatakanahalfwidth: "FF94", - yakorean: "3151", - yamakkanthai: "0E4E", - yasmallhiragana: "3083", - yasmallkatakana: "30E3", - yasmallkatakanahalfwidth: "FF6C", - yatcyrillic: "0463", - ycircle: "24E8", - ycircumflex: "0177", - ydieresis: "00FF", - ydotaccent: "1E8F", - ydotbelow: "1EF5", - yeharabic: "064A", - yehbarreearabic: "06D2", - yehbarreefinalarabic: "FBAF", - yehfinalarabic: "FEF2", - yehhamzaabovearabic: "0626", - yehhamzaabovefinalarabic: "FE8A", - yehhamzaaboveinitialarabic: "FE8B", - yehhamzaabovemedialarabic: "FE8C", - yehinitialarabic: "FEF3", - yehmedialarabic: "FEF4", - yehmeeminitialarabic: "FCDD", - yehmeemisolatedarabic: "FC58", - yehnoonfinalarabic: "FC94", - yehthreedotsbelowarabic: "06D1", - yekorean: "3156", - yen: "00A5", - yenmonospace: "FFE5", - yeokorean: "3155", - yeorinhieuhkorean: "3186", - yerahbenyomohebrew: "05AA", - yerahbenyomolefthebrew: "05AA", - yericyrillic: "044B", - yerudieresiscyrillic: "04F9", - yesieungkorean: "3181", - yesieungpansioskorean: "3183", - yesieungsioskorean: "3182", - yetivhebrew: "059A", - ygrave: "1EF3", - yhook: "01B4", - yhookabove: "1EF7", - yiarmenian: "0575", - yicyrillic: "0457", - yikorean: "3162", - yinyang: "262F", - yiwnarmenian: "0582", - ymonospace: "FF59", - yod: "05D9", - yoddagesh: "FB39", - yoddageshhebrew: "FB39", - yodhebrew: "05D9", - yodyodhebrew: "05F2", - yodyodpatahhebrew: "FB1F", - yohiragana: "3088", - yoikorean: "3189", - yokatakana: "30E8", - yokatakanahalfwidth: "FF96", - yokorean: "315B", - yosmallhiragana: "3087", - yosmallkatakana: "30E7", - yosmallkatakanahalfwidth: "FF6E", - yotgreek: "03F3", - yoyaekorean: "3188", - yoyakorean: "3187", - yoyakthai: "0E22", - yoyingthai: "0E0D", - yparen: "24B4", - ypogegrammeni: "037A", - ypogegrammenigreekcmb: "0345", - yr: "01A6", - yring: "1E99", - ysuperior: "02B8", - ytilde: "1EF9", - yturned: "028E", - yuhiragana: "3086", - yuikorean: "318C", - yukatakana: "30E6", - yukatakanahalfwidth: "FF95", - yukorean: "3160", - yusbigcyrillic: "046B", - yusbigiotifiedcyrillic: "046D", - yuslittlecyrillic: "0467", - yuslittleiotifiedcyrillic: "0469", - yusmallhiragana: "3085", - yusmallkatakana: "30E5", - yusmallkatakanahalfwidth: "FF6D", - yuyekorean: "318B", - yuyeokorean: "318A", - yyabengali: "09DF", - yyadeva: "095F", - z: "007A", - zaarmenian: "0566", - zacute: "017A", - zadeva: "095B", - zagurmukhi: "0A5B", - zaharabic: "0638", - zahfinalarabic: "FEC6", - zahinitialarabic: "FEC7", - zahiragana: "3056", - zahmedialarabic: "FEC8", - zainarabic: "0632", - zainfinalarabic: "FEB0", - zakatakana: "30B6", - zaqefgadolhebrew: "0595", - zaqefqatanhebrew: "0594", - zarqahebrew: "0598", - zayin: "05D6", - zayindagesh: "FB36", - zayindageshhebrew: "FB36", - zayinhebrew: "05D6", - zbopomofo: "3117", - zcaron: "017E", - zcircle: "24E9", - zcircumflex: "1E91", - zcurl: "0291", - zdot: "017C", - zdotaccent: "017C", - zdotbelow: "1E93", - zecyrillic: "0437", - zedescendercyrillic: "0499", - zedieresiscyrillic: "04DF", - zehiragana: "305C", - zekatakana: "30BC", - zero: "0030", - zeroarabic: "0660", - zerobengali: "09E6", - zerodeva: "0966", - zerogujarati: "0AE6", - zerogurmukhi: "0A66", - zerohackarabic: "0660", - zeroinferior: "2080", - zeromonospace: "FF10", - zerooldstyle: "F730", - zeropersian: "06F0", - zerosuperior: "2070", - zerothai: "0E50", - zerowidthjoiner: "FEFF", - zerowidthnonjoiner: "200C", - zerowidthspace: "200B", - zeta: "03B6", - zhbopomofo: "3113", - zhearmenian: "056A", - zhebrevecyrillic: "04C2", - zhecyrillic: "0436", - zhedescendercyrillic: "0497", - zhedieresiscyrillic: "04DD", - zihiragana: "3058", - zikatakana: "30B8", - zinorhebrew: "05AE", - zlinebelow: "1E95", - zmonospace: "FF5A", - zohiragana: "305E", - zokatakana: "30BE", - zparen: "24B5", - zretroflexhook: "0290", - zstroke: "01B6", - zuhiragana: "305A", - zukatakana: "30BA" + tcircle: 0x24E3, + tcircumflexbelow: 0x1E71, + tcommaaccent: 0x0163, + tdieresis: 0x1E97, + tdotaccent: 0x1E6B, + tdotbelow: 0x1E6D, + tecyrillic: 0x0442, + tedescendercyrillic: 0x04AD, + teharabic: 0x062A, + tehfinalarabic: 0xFE96, + tehhahinitialarabic: 0xFCA2, + tehhahisolatedarabic: 0xFC0C, + tehinitialarabic: 0xFE97, + tehiragana: 0x3066, + tehjeeminitialarabic: 0xFCA1, + tehjeemisolatedarabic: 0xFC0B, + tehmarbutaarabic: 0x0629, + tehmarbutafinalarabic: 0xFE94, + tehmedialarabic: 0xFE98, + tehmeeminitialarabic: 0xFCA4, + tehmeemisolatedarabic: 0xFC0E, + tehnoonfinalarabic: 0xFC73, + tekatakana: 0x30C6, + tekatakanahalfwidth: 0xFF83, + telephone: 0x2121, + telephoneblack: 0x260E, + telishagedolahebrew: 0x05A0, + telishaqetanahebrew: 0x05A9, + tencircle: 0x2469, + tenideographicparen: 0x3229, + tenparen: 0x247D, + tenperiod: 0x2491, + tenroman: 0x2179, + tesh: 0x02A7, + tet: 0x05D8, + tetdagesh: 0xFB38, + tetdageshhebrew: 0xFB38, + tethebrew: 0x05D8, + tetsecyrillic: 0x04B5, + tevirhebrew: 0x059B, + tevirlefthebrew: 0x059B, + thabengali: 0x09A5, + thadeva: 0x0925, + thagujarati: 0x0AA5, + thagurmukhi: 0x0A25, + thalarabic: 0x0630, + thalfinalarabic: 0xFEAC, + thanthakhatlowleftthai: 0xF898, + thanthakhatlowrightthai: 0xF897, + thanthakhatthai: 0x0E4C, + thanthakhatupperleftthai: 0xF896, + theharabic: 0x062B, + thehfinalarabic: 0xFE9A, + thehinitialarabic: 0xFE9B, + thehmedialarabic: 0xFE9C, + thereexists: 0x2203, + therefore: 0x2234, + theta: 0x03B8, + theta1: 0x03D1, + thetasymbolgreek: 0x03D1, + thieuthacirclekorean: 0x3279, + thieuthaparenkorean: 0x3219, + thieuthcirclekorean: 0x326B, + thieuthkorean: 0x314C, + thieuthparenkorean: 0x320B, + thirteencircle: 0x246C, + thirteenparen: 0x2480, + thirteenperiod: 0x2494, + thonangmonthothai: 0x0E11, + thook: 0x01AD, + thophuthaothai: 0x0E12, + thorn: 0x00FE, + thothahanthai: 0x0E17, + thothanthai: 0x0E10, + thothongthai: 0x0E18, + thothungthai: 0x0E16, + thousandcyrillic: 0x0482, + thousandsseparatorarabic: 0x066C, + thousandsseparatorpersian: 0x066C, + three: 0x0033, + threearabic: 0x0663, + threebengali: 0x09E9, + threecircle: 0x2462, + threecircleinversesansserif: 0x278C, + threedeva: 0x0969, + threeeighths: 0x215C, + threegujarati: 0x0AE9, + threegurmukhi: 0x0A69, + threehackarabic: 0x0663, + threehangzhou: 0x3023, + threeideographicparen: 0x3222, + threeinferior: 0x2083, + threemonospace: 0xFF13, + threenumeratorbengali: 0x09F6, + threeoldstyle: 0xF733, + threeparen: 0x2476, + threeperiod: 0x248A, + threepersian: 0x06F3, + threequarters: 0x00BE, + threequartersemdash: 0xF6DE, + threeroman: 0x2172, + threesuperior: 0x00B3, + threethai: 0x0E53, + thzsquare: 0x3394, + tihiragana: 0x3061, + tikatakana: 0x30C1, + tikatakanahalfwidth: 0xFF81, + tikeutacirclekorean: 0x3270, + tikeutaparenkorean: 0x3210, + tikeutcirclekorean: 0x3262, + tikeutkorean: 0x3137, + tikeutparenkorean: 0x3202, + tilde: 0x02DC, + tildebelowcmb: 0x0330, + tildecmb: 0x0303, + tildecomb: 0x0303, + tildedoublecmb: 0x0360, + tildeoperator: 0x223C, + tildeoverlaycmb: 0x0334, + tildeverticalcmb: 0x033E, + timescircle: 0x2297, + tipehahebrew: 0x0596, + tipehalefthebrew: 0x0596, + tippigurmukhi: 0x0A70, + titlocyrilliccmb: 0x0483, + tiwnarmenian: 0x057F, + tlinebelow: 0x1E6F, + tmonospace: 0xFF54, + toarmenian: 0x0569, + tohiragana: 0x3068, + tokatakana: 0x30C8, + tokatakanahalfwidth: 0xFF84, + tonebarextrahighmod: 0x02E5, + tonebarextralowmod: 0x02E9, + tonebarhighmod: 0x02E6, + tonebarlowmod: 0x02E8, + tonebarmidmod: 0x02E7, + tonefive: 0x01BD, + tonesix: 0x0185, + tonetwo: 0x01A8, + tonos: 0x0384, + tonsquare: 0x3327, + topatakthai: 0x0E0F, + tortoiseshellbracketleft: 0x3014, + tortoiseshellbracketleftsmall: 0xFE5D, + tortoiseshellbracketleftvertical: 0xFE39, + tortoiseshellbracketright: 0x3015, + tortoiseshellbracketrightsmall: 0xFE5E, + tortoiseshellbracketrightvertical: 0xFE3A, + totaothai: 0x0E15, + tpalatalhook: 0x01AB, + tparen: 0x24AF, + trademark: 0x2122, + trademarksans: 0xF8EA, + trademarkserif: 0xF6DB, + tretroflexhook: 0x0288, + triagdn: 0x25BC, + triaglf: 0x25C4, + triagrt: 0x25BA, + triagup: 0x25B2, + ts: 0x02A6, + tsadi: 0x05E6, + tsadidagesh: 0xFB46, + tsadidageshhebrew: 0xFB46, + tsadihebrew: 0x05E6, + tsecyrillic: 0x0446, + tsere: 0x05B5, + tsere12: 0x05B5, + tsere1e: 0x05B5, + tsere2b: 0x05B5, + tserehebrew: 0x05B5, + tserenarrowhebrew: 0x05B5, + tserequarterhebrew: 0x05B5, + tserewidehebrew: 0x05B5, + tshecyrillic: 0x045B, + tsuperior: 0xF6F3, + ttabengali: 0x099F, + ttadeva: 0x091F, + ttagujarati: 0x0A9F, + ttagurmukhi: 0x0A1F, + tteharabic: 0x0679, + ttehfinalarabic: 0xFB67, + ttehinitialarabic: 0xFB68, + ttehmedialarabic: 0xFB69, + tthabengali: 0x09A0, + tthadeva: 0x0920, + tthagujarati: 0x0AA0, + tthagurmukhi: 0x0A20, + tturned: 0x0287, + tuhiragana: 0x3064, + tukatakana: 0x30C4, + tukatakanahalfwidth: 0xFF82, + tusmallhiragana: 0x3063, + tusmallkatakana: 0x30C3, + tusmallkatakanahalfwidth: 0xFF6F, + twelvecircle: 0x246B, + twelveparen: 0x247F, + twelveperiod: 0x2493, + twelveroman: 0x217B, + twentycircle: 0x2473, + twentyhangzhou: 0x5344, + twentyparen: 0x2487, + twentyperiod: 0x249B, + two: 0x0032, + twoarabic: 0x0662, + twobengali: 0x09E8, + twocircle: 0x2461, + twocircleinversesansserif: 0x278B, + twodeva: 0x0968, + twodotenleader: 0x2025, + twodotleader: 0x2025, + twodotleadervertical: 0xFE30, + twogujarati: 0x0AE8, + twogurmukhi: 0x0A68, + twohackarabic: 0x0662, + twohangzhou: 0x3022, + twoideographicparen: 0x3221, + twoinferior: 0x2082, + twomonospace: 0xFF12, + twonumeratorbengali: 0x09F5, + twooldstyle: 0xF732, + twoparen: 0x2475, + twoperiod: 0x2489, + twopersian: 0x06F2, + tworoman: 0x2171, + twostroke: 0x01BB, + twosuperior: 0x00B2, + twothai: 0x0E52, + twothirds: 0x2154, + u: 0x0075, + uacute: 0x00FA, + ubar: 0x0289, + ubengali: 0x0989, + ubopomofo: 0x3128, + ubreve: 0x016D, + ucaron: 0x01D4, + ucircle: 0x24E4, + ucircumflex: 0x00FB, + ucircumflexbelow: 0x1E77, + ucyrillic: 0x0443, + udattadeva: 0x0951, + udblacute: 0x0171, + udblgrave: 0x0215, + udeva: 0x0909, + udieresis: 0x00FC, + udieresisacute: 0x01D8, + udieresisbelow: 0x1E73, + udieresiscaron: 0x01DA, + udieresiscyrillic: 0x04F1, + udieresisgrave: 0x01DC, + udieresismacron: 0x01D6, + udotbelow: 0x1EE5, + ugrave: 0x00F9, + ugujarati: 0x0A89, + ugurmukhi: 0x0A09, + uhiragana: 0x3046, + uhookabove: 0x1EE7, + uhorn: 0x01B0, + uhornacute: 0x1EE9, + uhorndotbelow: 0x1EF1, + uhorngrave: 0x1EEB, + uhornhookabove: 0x1EED, + uhorntilde: 0x1EEF, + uhungarumlaut: 0x0171, + uhungarumlautcyrillic: 0x04F3, + uinvertedbreve: 0x0217, + ukatakana: 0x30A6, + ukatakanahalfwidth: 0xFF73, + ukcyrillic: 0x0479, + ukorean: 0x315C, + umacron: 0x016B, + umacroncyrillic: 0x04EF, + umacrondieresis: 0x1E7B, + umatragurmukhi: 0x0A41, + umonospace: 0xFF55, + underscore: 0x005F, + underscoredbl: 0x2017, + underscoremonospace: 0xFF3F, + underscorevertical: 0xFE33, + underscorewavy: 0xFE4F, + union: 0x222A, + universal: 0x2200, + uogonek: 0x0173, + uparen: 0x24B0, + upblock: 0x2580, + upperdothebrew: 0x05C4, + upsilon: 0x03C5, + upsilondieresis: 0x03CB, + upsilondieresistonos: 0x03B0, + upsilonlatin: 0x028A, + upsilontonos: 0x03CD, + uptackbelowcmb: 0x031D, + uptackmod: 0x02D4, + uragurmukhi: 0x0A73, + uring: 0x016F, + ushortcyrillic: 0x045E, + usmallhiragana: 0x3045, + usmallkatakana: 0x30A5, + usmallkatakanahalfwidth: 0xFF69, + ustraightcyrillic: 0x04AF, + ustraightstrokecyrillic: 0x04B1, + utilde: 0x0169, + utildeacute: 0x1E79, + utildebelow: 0x1E75, + uubengali: 0x098A, + uudeva: 0x090A, + uugujarati: 0x0A8A, + uugurmukhi: 0x0A0A, + uumatragurmukhi: 0x0A42, + uuvowelsignbengali: 0x09C2, + uuvowelsigndeva: 0x0942, + uuvowelsigngujarati: 0x0AC2, + uvowelsignbengali: 0x09C1, + uvowelsigndeva: 0x0941, + uvowelsigngujarati: 0x0AC1, + v: 0x0076, + vadeva: 0x0935, + vagujarati: 0x0AB5, + vagurmukhi: 0x0A35, + vakatakana: 0x30F7, + vav: 0x05D5, + vavdagesh: 0xFB35, + vavdagesh65: 0xFB35, + vavdageshhebrew: 0xFB35, + vavhebrew: 0x05D5, + vavholam: 0xFB4B, + vavholamhebrew: 0xFB4B, + vavvavhebrew: 0x05F0, + vavyodhebrew: 0x05F1, + vcircle: 0x24E5, + vdotbelow: 0x1E7F, + vecyrillic: 0x0432, + veharabic: 0x06A4, + vehfinalarabic: 0xFB6B, + vehinitialarabic: 0xFB6C, + vehmedialarabic: 0xFB6D, + vekatakana: 0x30F9, + venus: 0x2640, + verticalbar: 0x007C, + verticallineabovecmb: 0x030D, + verticallinebelowcmb: 0x0329, + verticallinelowmod: 0x02CC, + verticallinemod: 0x02C8, + vewarmenian: 0x057E, + vhook: 0x028B, + vikatakana: 0x30F8, + viramabengali: 0x09CD, + viramadeva: 0x094D, + viramagujarati: 0x0ACD, + visargabengali: 0x0983, + visargadeva: 0x0903, + visargagujarati: 0x0A83, + vmonospace: 0xFF56, + voarmenian: 0x0578, + voicediterationhiragana: 0x309E, + voicediterationkatakana: 0x30FE, + voicedmarkkana: 0x309B, + voicedmarkkanahalfwidth: 0xFF9E, + vokatakana: 0x30FA, + vparen: 0x24B1, + vtilde: 0x1E7D, + vturned: 0x028C, + vuhiragana: 0x3094, + vukatakana: 0x30F4, + w: 0x0077, + wacute: 0x1E83, + waekorean: 0x3159, + wahiragana: 0x308F, + wakatakana: 0x30EF, + wakatakanahalfwidth: 0xFF9C, + wakorean: 0x3158, + wasmallhiragana: 0x308E, + wasmallkatakana: 0x30EE, + wattosquare: 0x3357, + wavedash: 0x301C, + wavyunderscorevertical: 0xFE34, + wawarabic: 0x0648, + wawfinalarabic: 0xFEEE, + wawhamzaabovearabic: 0x0624, + wawhamzaabovefinalarabic: 0xFE86, + wbsquare: 0x33DD, + wcircle: 0x24E6, + wcircumflex: 0x0175, + wdieresis: 0x1E85, + wdotaccent: 0x1E87, + wdotbelow: 0x1E89, + wehiragana: 0x3091, + weierstrass: 0x2118, + wekatakana: 0x30F1, + wekorean: 0x315E, + weokorean: 0x315D, + wgrave: 0x1E81, + whitebullet: 0x25E6, + whitecircle: 0x25CB, + whitecircleinverse: 0x25D9, + whitecornerbracketleft: 0x300E, + whitecornerbracketleftvertical: 0xFE43, + whitecornerbracketright: 0x300F, + whitecornerbracketrightvertical: 0xFE44, + whitediamond: 0x25C7, + whitediamondcontainingblacksmalldiamond: 0x25C8, + whitedownpointingsmalltriangle: 0x25BF, + whitedownpointingtriangle: 0x25BD, + whiteleftpointingsmalltriangle: 0x25C3, + whiteleftpointingtriangle: 0x25C1, + whitelenticularbracketleft: 0x3016, + whitelenticularbracketright: 0x3017, + whiterightpointingsmalltriangle: 0x25B9, + whiterightpointingtriangle: 0x25B7, + whitesmallsquare: 0x25AB, + whitesmilingface: 0x263A, + whitesquare: 0x25A1, + whitestar: 0x2606, + whitetelephone: 0x260F, + whitetortoiseshellbracketleft: 0x3018, + whitetortoiseshellbracketright: 0x3019, + whiteuppointingsmalltriangle: 0x25B5, + whiteuppointingtriangle: 0x25B3, + wihiragana: 0x3090, + wikatakana: 0x30F0, + wikorean: 0x315F, + wmonospace: 0xFF57, + wohiragana: 0x3092, + wokatakana: 0x30F2, + wokatakanahalfwidth: 0xFF66, + won: 0x20A9, + wonmonospace: 0xFFE6, + wowaenthai: 0x0E27, + wparen: 0x24B2, + wring: 0x1E98, + wsuperior: 0x02B7, + wturned: 0x028D, + wynn: 0x01BF, + x: 0x0078, + xabovecmb: 0x033D, + xbopomofo: 0x3112, + xcircle: 0x24E7, + xdieresis: 0x1E8D, + xdotaccent: 0x1E8B, + xeharmenian: 0x056D, + xi: 0x03BE, + xmonospace: 0xFF58, + xparen: 0x24B3, + xsuperior: 0x02E3, + y: 0x0079, + yaadosquare: 0x334E, + yabengali: 0x09AF, + yacute: 0x00FD, + yadeva: 0x092F, + yaekorean: 0x3152, + yagujarati: 0x0AAF, + yagurmukhi: 0x0A2F, + yahiragana: 0x3084, + yakatakana: 0x30E4, + yakatakanahalfwidth: 0xFF94, + yakorean: 0x3151, + yamakkanthai: 0x0E4E, + yasmallhiragana: 0x3083, + yasmallkatakana: 0x30E3, + yasmallkatakanahalfwidth: 0xFF6C, + yatcyrillic: 0x0463, + ycircle: 0x24E8, + ycircumflex: 0x0177, + ydieresis: 0x00FF, + ydotaccent: 0x1E8F, + ydotbelow: 0x1EF5, + yeharabic: 0x064A, + yehbarreearabic: 0x06D2, + yehbarreefinalarabic: 0xFBAF, + yehfinalarabic: 0xFEF2, + yehhamzaabovearabic: 0x0626, + yehhamzaabovefinalarabic: 0xFE8A, + yehhamzaaboveinitialarabic: 0xFE8B, + yehhamzaabovemedialarabic: 0xFE8C, + yehinitialarabic: 0xFEF3, + yehmedialarabic: 0xFEF4, + yehmeeminitialarabic: 0xFCDD, + yehmeemisolatedarabic: 0xFC58, + yehnoonfinalarabic: 0xFC94, + yehthreedotsbelowarabic: 0x06D1, + yekorean: 0x3156, + yen: 0x00A5, + yenmonospace: 0xFFE5, + yeokorean: 0x3155, + yeorinhieuhkorean: 0x3186, + yerahbenyomohebrew: 0x05AA, + yerahbenyomolefthebrew: 0x05AA, + yericyrillic: 0x044B, + yerudieresiscyrillic: 0x04F9, + yesieungkorean: 0x3181, + yesieungpansioskorean: 0x3183, + yesieungsioskorean: 0x3182, + yetivhebrew: 0x059A, + ygrave: 0x1EF3, + yhook: 0x01B4, + yhookabove: 0x1EF7, + yiarmenian: 0x0575, + yicyrillic: 0x0457, + yikorean: 0x3162, + yinyang: 0x262F, + yiwnarmenian: 0x0582, + ymonospace: 0xFF59, + yod: 0x05D9, + yoddagesh: 0xFB39, + yoddageshhebrew: 0xFB39, + yodhebrew: 0x05D9, + yodyodhebrew: 0x05F2, + yodyodpatahhebrew: 0xFB1F, + yohiragana: 0x3088, + yoikorean: 0x3189, + yokatakana: 0x30E8, + yokatakanahalfwidth: 0xFF96, + yokorean: 0x315B, + yosmallhiragana: 0x3087, + yosmallkatakana: 0x30E7, + yosmallkatakanahalfwidth: 0xFF6E, + yotgreek: 0x03F3, + yoyaekorean: 0x3188, + yoyakorean: 0x3187, + yoyakthai: 0x0E22, + yoyingthai: 0x0E0D, + yparen: 0x24B4, + ypogegrammeni: 0x037A, + ypogegrammenigreekcmb: 0x0345, + yr: 0x01A6, + yring: 0x1E99, + ysuperior: 0x02B8, + ytilde: 0x1EF9, + yturned: 0x028E, + yuhiragana: 0x3086, + yuikorean: 0x318C, + yukatakana: 0x30E6, + yukatakanahalfwidth: 0xFF95, + yukorean: 0x3160, + yusbigcyrillic: 0x046B, + yusbigiotifiedcyrillic: 0x046D, + yuslittlecyrillic: 0x0467, + yuslittleiotifiedcyrillic: 0x0469, + yusmallhiragana: 0x3085, + yusmallkatakana: 0x30E5, + yusmallkatakanahalfwidth: 0xFF6D, + yuyekorean: 0x318B, + yuyeokorean: 0x318A, + yyabengali: 0x09DF, + yyadeva: 0x095F, + z: 0x007A, + zaarmenian: 0x0566, + zacute: 0x017A, + zadeva: 0x095B, + zagurmukhi: 0x0A5B, + zaharabic: 0x0638, + zahfinalarabic: 0xFEC6, + zahinitialarabic: 0xFEC7, + zahiragana: 0x3056, + zahmedialarabic: 0xFEC8, + zainarabic: 0x0632, + zainfinalarabic: 0xFEB0, + zakatakana: 0x30B6, + zaqefgadolhebrew: 0x0595, + zaqefqatanhebrew: 0x0594, + zarqahebrew: 0x0598, + zayin: 0x05D6, + zayindagesh: 0xFB36, + zayindageshhebrew: 0xFB36, + zayinhebrew: 0x05D6, + zbopomofo: 0x3117, + zcaron: 0x017E, + zcircle: 0x24E9, + zcircumflex: 0x1E91, + zcurl: 0x0291, + zdot: 0x017C, + zdotaccent: 0x017C, + zdotbelow: 0x1E93, + zecyrillic: 0x0437, + zedescendercyrillic: 0x0499, + zedieresiscyrillic: 0x04DF, + zehiragana: 0x305C, + zekatakana: 0x30BC, + zero: 0x0030, + zeroarabic: 0x0660, + zerobengali: 0x09E6, + zerodeva: 0x0966, + zerogujarati: 0x0AE6, + zerogurmukhi: 0x0A66, + zerohackarabic: 0x0660, + zeroinferior: 0x2080, + zeromonospace: 0xFF10, + zerooldstyle: 0xF730, + zeropersian: 0x06F0, + zerosuperior: 0x2070, + zerothai: 0x0E50, + zerowidthjoiner: 0xFEFF, + zerowidthnonjoiner: 0x200C, + zerowidthspace: 0x200B, + zeta: 0x03B6, + zhbopomofo: 0x3113, + zhearmenian: 0x056A, + zhebrevecyrillic: 0x04C2, + zhecyrillic: 0x0436, + zhedescendercyrillic: 0x0497, + zhedieresiscyrillic: 0x04DD, + zihiragana: 0x3058, + zikatakana: 0x30B8, + zinorhebrew: 0x05AE, + zlinebelow: 0x1E95, + zmonospace: 0xFF5A, + zohiragana: 0x305E, + zokatakana: 0x30BE, + zparen: 0x24B5, + zretroflexhook: 0x0290, + zstroke: 0x01B6, + zuhiragana: 0x305A, + zukatakana: 0x30BA }; // Add missing glyphs from the original Adobe's list -GlyphsUnicode["angbracketleft"] = "3008"; -GlyphsUnicode["angbracketright"] = "3009"; -GlyphsUnicode["circlecopyrt"] = "00A9"; +GlyphsUnicode["angbracketleft"] = 0x3008; +GlyphsUnicode["angbracketright"] = 0x3009; +GlyphsUnicode["circlecopyrt"] = 0x00A9; From b82392f41759b90a47fa6b6e67c913734ad28707 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 17 Jun 2011 01:19:59 -0700 Subject: [PATCH 053/439] render at 1.5x scale --- test.css | 4 ++-- test.html | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test.css b/test.css index 0a3449ae9..857eed101 100644 --- a/test.css +++ b/test.css @@ -26,8 +26,8 @@ span#info { #viewer { margin: auto; border: 1px solid black; - width: 8.5in; - height: 11in; + width: 12.75in; + height: 16.5in; } #pageNumber { diff --git a/test.html b/test.html index 023cdeec2..458c50268 100644 --- a/test.html +++ b/test.html @@ -26,8 +26,9 @@
- + are always 96 dpi. 816x1056 is 8.5x11in at 96dpi. --> + +
From 1980f4ef42be2883ba34472d44ec29de43b47abe Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 13:55:42 +0200 Subject: [PATCH 054/439] Clean up some debug leftovers --- fonts.js | 158 +++++++++++++++++++++---------------------------------- pdf.js | 17 ++++-- 2 files changed, 71 insertions(+), 104 deletions(-) diff --git a/fonts.js b/fonts.js index 5390abba4..b9ef5b330 100644 --- a/fonts.js +++ b/fonts.js @@ -31,7 +31,7 @@ var fontCount = 0; var Fonts = { _active: null, get active() { - return this._active || { encoding: [] }; + return this._active; }, set active(aName) { @@ -39,8 +39,11 @@ var Fonts = { }, unicodeFromCode: function fonts_unicodeFromCode(aCode) { - var unicode = GlyphsUnicode[this.active.encoding[aCode]]; - return unicode ? unicode : aCode; + var active = this._active; + if (!active || !active.properties.encoding) + return aCode; + + return GlyphsUnicode[active.properties.encoding[aCode]]; } }; @@ -49,16 +52,10 @@ var Fonts = { * decoding logics whatever type it is (assuming the font type is supported). * * For example to read a Type1 font and to attach it to the document: - * var type1Font = new Font("MyFontName", binaryData, aFontEncoding, "Type1"); + * var type1Font = new Font("MyFontName", binaryFile, propertiesObject); * type1Font.bind(); - * - * As an improvment the last parameter can be replaced by an automatic guess - * of the font type based on the first byte of the file. - * - * FIXME There is now too many parameters, this should be turned into an - * object containing all the required informations about the font */ -var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { +var Font = function(aName, aFile, aProperties) { this.name = aName; // If the font has already been decoded simply return @@ -68,41 +65,40 @@ var Font = function(aName, aFile, aEncoding, aCharset, aBBox, aType) { } fontCount++; - var start = Date.now(); - switch (aType) { + switch (aProperties.type) { case "Type1": - var cff = new CFF(aName, aBBox, aFile); + var cff = new CFF(aName, aFile, aProperties); this.mimetype = "font/otf"; // Wrap the CFF data inside an OTF font file - this.font = this.cover(cff); + this.font = this.cover(cff, aProperties); break; case "TrueType": + // TrueType is disabled for the moment since the sanitizer prevent it + // from loading because of an overdated cmap table return Fonts[aName] = { data: null, - encoding: {}, - charset: null, + properties: { + encoding: {}, + charset: null + }, loading: false }; - // TrueType is disabled for the moment since the sanitizer prevent it - // from loading this.mimetype = "font/ttf"; var ttf = new TrueType(aFile); this.font = ttf.data; break; default: - warn("Font " + aType + " is not supported"); + warn("Font " + aProperties.type + " is not supported"); break; } - var end = Date.now(); Fonts[aName] = { data: this.font, - encoding: aEncoding, - charset: aCharset ? aCharset.slice() : null, + properties: aProperties, loading: true } @@ -204,7 +200,7 @@ Font.prototype = { if (debug) ctx.fillText(testString, 20, 50); - }, 20, this); + }, 50, this); /** Hack end */ @@ -355,7 +351,7 @@ Font.prototype = { idDeltas, idRangeOffsets, glyphsIdsArray); }, - cover: function font_cover(aFont) { + cover: function font_cover(aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); // Required Tables @@ -431,7 +427,7 @@ Font.prototype = { this._createTableEntry(otf, offsets, "OS/2", OS2); //XXX Getting charstrings here seems wrong since this is another CFF glue - var charstrings = aFont.getOrderedCharStrings(aFont.glyphs); + var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); /** CMAP */ cmap = this._createCMAPTable(charstrings); @@ -715,22 +711,11 @@ var TrueType = function(aFile) { ttf.set(tableData, offsets.currentOffset); offsets.currentOffset += tableData.length; - if (0) { - var data = []; - for (var j = 0; j < tableData.length; j++) - d.push(tableData[j]); - log("data for table: " + table.tag + ": " + data); - } - // 4-byte aligned data while (offsets.currentOffset & 3) offsets.currentOffset++; } - var fontData = []; - for (var i = 0; i < ttf.length; i++) - fontData.push(ttf[i]); - this.data = ttf; return; } else if (requiredTables.lenght) { @@ -844,17 +829,11 @@ TrueType.prototype = { /** - * This dictionary holds decoded fonts data. + * Type1Parser encapsulate the needed code for parsing a Type1 font + * program. + * Some of its logic depends on the Type2 charstrings structure. */ var Type1Parser = function() { - // Turn on this flag for additional debugging logs - var debug = false; - - var dump = function(aData) { - if (debug) - log(aData); - }; - /* * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence * of Plaintext Bytes. The function took a key as a parameter which can be @@ -863,8 +842,7 @@ var Type1Parser = function() { var kEexecEncryptionKey = 55665; var kCharStringsEncryptionKey = 4330; - function decrypt(aStream, aKey, aDiscardNumber, aByteArray) { - var start = Date.now(); + function decrypt(aStream, aKey, aDiscardNumber) { var r = aKey, c1 = 52845, c2 = 22719; var decryptedString = []; @@ -872,14 +850,9 @@ var Type1Parser = function() { var count = aStream.length; for (var i = 0; i < count; i++) { value = aStream[i]; - if (aByteArray) - decryptedString[i] = value ^ (r >> 8); - else - decryptedString[i] = String.fromCharCode(value ^ (r >> 8)); + decryptedString[i] = value ^ (r >> 8); r = ((value + r) * c1 + c2) & ((1 << 16) - 1); } - var end = Date.now(); - dump("Time to decrypt string of length " + count + " is " + (end - start)); return decryptedString.slice(aDiscardNumber); }; @@ -1014,8 +987,7 @@ var Type1Parser = function() { } else if (!command) { break; } else if (command == -1) { - log("decodeCharstring: " + charString); - error("Support for Type1 command " + value + " (" + escape + ") is not implemented"); + error("Support for Type1 command " + value + " (" + escape + ") is not implemented in charstring: " + charString); } value = command; @@ -1042,8 +1014,8 @@ var Type1Parser = function() { * Returns an object containing a Subrs array and a CharStrings array * extracted from and eexec encrypted block of data */ - this.extractFontInfo = function(aStream) { - var eexecString = decrypt(aStream, kEexecEncryptionKey, 4, true); + this.extractFontProgram = function t1_extractFontProgram(aStream) { + var eexecString = decrypt(aStream, kEexecEncryptionKey, 4); var subrs = [], glyphs = []; var inSubrs = inGlyphs = false; var glyph = ""; @@ -1052,15 +1024,15 @@ var Type1Parser = function() { var index = 0; var length = 0; - var count = eexecString.length; var c = ""; + var count = eexecString.length; for (var i = 0; i < count; i++) { var c = eexecString[i]; if (inSubrs && c == 0x52) { length = parseInt(length); var data = eexecString.slice(i + 3, i + 3 + length); - var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4, true); + var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4); var subr = decodeCharString(encodedSubr); subrs.push(subr); @@ -1068,7 +1040,7 @@ var Type1Parser = function() { } else if (inGlyphs && c == 0x52) { length = parseInt(length); var data = eexecString.slice(i + 3, i + 3 + length); - var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4, true); + var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4); var subr = decodeCharString(encodedCharstring); glyphs.push({ @@ -1104,36 +1076,37 @@ var Type1Parser = function() { } }; -var CFF = function(aFontName, aFontBBox, aFontFile) { +/** + * Take a Type1 file as input and wrap it into a Compact Font Format (CFF) + * wrapping Type2 charstrings. + */ +var CFF = function(aName, aFile, aProperties) { // Get the data block containing glyphs and subrs informations - var length1 = aFontFile.dict.get("Length1"); - var length2 = aFontFile.dict.get("Length2"); - aFontFile.skip(length1); - var eexecBlock = aFontFile.getBytes(length2); + var length1 = aFile.dict.get("Length1"); + var length2 = aFile.dict.get("Length2"); + aFile.skip(length1); + var eexecBlock = aFile.getBytes(length2); - // Extract informations from it - var start = Date.now(); + // Decrypt the data blocks and retrieve the informations from it var parser = new Type1Parser(); - var fontInfo = parser.extractFontInfo(eexecBlock); - fontInfo.name = aFontName; - fontInfo.bbox = aFontBBox; + var fontInfo = parser.extractFontProgram(eexecBlock); - // XXX This hold the glyph data as if, this should be improved - this.glyphs = fontInfo.charstrings; - - this.data = this.convertToCFF(fontInfo); - var end = Date.now(); + aProperties.subrs = fontInfo.subrs; + aProperties.glyphs = fontInfo.charstrings; + this.data = this.wrap(aName, aProperties); }; CFF.prototype = { createCFFIndexHeader: function(aObjects, aIsByte) { - var data = []; - // First 2 bytes contains the number of objects contained into this index var count = aObjects.length; - if (count ==0) + + // If there is no object, just create an array saying that with another + // offset byte. + if (count == 0) return [0x00, 0x00, 0x00]; + var data = []; var bytes = FontsUtils.integerToBytes(count, 2); for (var i = 0; i < bytes.length; i++) data.push(bytes[i]); @@ -1164,10 +1137,9 @@ CFF.prototype = { encodeNumber: function(aValue) { var x = 0; if (aValue >= -32768 && aValue <= 32767) { - return [ 28, aValue >> 8, aValue ]; + return [ 28, aValue >> 8, aValue & 0xFF ]; } else if (aValue >= (-2147483647-1) && aValue <= 2147483647) { - return [ - 0xFF, aValue >> 24, Value >> 16, aValue >> 8, aValue ]; + return [ 0xFF, aValue >> 24, Value >> 16, aValue >> 8, aValue & 0xFF ]; } else { error("Value: " + aValue + " is not allowed"); } @@ -1220,7 +1192,6 @@ CFF.prototype = { }, flattenCharstring: function(aGlyph, aCharstring, aSubrs) { - var original = aCharstring.slice(); var i = 0; while (true) { var obj = aCharstring[i]; @@ -1324,17 +1295,10 @@ CFF.prototype = { error("failing with i = " + i + " in charstring:" + aCharstring + "(" + aCharstring.length + ")"); }, - convertToCFF: function(aFontInfo) { - var debug = false; - function dump(aMsg) { - if (debug) - log(aMsg); - }; - - var charstrings = this.getOrderedCharStrings(aFontInfo.charstrings); + wrap: function(aName, aProperties) { + var charstrings = this.getOrderedCharStrings(aProperties.glyphs); // Starts the conversion of the Type1 charstrings to Type2 - var start = Date.now(); var charstringsCount = 0; var charstringsDataLength = 0; var glyphs = []; @@ -1342,16 +1306,12 @@ CFF.prototype = { var charstring = charstrings[i].charstring.slice(); var glyph = charstrings[i].glyph; - var flattened = this.flattenCharstring(glyph, charstring, aFontInfo.subrs); + var flattened = this.flattenCharstring(glyph, charstring, aProperties.subrs); glyphs.push(flattened); charstringsCount++; charstringsDataLength += flattened.length; } - var end = Date.now(); - dump("There is " + charstringsCount + " glyphs (size: " + charstringsDataLength + ")"); - dump("Time to flatten the strings is : " + (end -start)); - // Create a CFF font data var cff = new Uint8Array(kMaxFontFileSize); var currentOffset = 0; @@ -1362,7 +1322,7 @@ CFF.prototype = { cff.set(header); // Names Index - var nameIndex = this.createCFFIndexHeader([aFontInfo.name]); + var nameIndex = this.createCFFIndexHeader([aName]); cff.set(nameIndex, currentOffset); currentOffset += nameIndex.length; @@ -1406,7 +1366,7 @@ CFF.prototype = { 248, 31, 4 // Weight ]; - var fontBBox = aFontInfo.bbox; + var fontBBox = aProperties.bbox; for (var i = 0; i < fontBBox.length; i++) topDictIndex = topDictIndex.concat(this.encodeNumber(fontBBox[i])); topDictIndex.push(5) // FontBBox; diff --git a/pdf.js b/pdf.js index fe636bcf9..b8f32226b 100644 --- a/pdf.js +++ b/pdf.js @@ -1737,6 +1737,7 @@ var CanvasGraphics = (function() { // Generate the custom cmap of the font if needed var encodingMap = {}; if (fontDict.has("Encoding")) { + var encoding = xref.fetchIfRef(fontDict.get("Encoding")); if (IsDict(encoding)) { // Build an map between codes and glyphs @@ -1749,6 +1750,7 @@ var CanvasGraphics = (function() { // Get the font charset var charset = descriptor.get("CharSet").split("/"); + } else if (IsName(encoding)) { var encoding = Encodings[encoding]; var widths = xref.fetchIfRef(fontDict.get("Widths")); @@ -1757,15 +1759,20 @@ var CanvasGraphics = (function() { var charset = []; for (var j = 0; j < widths.length; j++) { var index = widths[j]; - if (index) - charset.push(encoding[j + firstchar]); + if (!index) + continue; + charset.push(encoding[j + firstchar]); } } } - var fontBBox = descriptor.get("FontBBox"); - var subtype = fontDict.get("Subtype").name; - new Font(fontName, fontFile, encodingMap, charset, fontBBox, subtype); + var properties = { + type: fontDict.get("Subtype").name, + encoding: encodingMap, + charset: charset, + bbox: descriptor.get("FontBBox") + }; + new Font(fontName, fontFile, properties); } return Fonts[fontName]; }, From 0e5f74b6c294f575c85bcac914768cfc9e3f19e2 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 17 Jun 2011 07:37:14 -0500 Subject: [PATCH 055/439] readXRefStream and PNG predictor 12 --- pdf.js | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 160 insertions(+), 16 deletions(-) diff --git a/pdf.js b/pdf.js index 17537d233..dc2302d2d 100644 --- a/pdf.js +++ b/pdf.js @@ -506,6 +506,94 @@ var FlateStream = (function() { return constructor; })(); +var PredictorStream = (function() { + function constructor(stream, params) { + this.stream = stream; + this.predictor = params.get("Predictor") || 1; + if (this.predictor <= 1) { + return stream; // no prediction + } + if (params.has("EarlyChange")) { + error("EarlyChange predictor parameter is not supported"); + } + this.colors = params.get("Colors") || 1; + this.bitsPerComponent = params.get("BitsPerComponent") || 8; + this.columns = params.get("Columns") || 1; + if (this.colors !== 1 || this.bitsPerComponent !== 8) { + error("Multi-color and multi-byte predictors are not supported"); + } + if (this.predictor < 10 || this.predictor > 15) { + error("Unsupported predictor"); + } + this.currentRow = new Uint8Array(this.columns); + this.pos = 0; + this.bufferLength = 0; + } + + constructor.prototype = { + readRow : function() { + var lastRow = this.currentRow; + var predictor = this.stream.getByte(); + var currentRow = this.stream.getBytes(this.columns), i; + switch (predictor) { + default: + error("Unsupported predictor"); + break; + case 0: + break; + case 2: + for (i = 0; i < currentRow.length; ++i) { + currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF; + } + break; + } + this.pos = 0; + this.bufferLength = currentRow.length; + this.currentRow = currentRow; + }, + getByte : function() { + if (this.pos >= this.bufferLength) { + this.readRow(); + } + return this.currentRow[this.pos++]; + }, + getBytes : function(n) { + var i, bytes; + bytes = new Uint8Array(n); + for (i = 0; i < n; ++i) { + if (this.pos >= this.bufferLength) { + this.readRow(); + } + bytes[i] = this.currentRow[this.pos++]; + } + return bytes; + }, + getChar : function() { + return String.formCharCode(this.getByte()); + }, + lookChar : function() { + if (this.pos >= this.bufferLength) { + this.readRow(); + } + return String.formCharCode(this.currentRow[this.pos]); + }, + skip : function(n) { + var i; + if (!n) { + n = 1; + } + while (n > this.bufferLength - this.pos) { + n -= this.bufferLength - this.pos; + this.readRow(); + if (this.bufferLength === 0) break; + } + this.pos += n; + } + }; + + return constructor; +})(); + var DecryptStream = (function() { function constructor(str, fileKey, encAlgorithm, keyLength) { // TODO @@ -1079,7 +1167,9 @@ var Parser = (function() { this.encAlgorithm, this.keyLength); } - return this.filter(stream, dict); + stream = this.filter(stream, dict); + stream.parameters = dict; + return stream; }, filter: function(stream, dict) { var filter = dict.get2("Filter", "F"); @@ -1104,8 +1194,9 @@ var Parser = (function() { }, makeFilter: function(stream, name, params) { if (name == "FlateDecode" || name == "Fl") { - if (params) - error("params not supported yet for FlateDecode"); + if (params) { + return new PredictorStream(new FlateStream(stream), params); + } return new FlateStream(stream); } else { error("filter '" + name + "' not supported yet"); @@ -1198,10 +1289,10 @@ var XRef = (function() { this.stream = stream; this.entries = []; this.xrefstms = {}; - this.readXRef(startXRef); + var trailerDict = this.readXRef(startXRef); // get the root dictionary (catalog) object - if (!IsRef(this.root = this.trailerDict.get("Root"))) + if (!IsRef(this.root = trailerDict.get("Root"))) error("Invalid root reference"); // prepare the XRef cache @@ -1256,18 +1347,18 @@ var XRef = (function() { error("Invalid XRef table"); // get the 'Prev' pointer - var more = false; + var prev; obj = dict.get("Prev"); if (IsInt(obj)) { - this.prev = obj; - more = true; + prev = obj; } else if (IsRef(obj)) { // certain buggy PDF generators generate "/Prev NNN 0 R" instead // of "/Prev NNN" - this.prev = obj.num; - more = true; + prev = obj.num; + } + if (prev) { + this.readXRef(prev); } - this.trailerDict = dict; // check for 'XRefStm' key if (IsInt(obj = dict.get("XRefStm"))) { @@ -1277,11 +1368,64 @@ var XRef = (function() { this.xrefstms[pos] = 1; // avoid infinite recursion this.readXRef(pos); } - - return more; + return dict; }, - readXRefStream: function(parser) { - error("Invalid XRef stream"); + readXRefStream: function(stream) { + var streamParameters = stream.parameters; + var length = streamParameters.get("Length"); + var byteWidths = streamParameters.get("W"); + var range = streamParameters.get("Index"); + if (!range) { + range = [0, streamParameters.get("Size")]; + } + var i, j; + while (range.length > 0) { + var first = range[0], n = range[1]; + if (!IsInt(first) || !IsInt(n)) { + error("Invalid XRef range fields"); + } + var typeFieldWidth = byteWidths[0], offsetFieldWidth = byteWidths[1], generationFieldWidth = byteWidths[2]; + if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) { + error("Invalid XRef entry fields length"); + } + for (i = 0; i < n; ++i) { + var type = 0, offset = 0, generation = 0; + for (j = 0; j < typeFieldWidth; ++j) { + type = (type << 8) | stream.getByte(); + } + for (j = 0; j < offsetFieldWidth; ++j) { + offset = (offset << 8) | stream.getByte(); + } + for (j = 0; j < generationFieldWidth; ++j) { + generation = (generation << 8) | stream.getByte(); + } + var entry = { offset: offset, gen: generation }; + if (typeFieldWidth > 0) { + switch (type) { + case 0: + entry.free = true; + break; + case 1: + entry.uncompressed = true; + break; + case 2: + break; + default: + error("Invalid XRef entry type"); + break; + } + } + if (!this.entries[first + i]) { + this.entries[first + i] = entry; + } + } + range.splice(0, 2); + } + var prev = streamParameters.get("Prev"); + if (IsInt(prev)) { + this.readXRef(prev); + } + return streamParameters; }, readXRef: function(startXRef) { var stream = this.stream; @@ -1565,7 +1709,7 @@ var PDFDoc = (function() { }, getPage: function(n) { var linearization = this.linearization; - assert(!linearization, "linearized page access not implemented"); + // assert(!linearization, "linearized page access not implemented"); return this.catalog.getPage(n); } }; From 9621727db520301d787e99cd4a3a28b56c07e592 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 10:10:29 -0700 Subject: [PATCH 056/439] stored bytes in flatestream --- pdf.js | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/pdf.js b/pdf.js index 5bf559fcf..656453524 100644 --- a/pdf.js +++ b/pdf.js @@ -73,7 +73,7 @@ var Stream = (function() { var pos = this.pos; var end = pos + length; var strEnd = this.end; - if (end > strEnd) + if (!end || end > strEnd) end = strEnd; this.pos = end; @@ -232,10 +232,12 @@ var FlateStream = (function() { ]), 5]; function constructor(stream) { - this.stream = stream; + var bytes = stream.getBytes(); + var bytesIdx = 0; + this.dict = stream.dict; - var cmf = stream.getByte(); - var flg = stream.getByte(); + var cmf = bytes[bytesIdx++]; + var flg = bytes[bytesIdx++]; if (cmf == -1 || flg == -1) error("Invalid header in flate stream"); if ((cmf & 0x0f) != 0x08) @@ -244,6 +246,9 @@ var FlateStream = (function() { error("Bad FCHECK in flate stream"); if (flg & 0x20) error("FDICT bit set in flate stream"); + + this.bytes = bytes; + this.bytesIdx = bytesIdx; this.eof = false; this.codeSize = 0; this.codeBuf = 0; @@ -254,12 +259,14 @@ var FlateStream = (function() { constructor.prototype = { getBits: function(bits) { - var stream = this.stream; var codeSize = this.codeSize; var codeBuf = this.codeBuf; + var bytes = this.bytes; + var bytesIdx = this.bytesIdx; + var b; while (codeSize < bits) { - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad encoding in flate stream"); codeBuf |= b << codeSize; codeSize += 8; @@ -267,6 +274,7 @@ var FlateStream = (function() { b = codeBuf & ((1 << bits) - 1); this.codeBuf = codeBuf >> bits; this.codeSize = codeSize -= bits; + this.bytesIdx = bytesIdx; return b; }, getCode: function(table) { @@ -274,10 +282,12 @@ var FlateStream = (function() { var maxLen = table[1]; var codeSize = this.codeSize; var codeBuf = this.codeBuf; - var stream = this.stream; + var bytes = this.bytes; + var bytesIdx = this.bytesIdx; + while (codeSize < maxLen) { var b; - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad encoding in flate stream"); codeBuf |= (b << codeSize); codeSize += 8; @@ -289,6 +299,7 @@ var FlateStream = (function() { error("Bad encoding in flate stream"); this.codeBuf = (codeBuf >> codeLen); this.codeSize = (codeSize - codeLen); + this.bytesIdx = bytesIdx; return codeVal; }, ensureBuffer: function(requested) { @@ -390,7 +401,8 @@ var FlateStream = (function() { return [codes, maxLen]; }, readBlock: function() { - var stream = this.stream; + var bytes = this.bytes; + var bytesIdx = this.bytesIdx; // read block header var hdr = this.getBits(3); @@ -400,16 +412,16 @@ var FlateStream = (function() { var b; if (hdr == 0) { // uncompressed block - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad block header in flate stream"); var blockLen = b; - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad block header in flate stream"); blockLen |= (b << 8); - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad block header in flate stream"); var check = b; - if ((b = stream.getByte()) == -1) + if ((b = bytes[bytesIdx++]) == undefined) error("Bad block header in flate stream"); check |= (b << 8); if (check != (~this.blockLen & 0xffff)) @@ -418,7 +430,7 @@ var FlateStream = (function() { var buffer = this.ensureBuffer(bufferLength + blockLen); this.bufferLength = bufferLength + blockLen; for (var n = bufferLength; n < blockLen; ++n) { - if ((b = stream.getByte()) == -1) { + if ((b = bytes[bytesIdx++]) == undefined) { this.eof = true; break; } From e475d03675f5a7dc12807803c1bb45322a6b015c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 20:29:34 +0200 Subject: [PATCH 057/439] Do not assume charset is defined and move some fonts timing to the right place --- pdf.js | 77 ++++++++++++++++++++++++++++++--------------------------- test.js | 55 +++++++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/pdf.js b/pdf.js index b8f32226b..1a1714647 100644 --- a/pdf.js +++ b/pdf.js @@ -1729,52 +1729,57 @@ var CanvasGraphics = (function() { var fontName = descriptor.get("FontName").name; fontName = fontName.replace("+", "_"); - var font = Fonts[fontName]; - if (!font) { - var fontFile = descriptor.get2("FontFile", "FontFile2"); - fontFile = xref.fetchIfRef(fontFile); + var fontFile = descriptor.get2("FontFile", "FontFile2"); + if (!fontFile) + errort("FontFile not found for font: " + fontName); + fontFile = xref.fetchIfRef(fontFile); - // Generate the custom cmap of the font if needed - var encodingMap = {}; - if (fontDict.has("Encoding")) { + // Generate the custom cmap of the font if needed + var encodingMap = {}; + if (fontDict.has("Encoding")) { + var encoding = xref.fetchIfRef(fontDict.get("Encoding")); + if (IsDict(encoding)) { + // Build an map between codes and glyphs + var differences = encoding.get("Differences"); + var index = 0; + for (var j = 0; j < differences.length; j++) { + var data = differences[j]; + IsNum(data) ? index = data : encodingMap[index++] = data; + } - var encoding = xref.fetchIfRef(fontDict.get("Encoding")); - if (IsDict(encoding)) { - // Build an map between codes and glyphs - var differences = encoding.get("Differences"); - var index = 0; - for (var j = 0; j < differences.length; j++) { - var data = differences[j]; - IsNum(data) ? index = data : encodingMap[index++] = data; - } + // Get the font charset if any + var charset = descriptor.get("CharSet"); + if (charset) + charset = charset.split("/"); - // Get the font charset - var charset = descriptor.get("CharSet").split("/"); + } else if (IsName(encoding)) { + var encoding = Encodings[encoding]; + var widths = xref.fetchIfRef(fontDict.get("Widths")); + var firstchar = xref.fetchIfRef(fontDict.get("FirstChar")); - } else if (IsName(encoding)) { - var encoding = Encodings[encoding]; - var widths = xref.fetchIfRef(fontDict.get("Widths")); - var firstchar = xref.fetchIfRef(fontDict.get("FirstChar")); + var charset = []; + for (var j = 0; j < widths.length; j++) { + var index = widths[j]; + if (!index) + continue; - var charset = []; - for (var j = 0; j < widths.length; j++) { - var index = widths[j]; - if (!index) - continue; - charset.push(encoding[j + firstchar]); - } - } - } + charset.push(encoding[j + firstchar]); + } + } + } - var properties = { + var properties = { type: fontDict.get("Subtype").name, encoding: encodingMap, charset: charset, bbox: descriptor.get("FontBBox") - }; - new Font(fontName, fontFile, properties); - } - return Fonts[fontName]; + }; + + return { + name: fontName, + file: fontFile, + properties: properties + } }, beginDrawing: function(mediaBox) { diff --git a/test.js b/test.js index cbfd70c65..59d8167a2 100644 --- a/test.js +++ b/test.js @@ -74,30 +74,43 @@ function displayPage(num) { page.compile(gfx, fonts); var t2 = Date.now(); - var interval = 0; - for (var i = 0; i < fonts.length; i++) { - if (fonts[i].loading) { - interval = 10; - break; + var fontsReady = true; + + // Inspect fonts and translate the missing one + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; } + + new Font(font.name, font.file, font.properties); + fontsReady = false; + } + + function delayLoadFont() { + for (var i = 0; i < count; i++) { + if (Fonts[font.name].loading) + return; + } + clearInterval(pageInterval); + + var t3 = Date.now(); + + page.display(gfx); + + var t4 = Date.now(); + + var infoDisplay = document.getElementById("info"); + infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; }; - // FIXME This need to be replaced by an event - pageInterval = setInterval(function() { - for (var i = 0; i < fonts.length; i++) { - if (fonts[i].loading) - return; - } - var t3 = Date.now(); - - clearInterval(pageInterval); - page.display(gfx); - - var t4 = Date.now(); - - var infoDisplay = document.getElementById("info"); - infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; - }, interval); + if (fontsReady) { + delayLoadFont(); + } else { + pageInterval = setInterval(delayLoadFont, 10); + } } function nextPage() { From 5a4d6793727d21efa088f59c399a59863ff39bb8 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 13:13:25 -0700 Subject: [PATCH 058/439] changed skip in FlateStream to not call getChar --- pdf.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index 03cf6598a..e6dc776df 100644 --- a/pdf.js +++ b/pdf.js @@ -316,9 +316,8 @@ var FlateStream = (function() { return this.buffer = buffer2; }, getByte: function() { - var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength == pos) { + while (this.bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -341,9 +340,8 @@ var FlateStream = (function() { return this.buffer.subarray(pos, end) }, lookChar: function() { - var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength == pos) { + while (this.bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -352,16 +350,15 @@ var FlateStream = (function() { }, getChar: function() { var ch = this.lookChar(); - if (!ch) - return; + // shouldnt matter what the position is if we get past the eof + // so no need to check if ch is undefined this.pos++; return ch; }, skip: function(n) { if (!n) n = 1; - while (n-- > 0) - this.getChar(); + this.pos += n; }, generateHuffmanTable: function(lengths) { var n = lengths.length; From 2170c2408bb32ad74f7e4ec0ef2611f860d50b2e Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 13:32:26 -0700 Subject: [PATCH 059/439] Rearranged predictor interface --- pdf.js | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/pdf.js b/pdf.js index 256e56adf..b591c20f1 100644 --- a/pdf.js +++ b/pdf.js @@ -232,23 +232,6 @@ var FlateStream = (function() { ]), 5]; function constructor(stream, params) { - if (IsDict(params)) { - var predType = params.get("Predictor"); - if (predType && predType > 1) { - var colors = params.get("Colors"); - if (!colors) - colors = 1; - var bpc = params.get("BitsPerComponent"); - if (!bpc) - bpc = 8; - var cols = params.get("Columns"); - if (!cols) - cols = 1; - - this.pred = new FilterPredictor(this, predType, cols, - colors, bpc); - } - } this.stream = stream; this.dict = stream.dict; var cmf = stream.getByte(); @@ -1297,9 +1280,25 @@ var Parser = (function() { }, makeFilter: function(stream, name, params) { if (name == "FlateDecode" || name == "Fl") { - if (params) - error("params not supported yet for FlateDecode"); - return new FlateStream(stream); + var flateStr = new FlateStream(stream); + if (IsDict(params)) { + var predType = params.get("Predictor"); + if (predType && predType > 1) { + var colors = params.get("Colors"); + if (!colors) + colors = 1; + var bpc = params.get("BitsPerComponent"); + if (!bpc) + bpc = 8; + var cols = params.get("Columns"); + if (!cols) + cols = 1; + + flateStr = new FilterPredictor(flateStr, predType, cols, + colors, bpc); + } + } + return flateStr; } else { error("filter '" + name + "' not supported yet"); } From a705db84b02532e2504ade095297bd152041c6b7 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 23:38:01 +0200 Subject: [PATCH 060/439] Fix wrong order of the 'div' command --- fonts.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fonts.js b/fonts.js index b9ef5b330..6c3d13051 100644 --- a/fonts.js +++ b/fonts.js @@ -1235,7 +1235,7 @@ CFF.prototype = { case "div": var num2 = aCharstring[i - 1]; var num1 = aCharstring[i - 2]; - aCharstring.splice(i - 2, 3, num2 / num1); + aCharstring.splice(i - 2, 3, num1 / num2); i -= 2; break; @@ -1354,7 +1354,6 @@ CFF.prototype = { } var charstringsIndex = this.createCFFIndexHeader([[0x40, 0x0E]].concat(glyphs), true); - charstringsIndex = charstringsIndex.join(" ").split(" "); // XXX why? //Top Dict Index var topDictIndex = [ @@ -1388,7 +1387,6 @@ CFF.prototype = { var privateOffset = charstringsOffset + charstringsIndex.length; topDictIndex = topDictIndex.concat(this.encodeNumber(privateOffset)); topDictIndex.push(18); // Private - topDictIndex = topDictIndex.join(" ").split(" "); var indexes = [ topDictIndex, stringsIndex, @@ -1418,7 +1416,6 @@ CFF.prototype = { 139, 12, 14, 28, 0, 55, 19 ]); - privateData = privateData.join(" ").split(" "); cff.set(privateData, currentOffset); currentOffset += privateData.length; From 741191e372dc06d79263adacf1945d0ec3cc7cc8 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 17 Jun 2011 23:39:17 +0200 Subject: [PATCH 061/439] Replace clearTimeout by clearInterval, otherwise we could end up drawing the page in an infinite loop --- test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index 59d8167a2..a8e7ae6e1 100644 --- a/test.js +++ b/test.js @@ -50,8 +50,7 @@ function gotoPage(num) { } function displayPage(num) { - if (pageNum != num) - window.clearTimeout(pageInterval); + window.clearInterval(pageInterval); document.getElementById("pageNumber").value = num; @@ -94,7 +93,7 @@ function displayPage(num) { if (Fonts[font.name].loading) return; } - clearInterval(pageInterval); + window.clearInterval(pageInterval); var t3 = Date.now(); From 9e178e88c8aed733997ac9a0cc2ca9c802084105 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 15:48:17 -0700 Subject: [PATCH 062/439] inline Encodings table into pdf.js and use getters for lazy construction --- Encodings.js | 1552 -------------------------------------------------- pdf.js | 192 ++++++- test.html | 1 - 3 files changed, 184 insertions(+), 1561 deletions(-) delete mode 100644 Encodings.js diff --git a/Encodings.js b/Encodings.js deleted file mode 100644 index d32a399c8..000000000 --- a/Encodings.js +++ /dev/null @@ -1,1552 +0,0 @@ - -var Encodings = { - ExpertEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "space", - "exclamsmall", - "Hungarumlautsmall", - null, - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - null, - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - null, - null, - null, - "isuperior", - null, - null, - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - null, - null, - "rsuperior", - "ssuperior", - "tsuperior", - null, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - null, - "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", - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - null, - null, - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - null, - "Dotaccentsmall", - null, - null, - "Macronsmall", - null, - null, - "figuredash", - "hypheninferior", - null, - null, - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - null, - null, - null, - "onequarter", - "onehalf", - "threequarters", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - null, - null, - "zerosuperior", - "onesuperior", - "twosuperior", - "threesuperior", - "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" - ], - MacExpertEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "space", - "exclamsmall", - "Hungarumlautsmall", - "centoldstyle", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - null, - "threequartersemdash", - null, - "questionsmall", - null, - null, - null, - null, - "Ethsmall", - null, - null, - "onequarter", - "onehalf", - "threequarters", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - null, - null, - null, - null, - null, - null, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - null, - "parenrightinferior", - "Circumflexsmall", - "hypheninferior", - "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", - null, - null, - "asuperior", - "centsuperior", - null, - null, - null, - null, - "Aacutesmall", - "Agravesmall", - "Acircumflexsmall", - "Adieresissmall", - "Atildesmall", - "Aringsmall", - "Ccedillasmall", - "Eacutesmall", - "Egravesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Iacutesmall", - "Igravesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ntildesmall", - "Oacutesmall", - "Ogravesmall", - "Ocircumflexsmall", - "Odieresissmall", - "Otildesmall", - "Uacutesmall", - "Ugravesmall", - "Ucircumflexsmall", - "Udieresissmall", - null, - "eightsuperior", - "fourinferior", - "threeinferior", - "sixinferior", - "eightinferior", - "seveninferior", - "Scaronsmall", - null, - "centinferior", - "twoinferior", - null, - "Dieresissmall", - null, - "Caronsmall", - "osuperior", - "fiveinferior", - null, - "commainferior", - "periodinferior", - "Yacutesmall", - null, - "dollarinferior", - null, - null, - "Thornsmall", - null, - "nineinferior", - "zeroinferior", - "Zcaronsmall", - "AEsmall", - "Oslashsmall", - "questiondownsmall", - "oneinferior", - "Lslashsmall", - null, - null, - null, - null, - null, - null, - "Cedillasmall", - null, - null, - null, - null, - null, - "OEsmall", - "figuredash", - "hyphensuperior", - null, - null, - null, - null, - "exclamdownsmall", - null, - "Ydieresissmall", - null, - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "ninesuperior", - "zerosuperior", - null, - "esuperior", - "rsuperior", - "tsuperior", - null, - null, - "isuperior", - "ssuperior", - "dsuperior", - null, - null, - null, - null, - null, - "lsuperior", - "Ogoneksmall", - "Brevesmall", - "Macronsmall", - "bsuperior", - "nsuperior", - "msuperior", - "commasuperior", - "periodsuperior", - "Dotaccentsmall", - "Ringsmall", - null, - null, - null, - null - ], - MacRomanEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "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", - "grave", - "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", - null, - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Omega", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "Delta", - "guillemotleft", - "guillemotright", - "ellipsis", - "space", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "apple", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron" - ], - StandardEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "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", - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - null, - "endash", - "dagger", - "daggerdbl", - "periodcentered", - null, - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - null, - "questiondown", - null, - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - null, - "ring", - "cedilla", - null, - "hungarumlaut", - "ogonek", - "caron", - "emdash", - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "AE", - null, - "ordfeminine", - null, - null, - null, - null, - "Lslash", - "Oslash", - "OE", - "ordmasculine", - null, - null, - null, - null, - null, - "ae", - null, - null, - null, - "dotlessi", - null, - null, - "lslash", - "oslash", - "oe", - "germandbls", - null, - null, - null, - null - ], - WinAnsiEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "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", - "grave", - "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", - "bullet", - "Euro", - "bullet", - "quotesinglbase", - "florin", - "quotedblbase", - "ellipsis", - "dagger", - "daggerdbl", - "circumflex", - "perthousand", - "Scaron", - "guilsinglleft", - "OE", - "bullet", - "Zcaron", - "bullet", - "bullet", - "quoteleft", - "quoteright", - "quotedblleft", - "quotedblright", - "bullet", - "endash", - "emdash", - "tilde", - "trademark", - "scaron", - "guilsinglright", - "oe", - "bullet", - "zcaron", - "Ydieresis", - "space", - "exclamdown", - "cent", - "sterling", - "currency", - "yen", - "brokenbar", - "section", - "dieresis", - "copyright", - "ordfeminine", - "guillemotleft", - "logicalnot", - "hyphen", - "registered", - "macron", - "degree", - "plusminus", - "twosuperior", - "threesuperior", - "acute", - "mu", - "paragraph", - "periodcentered", - "cedilla", - "onesuperior", - "ordmasculine", - "guillemotright", - "onequarter", - "onehalf", - "threequarters", - "questiondown", - "Agrave", - "Aacute", - "Acircumflex", - "Atilde", - "Adieresis", - "Aring", - "AE", - "Ccedilla", - "Egrave", - "Eacute", - "Ecircumflex", - "Edieresis", - "Igrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Eth", - "Ntilde", - "Ograve", - "Oacute", - "Ocircumflex", - "Otilde", - "Odieresis", - "multiply", - "Oslash", - "Ugrave", - "Uacute", - "Ucircumflex", - "Udieresis", - "Yacute", - "Thorn", - "germandbls", - "agrave", - "aacute", - "acircumflex", - "atilde", - "adieresis", - "aring", - "ae", - "ccedilla", - "egrave", - "eacute", - "ecircumflex", - "edieresis", - "igrave", - "iacute", - "icircumflex", - "idieresis", - "eth", - "ntilde", - "ograve", - "oacute", - "ocircumflex", - "otilde", - "odieresis", - "divide", - "oslash", - "ugrave", - "uacute", - "ucircumflex", - "udieresis", - "yacute", - "thorn", - "ydieresis" - ], - zapfDingbatsEncoding: [ - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "space", - "a1", - "a2", - "a202", - "a3", - "a4", - "a5", - "a119", - "a118", - "a117", - "a11", - "a12", - "a13", - "a14", - "a15", - "a16", - "a105", - "a17", - "a18", - "a19", - "a20", - "a21", - "a22", - "a23", - "a24", - "a25", - "a26", - "a27", - "a28", - "a6", - "a7", - "a8", - "a9", - "a10", - "a29", - "a30", - "a31", - "a32", - "a33", - "a34", - "a35", - "a36", - "a37", - "a38", - "a39", - "a40", - "a41", - "a42", - "a43", - "a44", - "a45", - "a46", - "a47", - "a48", - "a49", - "a50", - "a51", - "a52", - "a53", - "a54", - "a55", - "a56", - "a57", - "a58", - "a59", - "a60", - "a61", - "a62", - "a63", - "a64", - "a65", - "a66", - "a67", - "a68", - "a69", - "a70", - "a71", - "a72", - "a73", - "a74", - "a203", - "a75", - "a204", - "a76", - "a77", - "a78", - "a79", - "a81", - "a82", - "a83", - "a84", - "a97", - "a98", - "a99", - "a100", - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "a101", - "a102", - "a103", - "a104", - "a106", - "a107", - "a108", - "a112", - "a111", - "a110", - "a109", - "a120", - "a121", - "a122", - "a123", - "a124", - "a125", - "a126", - "a127", - "a128", - "a129", - "a130", - "a131", - "a132", - "a133", - "a134", - "a135", - "a136", - "a137", - "a138", - "a139", - "a140", - "a141", - "a142", - "a143", - "a144", - "a145", - "a146", - "a147", - "a148", - "a149", - "a150", - "a151", - "a152", - "a153", - "a154", - "a155", - "a156", - "a157", - "a158", - "a159", - "a160", - "a161", - "a163", - "a164", - "a196", - "a165", - "a192", - "a166", - "a167", - "a168", - "a169", - "a170", - "a171", - "a172", - "a173", - "a162", - "a174", - "a175", - "a176", - "a177", - "a178", - "a179", - "a193", - "a180", - "a199", - "a181", - "a200", - "a182", - null, - "a201", - "a183", - "a184", - "a197", - "a185", - "a194", - "a198", - "a186", - "a195", - "a187", - "a188", - "a189", - "a190", - "a191", - null - ] -}; - diff --git a/pdf.js b/pdf.js index 1a1714647..0a6345799 100644 --- a/pdf.js +++ b/pdf.js @@ -1615,6 +1615,180 @@ var CanvasExtraState = (function() { return constructor; })(); +const Encodings = { + get ExpertEncoding() { + return shadow(this, "ExpertEncoding", [ + "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", + "ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior", + "twodotenleader","onedotenleader","comma","hyphen","period","fraction", + "zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle","fouroldstyle", + "fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle","nineoldstyle", + "colon","semicolon","commasuperior","threequartersemdash","periodsuperior", + "questionsmall",,"asuperior","bsuperior","centsuperior","dsuperior","esuperior",,, + "isuperior",,,"lsuperior","msuperior","nsuperior","osuperior",,,"rsuperior", + "ssuperior","tsuperior",,"ff","fi","fl","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",,,, + "onequarter","onehalf","threequarters","questiondownsmall","oneeighth", + "threeeighths","fiveeighths","seveneighths","onethird","twothirds",,, + "zerosuperior","onesuperior","twosuperior","threesuperior","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" + ]); + }, + get MacExpertEncoding() { + return shadow(this, "MacExpertEncoding", [ + "space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle", + "dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior", + "parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period", + "fraction","zerooldstyle","oneoldstyle","twooldstyle","threeoldstyle", + "fouroldstyle","fiveoldstyle","sixoldstyle","sevenoldstyle","eightoldstyle", + "nineoldstyle","colon","semicolon",,"threequartersemdash",,"questionsmall",,,,, + "Ethsmall",,,"onequarter","onehalf","threequarters","oneeighth","threeeighths", + "fiveeighths","seveneighths","onethird","twothirds",,,,,,,"ff","fi","fl","ffi", + "ffl","parenleftinferior",,"parenrightinferior","Circumflexsmall", + "hypheninferior","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",,, + "asuperior","centsuperior",,,,,"Aacutesmall","Agravesmall","Acircumflexsmall", + "Adieresissmall","Atildesmall","Aringsmall","Ccedillasmall","Eacutesmall", + "Egravesmall","Ecircumflexsmall","Edieresissmall","Iacutesmall","Igravesmall", + "Icircumflexsmall","Idieresissmall","Ntildesmall","Oacutesmall","Ogravesmall", + "Ocircumflexsmall","Odieresissmall","Otildesmall","Uacutesmall","Ugravesmall", + "Ucircumflexsmall","Udieresissmall",,"eightsuperior","fourinferior", + "threeinferior","sixinferior","eightinferior","seveninferior","Scaronsmall",, + "centinferior","twoinferior",,"Dieresissmall",,"Caronsmall","osuperior", + "fiveinferior",,"commainferior","periodinferior","Yacutesmall",,"dollarinferior",, + "Thornsmall",,"nineinferior","zeroinferior","Zcaronsmall","AEsmall","Oslashsmall", + "questiondownsmall","oneinferior","Lslashsmall",,,,,,,"Cedillasmall",,,,,, + "OEsmall","figuredash","hyphensuperior",,,,,"exclamdownsmall",,"Ydieresissmall",, + "onesuperior","twosuperior","threesuperior","foursuperior","fivesuperior", + "sixsuperior","sevensuperior","ninesuperior","zerosuperior",,"esuperior", + "rsuperior","tsuperior",,,"isuperior","ssuperior","dsuperior",,,,,,"lsuperior", + "Ogoneksmall","Brevesmall","Macronsmall","bsuperior","nsuperior","msuperior", + "commasuperior","periodsuperior","Dotaccentsmall","Ringsmall",,, + ]); + }, + get MacRomanEncoding() { + return shadow(this, "MacRomanEncoding", [ + "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", + "quotesingle","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", + "grave","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",, + "Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis","aacute", + "agrave","acircumflex","adieresis","atilde","aring","ccedilla","eacute","egrave", + "ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis","ntilde", + "oacute","ograve","ocircumflex","odieresis","otilde","uacute","ugrave", + "ucircumflex","udieresis","dagger","degree","cent","sterling","section","bullet", + "paragraph","germandbls","registered","copyright","trademark","acute","dieresis", + "notequal","AE","Oslash","infinity","plusminus","lessequal","greaterequal","yen", + "mu","partialdiff","summation","product","pi","integral","ordfeminine", + "ordmasculine","Omega","ae","oslash","questiondown","exclamdown","logicalnot", + "radical","florin","approxequal","Delta","guillemotleft","guillemotright", + "ellipsis","space","Agrave","Atilde","Otilde","OE","oe","endash","emdash", + "quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge", + "ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright", + "fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase", + "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave","Iacute", + "Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple","Ograve", + "Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde","macron","breve", + "dotaccent","ring","cedilla","hungarumlaut","ogonek","caron" + ]); + }, + get StandardEncoding() { + return shadow(this, "StandardEncoding", [ + "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",,, + ]); + }, + get WinAnsiEncoding() { + return shadow(this, "WinAnsiEncoding", [ + "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", + "quotesingle","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", + "grave","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", + "bullet","Euro","bullet","quotesinglbase","florin","quotedblbase","ellipsis", + "dagger","daggerdbl","circumflex","perthousand","Scaron","guilsinglleft","OE", + "bullet","Zcaron","bullet","bullet","quoteleft","quoteright","quotedblleft", + "quotedblright","bullet","endash","emdash","tilde","trademark","scaron", + "guilsinglright","oe","bullet","zcaron","Ydieresis","space","exclamdown","cent", + "sterling","currency","yen","brokenbar","section","dieresis","copyright", + "ordfeminine","guillemotleft","logicalnot","hyphen","registered","macron", + "degree","plusminus","twosuperior","threesuperior","acute","mu","paragraph", + "periodcentered","cedilla","onesuperior","ordmasculine","guillemotright", + "onequarter","onehalf","threequarters","questiondown","Agrave","Aacute", + "Acircumflex","Atilde","Adieresis","Aring","AE","Ccedilla","Egrave","Eacute", + "Ecircumflex","Edieresis","Igrave","Iacute","Icircumflex","Idieresis","Eth", + "Ntilde","Ograve","Oacute","Ocircumflex","Otilde","Odieresis","multiply","Oslash", + "Ugrave","Uacute","Ucircumflex","Udieresis","Yacute","Thorn","germandbls", + "agrave","aacute","acircumflex","atilde","adieresis","aring","ae","ccedilla", + "egrave","eacute","ecircumflex","edieresis","igrave","iacute","icircumflex", + "idieresis","eth","ntilde","ograve","oacute","ocircumflex","otilde","odieresis", + "divide","oslash","ugrave","uacute","ucircumflex","udieresis","yacute","thorn", + "ydieresis" + ]); + }, + get zapfDingbatsEncoding() { + return shadow(this, "zapfDingbatsEncoding", [ + "space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13", + "a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25", + "a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34", + "a35","a36","a37","a38","a39","a40","a41","a42","a43","a44","a45","a46","a47", + "a48","a49","a50","a51","a52","a53","a54","a55","a56","a57","a58","a59","a60", + "a61","a62","a63","a64","a65","a66","a67","a68","a69","a70","a71","a72","a73", + "a74","a203","a75","a204","a76","a77","a78","a79","a81","a82","a83","a84","a97", + "a98","a99","a100",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"a101","a102","a103","a104", + "a106","a107","a108","a112","a111","a110","a109","a120","a121","a122","a123", + "a124","a125","a126","a127","a128","a129","a130","a131","a132","a133","a134", + "a135","a136","a137","a138","a139","a140","a141","a142","a143","a144","a145", + "a146","a147","a148","a149","a150","a151","a152","a153","a154","a155","a156", + "a157","a158","a159","a160","a161","a163","a164","a196","a165","a192","a166", + "a167","a168","a169","a170","a171","a172","a173","a162","a174","a175","a176", + "a177","a178","a179","a193","a180","a199","a181","a200","a182",,"a201","a183", + "a184","a197","a185","a194","a198","a186","a195","a187","a188","a189","a190", + "a191" + ]); + } +}; + var CanvasGraphics = (function() { function constructor(canvasCtx) { this.ctx = canvasCtx; @@ -1731,7 +1905,7 @@ var CanvasGraphics = (function() { var fontFile = descriptor.get2("FontFile", "FontFile2"); if (!fontFile) - errort("FontFile not found for font: " + fontName); + error("FontFile not found for font: " + fontName); fontFile = xref.fetchIfRef(fontFile); // Generate the custom cmap of the font if needed @@ -1754,16 +1928,18 @@ var CanvasGraphics = (function() { } else if (IsName(encoding)) { var encoding = Encodings[encoding]; - var widths = xref.fetchIfRef(fontDict.get("Widths")); - var firstchar = xref.fetchIfRef(fontDict.get("FirstChar")); + if (!encoding) + error("Unknown encoding"); + var widths = xref.fetchIfRef(fontDict.get("Widths")); + var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); + alert(firstchar); + assertWellFormed(IsArray(widths) && IsInteger(firstChar), + "invalid Widths or FirstChar"); var charset = []; for (var j = 0; j < widths.length; j++) { - var index = widths[j]; - if (!index) - continue; - - charset.push(encoding[j + firstchar]); + if (widths[j]) + charset.push(encoding[j + firstChar]); } } } diff --git a/test.html b/test.html index 458c50268..dfe422e64 100644 --- a/test.html +++ b/test.html @@ -7,7 +7,6 @@ - From 8ce051c57978450d03098bec1b25e7ed342d7121 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 16:06:02 -0700 Subject: [PATCH 063/439] Working version of predictors --- pdf.js | 154 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/pdf.js b/pdf.js index b591c20f1..e39fcf6ff 100644 --- a/pdf.js +++ b/pdf.js @@ -18,6 +18,7 @@ function warn(msg) { } function error(msg) { + console.trace(); throw new Error(msg); } @@ -231,7 +232,7 @@ var FlateStream = (function() { 0x50007, 0x50017, 0x5000f, 0x00000 ]), 5]; - function constructor(stream, params) { + function constructor(stream) { this.stream = stream; this.dict = stream.dict; var cmf = stream.getByte(); @@ -510,6 +511,8 @@ var FlateStream = (function() { var FilterPredictor = (function() { function constructor(str, type, width, colors, bits) { this.str = str; + this.dict = str.dict; + this.type = type; this.width = width; this.colors = colors; @@ -536,11 +539,17 @@ var FilterPredictor = (function() { if(!this.getNextLine()) return; } - return this.prevLine[this.prevIdx]; + return this.prevLine[this.prevIdx++]; + }, + getBytes: function(length) { + var buf = new Uint8Array(length); + for (var i = 0; i < length; ++i) + buf[i] = this.getByte(); + return buf; }, getNextLine: function() { if (this.type >= 10) { - var curType = this.str.getRawByte(); + var curType = this.str.getByte(); if (!curType) return; curType += 10; @@ -550,7 +559,7 @@ var FilterPredictor = (function() { var line = []; for (var i = 0; i < this.rowBytes - this.pixBytes; i++) - line.push(this.str.getRawByte()); + line.push(this.str.getByte()); var pixBytes = this.pixBytes; var rowBytes = this.rowBytes; @@ -560,62 +569,62 @@ var FilterPredictor = (function() { for (var i = 0, ii = pixBytes + 1; i < ii; ++i) upLeftBuf.push(0); - for (var i = pixBytes, ii = rowBybtes; i < ii; ++i) { + for (var i = pixBytes, ii = rowBytes; i < ii; ++i) { for (var j = pixBytes; j > 0; --j) { upLeftBuf[j] = upLeftBuf[j - 1]; - upLeftBuf[0] = prevLine[i]; + } + upLeftBuf[0] = prevLine[i]; - var c = line[i - pixBytes]; - if (!c) { - if (i > pixBytes) - break; - return; - } - switch (curType) { - case 11: - prevLine[i] = prevLine[i - pixBytes] + c; + var c = line[i - pixBytes]; + if (c == undefined) { + if (i > pixBytes) break; - case 12: - prevLine[i] = prevLine[i] + c; - break; - case 13: - prevLine[i] = ((prevLine[i - pixBytes] - + prevLine[i]) >> 1) + c; - break; - case 14: - var left = prevLine[i - pixBytes]; - var up = prevLine[i]; - var upLeft = upLeftBuf[pixBytes]; - var p = left + up - upLeft; + return; + } + switch (curType) { + case 11: + prevLine[i] = prevLine[i - pixBytes] + c; + break; + case 12: + prevLine[i] = prevLine[i] + c; + break; + case 13: + prevLine[i] = ((prevLine[i - pixBytes] + + prevLine[i]) >> 1) + c; + break; + case 14: + var left = prevLine[i - pixBytes]; + var up = prevLine[i]; + var upLeft = upLeftBuf[pixBytes]; + var p = left + up - upLeft; - var pa = p - left; - if (pa < 0) - pa = -pa; - var pb = p - up; - if (pb < 0) + var pa = p - left; + if (pa < 0) + pa = -pa; + var pb = p - up; + if (pb < 0) pb = -pb; - var pc = p - upLeft; - if (pc < 0) - pc = -pc; + var pc = p - upLeft; + if (pc < 0) + pc = -pc; - if (pa <= pb && pa <= pc) - prevLine[i] = left + c; - else if (pb <= pc) - prevLine[i] = up + c; - else - prevLine[i] = upLeft + c; - break; - case 10: - default: - prevLine[i] = c; - break; - } + if (pa <= pb && pa <= pc) + prevLine[i] = left + c; + else if (pb <= pc) + prevLine[i] = up + c; + else + prevLine[i] = upLeft + c; + break; + case 10: + default: + prevLine[i] = c; + break; } } var bits = this.bits; var colors = this.colors; - if (curPred === 2) { + if (curType === 2) { if (bits === 1) { var inbuf = prevLine[pixBytes - 1]; for (var i = pixBytes; i < rowBytes; i+= 8) { @@ -656,7 +665,7 @@ var FilterPredictor = (function() { } } } - prevIdx = pixBytes; + this.prevIdx = pixBytes; return true; } }; @@ -680,9 +689,9 @@ var Name = (function() { } constructor.prototype = { - toString: function() { - return this.name; - } + toString: function() { + return this.name; + } }; return constructor; @@ -694,9 +703,9 @@ var Cmd = (function() { } constructor.prototype = { - toString: function() { - return this.cmd; - } + toString: function() { + return this.cmd; + } }; return constructor; @@ -709,18 +718,18 @@ var Dict = (function() { constructor.prototype = { get: function(key) { - return this.map[key]; - }, - get2: function(key1, key2) { - return this.get(key1) || this.get(key2); - }, - has: function(key) { - return key in this.map; - }, - set: function(key, value) { - this.map[key] = value; - }, - forEach: function(aCallback) { + return this.map[key]; + }, + get2: function(key1, key2) { + return this.get(key1) || this.get(key2); + }, + has: function(key) { + return key in this.map; + }, + set: function(key, value) { + this.map[key] = value; + }, + forEach: function(aCallback) { for (var key in this.map) aCallback(key, this.map[key]); }, @@ -784,7 +793,7 @@ function IsArray(v) { } function IsStream(v) { - return typeof v == "object" && "getChar" in v; + return typeof v == "object" && "getByte" in v; } function IsRef(v) { @@ -1294,6 +1303,7 @@ var Parser = (function() { if (!cols) cols = 1; + log("Predictor being used"); flateStr = new FilterPredictor(flateStr, predType, cols, colors, bpc); } @@ -2529,7 +2539,7 @@ var CanvasGraphics = (function() { var smask = image.dict.get("SMask"); smask = xref.fetchIfRef(smask); - if (IsStream(smask)) { + if (smask) { if (inline) error("cannot combine smask and inlining"); @@ -2559,8 +2569,6 @@ var CanvasGraphics = (function() { if (maskDecode) TODO("Handle mask decode"); // handle matte object - } else { - smask = null; } var tmpCanvas = document.createElement("canvas"); @@ -2573,7 +2581,7 @@ var CanvasGraphics = (function() { if (bitsPerComponent != 8) error("unhandled number of bits per component"); - if (smask) { + if (false && smask) { if (maskColorSpace.numComps != 1) error("Incorrect number of components in smask"); @@ -2711,6 +2719,8 @@ var ColorSpace = (function() { case "DeviceGray": case "G": this.numComps = 1; + case "DeviceRGB": + this.numComps = 3; break; } TODO("fill in color space constructor"); From 47a83035120b6b3d64e86be04101e5dc064e324d Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 16:07:09 -0700 Subject: [PATCH 064/439] move cffStandardStrings into utils/ along with font_utils.js --- fonts.js | 58 +++++++++++++++++++ test.html | 1 - .../cffStandardStrings.js | 0 fonts_utils.js => utils/fonts_utils.js | 0 4 files changed, 58 insertions(+), 1 deletion(-) rename cffStandardStrings.js => utils/cffStandardStrings.js (100%) rename fonts_utils.js => utils/fonts_utils.js (100%) diff --git a/fonts.js b/fonts.js index b9ef5b330..be4007d24 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/test.html b/test.html index dfe422e64..600ff3c57 100644 --- a/test.html +++ b/test.html @@ -6,7 +6,6 @@ - diff --git a/cffStandardStrings.js b/utils/cffStandardStrings.js similarity index 100% rename from cffStandardStrings.js rename to utils/cffStandardStrings.js diff --git a/fonts_utils.js b/utils/fonts_utils.js similarity index 100% rename from fonts_utils.js rename to utils/fonts_utils.js From 3f5974da32332f2c962e9e2f73f4ec61b08188ea Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 16:20:13 -0700 Subject: [PATCH 065/439] rename test.html to viewer.html --- glyphlist.js | 8 ++++---- test.css => viewer.css | 0 test.html => viewer.html | 4 ++-- test.js => viewer.js | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename test.css => viewer.css (100%) rename test.html => viewer.html (90%) rename test.js => viewer.js (100%) diff --git a/glyphlist.js b/glyphlist.js index f5a11b522..1a0190133 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -4282,8 +4282,8 @@ var GlyphsUnicode = { zukatakana: 0x30BA }; -// Add missing glyphs from the original Adobe's list -GlyphsUnicode["angbracketleft"] = 0x3008; -GlyphsUnicode["angbracketright"] = 0x3009; -GlyphsUnicode["circlecopyrt"] = 0x00A9; +// Add missing glyphs from the Adobe's original list +GlyphsUnicode.angbracketleft = 0x3008; +GlyphsUnicode.angbracketright = 0x3009; +GlyphsUnicode.circlecopyrt = 0x00A9; diff --git a/test.css b/viewer.css similarity index 100% rename from test.css rename to viewer.css diff --git a/test.html b/viewer.html similarity index 90% rename from test.html rename to viewer.html index 600ff3c57..6e733319e 100644 --- a/test.html +++ b/viewer.html @@ -1,9 +1,9 @@ Simple pdf.js page viewer - + - + diff --git a/test.js b/viewer.js similarity index 100% rename from test.js rename to viewer.js From 49c4196ec0c6f1ca5459412a0f10ab1cd72b5fe8 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 16:29:48 -0700 Subject: [PATCH 066/439] add more error checking for font translation --- pdf.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index 0a6345799..d656db87b 100644 --- a/pdf.js +++ b/pdf.js @@ -1900,8 +1900,10 @@ var CanvasGraphics = (function() { constructor.prototype = { translateFont: function(fontDict, xref, resources) { var descriptor = xref.fetch(fontDict.get("FontDescriptor")); - var fontName = descriptor.get("FontName").name; - fontName = fontName.replace("+", "_"); + + var fontName = descriptor.get("FontName"); + assertWellFormed(IsName(fontName), "invalid font name"); + fontName = fontName.name.replace("+", "_"); var fontFile = descriptor.get2("FontFile", "FontFile2"); if (!fontFile) @@ -1923,17 +1925,16 @@ var CanvasGraphics = (function() { // Get the font charset if any var charset = descriptor.get("CharSet"); - if (charset) - charset = charset.split("/"); + assertWellFormed(IsString(charset), "invalid charset"); + charset = charset.split("/"); } else if (IsName(encoding)) { - var encoding = Encodings[encoding]; + var encoding = Encodings[encoding.name]; if (!encoding) error("Unknown encoding"); var widths = xref.fetchIfRef(fontDict.get("Widths")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); - alert(firstchar); assertWellFormed(IsArray(widths) && IsInteger(firstChar), "invalid Widths or FirstChar"); var charset = []; @@ -1953,8 +1954,8 @@ var CanvasGraphics = (function() { return { name: fontName, - file: fontFile, - properties: properties + file: fontFile, + properties: properties } }, From 120a4a3f383cad41db6e1facfa582d6ace297e14 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 16:34:29 -0700 Subject: [PATCH 067/439] even more error checking for font translation --- pdf.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index d656db87b..56ab89017 100644 --- a/pdf.js +++ b/pdf.js @@ -1931,12 +1931,12 @@ var CanvasGraphics = (function() { } else if (IsName(encoding)) { var encoding = Encodings[encoding.name]; if (!encoding) - error("Unknown encoding"); + error("Unknown font encoding"); var widths = xref.fetchIfRef(fontDict.get("Widths")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); assertWellFormed(IsArray(widths) && IsInteger(firstChar), - "invalid Widths or FirstChar"); + "invalid font Widths or FirstChar"); var charset = []; for (var j = 0; j < widths.length; j++) { if (widths[j]) @@ -1945,11 +1945,16 @@ var CanvasGraphics = (function() { } } + var subType = fontDict.get("Subtype"); + var bbox = descriptor.get("FontBBox"); + assertWellFormed(IsName(subType) && IsArray(bbox), + "invalid font Subtype or FontBBox"); + var properties = { - type: fontDict.get("Subtype").name, + type: subType.name, encoding: encodingMap, charset: charset, - bbox: descriptor.get("FontBBox") + bbox: bbox }; return { From 518c7d3328ff1304fe4319c5b291a5f3cca1c84b Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 17:35:56 -0700 Subject: [PATCH 068/439] Cleaned up code for tiling --- pdf.js | 70 ++++++++++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/pdf.js b/pdf.js index 85c9489ae..0d18b272f 100644 --- a/pdf.js +++ b/pdf.js @@ -1609,38 +1609,8 @@ var CanvasExtraState = (function() { // Start of text line (in text coordinates) this.lineX = 0.0; this.lineY = 0.0; - - this.transMatrix = IDENTITY_MATRIX; } constructor.prototype = { - applyTransform: function(point) { - var m = this.transMatrix - var x = point[0] * m[0] + point[1] * m[2] + m[4]; - var y = point[0] * m[1] + point[1] * m[3] + m[5]; - return [x,y]; - }, - concatTransform: function(m) { - var tm = this.transMatrix; - - var a = m[0] * tm[0] + m[1] * tm[2]; - var b = m[0] * tm[1] + m[1] * tm[3]; - var c = m[2] * tm[0] + m[3] * tm[2]; - var d = m[2] * tm[1] + m[3] * tm[3]; - var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; - var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; - this.transMatrix = [a, b, c, d, e, f] - }, - getInvTransform: function(matrix) { - var m = this.transMatrix; - var det = 1 / (m[0] * m[3] - m[1] * m[2]); - var a = m[3] * det; - var b = -m[1] * det; - var c = -m[2] * det; - var d = m[0] * det; - var e = (m[2] * m[5] - m[3] * m[4]) * det; - var f = (m[1] * m[4] - m[0] * m[5]) * det; - return [a, b, c, d, e, f] - } }; return constructor; })(); @@ -1942,7 +1912,6 @@ var CanvasGraphics = (function() { }, transform: function(a, b, c, d, e, f) { this.ctx.transform(a, b, c, d, e, f); - this.current.concatTransform([a,b,c,d,e,f]); }, // Path @@ -2181,6 +2150,22 @@ var CanvasGraphics = (function() { } }, tilingFill: function(pattern) { + function applyMatrix(point, m) { + var x = point[0] * m[0] + point[1] * m[2] + m[4]; + var y = point[0] * m[1] + point[1] * m[3] + m[5]; + return [x,y]; + }; + + function multiply(m, tm) { + var a = m[0] * tm[0] + m[1] * tm[2]; + var b = m[0] * tm[1] + m[1] * tm[3]; + var c = m[2] * tm[0] + m[3] * tm[2]; + var d = m[2] * tm[1] + m[3] * tm[3]; + var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; + var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; + return [a, b, c, d, e, f] + }; + this.save(); var dict = pattern.dict; @@ -2196,10 +2181,9 @@ var CanvasGraphics = (function() { // not sure what to do with this var tilingType = dict.get("TilingType"); - var tempExtra = new CanvasExtraState(); var matrix = dict.get("Matrix"); - if (matrix && IsArray(matrix) && 6 == matrix.length) - tempExtra.transMatrix = matrix; + if (!matrix) + matrix = [1, 0, 0, 1, 0, 0]; var bbox = dict.get("BBox"); var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; @@ -2208,9 +2192,9 @@ var CanvasGraphics = (function() { var ystep = dict.get("YStep"); // top left corner should correspond to the top left of the bbox - var topLeft = tempExtra.applyTransform([x0,y0]); + var topLeft = applyMatrix([x0,y0], matrix); // we want the canvas to be as large as the step size - var botRight = tempExtra.applyTransform([x0 + xstep, y0 + ystep]); + var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix); var tmpCanvas = document.createElement("canvas"); tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); @@ -2221,20 +2205,17 @@ var CanvasGraphics = (function() { var oldCtx = this.ctx; this.ctx = tmpCtx; - // normalize matrix transform so each step - // takes up the entire tmpCanvas + // normalize transform matrix so each step + // takes up the entire tmpCanvas (no white borders) if (matrix[1] === 0 && matrix[2] === 0) { matrix[0] = tmpCanvas.width / xstep; matrix[3] = tmpCanvas.height / ystep; - tempExtra.transMatrix = matrix; - topLeft = tempExtra.applyTransform([x0,y0]); + topLeft = applyMatrix([x0,y0], matrix); } // move the top left corner of bounding box to [0,0] - tempExtra.transMatrix = [1, 0, 0, 1, -topLeft[0], -topLeft[1]]; - tempExtra.concatTransform(matrix); - matrix = tempExtra.transMatrix; - + matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]); + this.transform.apply(this, matrix); if (bbox && IsArray(bbox) && 4 == bbox.length) { @@ -2253,6 +2234,7 @@ var CanvasGraphics = (function() { this.ctx = oldCtx; this.restore(); + warn("Inverse pattern is painted"); var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); this.ctx.fillStyle = pattern; }, From 698132daec46bc8a2a66b0c07d84b2663662fcb6 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 17:46:02 -0700 Subject: [PATCH 069/439] clean up tiling --- pdf.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index 2fc51a21c..9c8b7e6a0 100644 --- a/pdf.js +++ b/pdf.js @@ -2110,11 +2110,10 @@ var CanvasGraphics = (function() { }, setFillColorSpace: function(space) { // TODO real impl - if (space.name === "Pattern") { + if (space.name === "Pattern") this.colorspace = "Pattern"; - } else { + else this.colorspace = null; - } }, setStrokeColor: function(/*...*/) { // TODO real impl @@ -2150,11 +2149,10 @@ var CanvasGraphics = (function() { var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); var type = pattern.dict.get("PatternType"); - if (type === 1) { + if (type === 1) this.tilingFill(pattern); - } else { + else error("Unhandled pattern type"); - } } } else { // TODO real impl @@ -2218,7 +2216,7 @@ var CanvasGraphics = (function() { this.ctx = tmpCtx; // normalize transform matrix so each step - // takes up the entire tmpCanvas (no white borders) + // takes up the entire tmpCanvas (need to remove white borders) if (matrix[1] === 0 && matrix[2] === 0) { matrix[0] = tmpCanvas.width / xstep; matrix[3] = tmpCanvas.height / ystep; From e80a8e6e2bdffca1ee51a40e4fde932163917751 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 17 Jun 2011 17:48:44 -0700 Subject: [PATCH 070/439] clean up tiling --- pdf.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 9c8b7e6a0..20a91d9af 100644 --- a/pdf.js +++ b/pdf.js @@ -2184,8 +2184,9 @@ var CanvasGraphics = (function() { error("Unsupported paint type"); } else { // should go to default for color space - this.ctx.fillStyle = this.makeCssRgb(1, 1, 1); - this.ctx.strokeStyle = this.makeCssRgb(0, 0, 0); + var ctx = this.ctx; + ctx.fillStyle = this.makeCssRgb(1, 1, 1); + ctx.strokeStyle = this.makeCssRgb(0, 0, 0); } // not sure what to do with this From dea351911a3e49e0768b5506687c88e373e6d1d3 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 20:17:10 -0700 Subject: [PATCH 071/439] IsInteger => IsInt --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 56ab89017..4a083c343 100644 --- a/pdf.js +++ b/pdf.js @@ -1935,7 +1935,7 @@ var CanvasGraphics = (function() { var widths = xref.fetchIfRef(fontDict.get("Widths")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); - assertWellFormed(IsArray(widths) && IsInteger(firstChar), + assertWellFormed(IsArray(widths) && IsInt(firstChar), "invalid font Widths or FirstChar"); var charset = []; for (var j = 0; j < widths.length; j++) { From d2e18d35b5b7d46ee5a6fd7416c6c3809a37ee06 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 21:22:37 -0700 Subject: [PATCH 072/439] speedup unicode/glyph conversion and cache translated strings in the font --- fonts.js | 37 +++++++++++++++++++++++++++++++------ pdf.js | 8 +------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/fonts.js b/fonts.js index be4007d24..f348c346f 100644 --- a/fonts.js +++ b/fonts.js @@ -30,6 +30,7 @@ var fontCount = 0; */ var Fonts = { _active: null, + get active() { return this._active; }, @@ -38,12 +39,34 @@ var Fonts = { this._active = this[aName]; }, - unicodeFromCode: function fonts_unicodeFromCode(aCode) { + chars2Unicode: function(chars) { var active = this._active; - if (!active || !active.properties.encoding) - return aCode; + if (!active) + return chars; - return GlyphsUnicode[active.properties.encoding[aCode]]; + // if we translated this string before, just grab it from the cache + var ret = active.cache[chars]; + if (ret) + return ret; + + // translate the string using the font's encoding + var encoding = active.properties.encoding; + if (!encoding) + return chars; + + var ret = ""; + for (var i = 0; i < chars.length; ++i) { + var ch = chars.charCodeAt(i); + var uc = encoding[ch]; + if (typeof uc != "number") // we didn't convert the glyph yet + uc = encoding[ch] = GlyphsUnicode[uc]; + ret += String.fromCharCode(uc); + } + + // enter the translated string into the cache + active.cache[chars] = ret; + + return ret; } }; @@ -83,7 +106,8 @@ var Font = function(aName, aFile, aProperties) { encoding: {}, charset: null }, - loading: false + loading: false, + cache: Object.create(null) }; this.mimetype = "font/ttf"; @@ -99,7 +123,8 @@ var Font = function(aName, aFile, aProperties) { Fonts[aName] = { data: this.font, properties: aProperties, - loading: true + loading: true, + cache: Object.create(null) } // Attach the font to the document diff --git a/pdf.js b/pdf.js index 4a083c343..cc866c174 100644 --- a/pdf.js +++ b/pdf.js @@ -2245,13 +2245,7 @@ var CanvasGraphics = (function() { this.ctx.translate(0, 2 * this.current.y); this.ctx.scale(1, -1); this.ctx.transform.apply(this.ctx, this.current.textMatrix); - - // Replace characters code by glyphs code - var glyphs = []; - for (var i = 0; i < text.length; i++) - glyphs[i] = String.fromCharCode(Fonts.unicodeFromCode(text[i].charCodeAt(0))); - - this.ctx.fillText(glyphs.join(""), this.current.x, this.current.y); + this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; this.ctx.restore(); From 494227dfcc262605e2cda1345a56ad5cdc7c9792 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 17 Jun 2011 21:34:06 -0700 Subject: [PATCH 073/439] avoid toString conversion in lookup --- fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index f348c346f..7978cd60d 100644 --- a/fonts.js +++ b/fonts.js @@ -58,8 +58,8 @@ var Fonts = { for (var i = 0; i < chars.length; ++i) { var ch = chars.charCodeAt(i); var uc = encoding[ch]; - if (typeof uc != "number") // we didn't convert the glyph yet - uc = encoding[ch] = GlyphsUnicode[uc]; + if (uc instanceof Name) // we didn't convert the glyph yet + uc = encoding[ch] = GlyphsUnicode[uc.name]; ret += String.fromCharCode(uc); } From c04da11be6617a074e659233af7ed2c3f1fc4ab3 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sat, 18 Jun 2011 01:18:21 -0700 Subject: [PATCH 074/439] remove toString code to avoid any future accidental implicit conversions --- pdf.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/pdf.js b/pdf.js index cc866c174..9c4344fab 100644 --- a/pdf.js +++ b/pdf.js @@ -5,7 +5,6 @@ var ERRORS = 0, WARNINGS = 1, TODOS = 5; var verbosity = WARNINGS; function log(msg) { - msg = msg.toString ? msg.toString() : msg; if (console && console.log) console.log(msg); else if (print) @@ -523,9 +522,6 @@ var Name = (function() { } constructor.prototype = { - toString: function() { - return this.name; - } }; return constructor; @@ -537,9 +533,6 @@ var Cmd = (function() { } constructor.prototype = { - toString: function() { - return this.cmd; - } }; return constructor; @@ -566,12 +559,6 @@ var Dict = (function() { forEach: function(aCallback) { for (var key in this.map) aCallback(key, this.map[key]); - }, - toString: function() { - var keys = []; - for (var key in this.map) - keys.push(key); - return "Dict with " + keys.length + " keys: " + keys; } }; From c828fdd2cab6c4b71246c35f5c47aaf10b816c97 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sat, 18 Jun 2011 04:33:13 -0400 Subject: [PATCH 075/439] Added a new multi-page viewer that uses lazy loading to display pages in a scrolling manner. --- multi-page-viewer.css | 50 ++++++++ multi-page-viewer.html | 21 ++++ multi-page-viewer.js | 261 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 multi-page-viewer.css create mode 100644 multi-page-viewer.html create mode 100644 multi-page-viewer.js diff --git a/multi-page-viewer.css b/multi-page-viewer.css new file mode 100644 index 000000000..488b10bd9 --- /dev/null +++ b/multi-page-viewer.css @@ -0,0 +1,50 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 10px; + position:fixed; + left: 0px; + top: 0px; + height: 28px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#pageNumber { + margin: 0px 0px 0px 10px; + text-align: right; +} + +#viewer { + background-color: #929292; + margin: 32px 0px 0px; + padding: 8px 0px; + width: 100%; +} diff --git a/multi-page-viewer.html b/multi-page-viewer.html new file mode 100644 index 000000000..a166f7fd4 --- /dev/null +++ b/multi-page-viewer.html @@ -0,0 +1,21 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + +
+ + + + / + -- +
+
+ + diff --git a/multi-page-viewer.js b/multi-page-viewer.js new file mode 100644 index 000000000..20d2e373e --- /dev/null +++ b/multi-page-viewer.js @@ -0,0 +1,261 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +var PDFViewer = { + queryParams: {}, + + element: null, + + pageNumberInput: null, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); + } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div && div.hasChildNodes()) { + while (div.childNodes.length > 0) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (PDFViewer.pdf) { + var page = PDFViewer.pdf.getPage(num); + var div = document.getElementById('pageContainer' + num); + + if (div && !div.hasChildNodes()) { + var canvas = document.createElement('canvas'); + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = 816; + canvas.height = 1056; + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + // This should be called when font loading is complete + page.display(gfx); + + div.appendChild(canvas); + } + } + }, + + goToPage: function(num) { + if (0 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + } + + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + document.location.hash = PDFViewer.pageNumber; + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + --PDFViewer.pageNumber; + } + + PDFViewer.goToPage(PDFViewer.pageNumber); + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + ++PDFViewer.pageNumber; + } + + PDFViewer.goToPage(PDFViewer.pageNumber); + }, + + open: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || + req.mozResponse || + req.responseArrayBuffer || + req.response; + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + }; + + req.send(null); + } +}; + +window.onload = function() { + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + var previousPageButton = document.getElementById('previousPageButton'); + previousPageButton.onclick = PDFViewer.goToPreviousPage; + + var nextPageButton = document.getElementById('nextPageButton'); + nextPageButton.onclick = PDFViewer.goToNextPage; + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + }; +}; From 5e3e5676894db13262b2f05dfce244fd66d85883 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sat, 18 Jun 2011 05:52:24 -0400 Subject: [PATCH 076/439] Added font loading in the multi-page viewer. Added support for changing the zoom/scale factor. --- multi-page-viewer.css | 7 ++-- multi-page-viewer.html | 19 ++++++++--- multi-page-viewer.js | 74 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/multi-page-viewer.css b/multi-page-viewer.css index 488b10bd9..013ca6aaf 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -2,6 +2,7 @@ /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ body { + background-color: #929292; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; margin: 0px; padding: 0px; @@ -17,6 +18,10 @@ span { font-size: 0.8em; } +.control { + margin: 0px 20px 0px 0px; +} + .page { width: 816px; height: 1056px; @@ -43,8 +48,6 @@ span { } #viewer { - background-color: #929292; margin: 32px 0px 0px; padding: 8px 0px; - width: 100%; } diff --git a/multi-page-viewer.html b/multi-page-viewer.html index a166f7fd4..6afe645a1 100644 --- a/multi-page-viewer.html +++ b/multi-page-viewer.html @@ -10,11 +10,20 @@
- - - - / - -- + + + + + + + / + -- + + + Zoom + + % +
diff --git a/multi-page-viewer.js b/multi-page-viewer.js index 20d2e373e..c6851e70e 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -48,7 +48,9 @@ var PDFViewer = { var div = document.createElement('div'); div.id = 'pageContainer' + num; - div.className = 'page'; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; PDFViewer.element.appendChild(anchor); PDFViewer.element.appendChild(div); @@ -76,8 +78,8 @@ var PDFViewer = { // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = 816; - canvas.height = 1056; + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); var ctx = canvas.getContext('2d'); ctx.save(); @@ -91,15 +93,67 @@ var PDFViewer = { // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display page.compile(gfx, fonts); - - // This should be called when font loading is complete - page.display(gfx); + var fontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + fontsReady = false; + } + + var pageInterval; + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + PDFViewer.drawPage(num); + } + + if (!fontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); div.appendChild(canvas); } } }, - + + changeScale: function(num) { + while (PDFViewer.element.childNodes.length > 0) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + if (PDFViewer.pdf) { + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + }, + goToPage: function(num) { if (0 <= num && num <= PDFViewer.numberOfPages) { PDFViewer.pageNumber = num; @@ -225,7 +279,13 @@ window.onload = function() { var nextPageButton = document.getElementById('nextPageButton'); nextPageButton.onclick = PDFViewer.goToNextPage; + var scaleInput = document.getElementById('scale'); + scaleInput.onchange = function(evt) { + PDFViewer.changeScale(this.value); + }; + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(scaleInput.value) / 100 || 1.0; PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); window.onscroll = function(evt) { From 616b4a5182d138739949eb87ce4dfdb1b0daa2a9 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sat, 18 Jun 2011 06:11:21 -0400 Subject: [PATCH 077/439] Edited the contributors list in the LICENSE file. --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index 6b2bc4d61..7c27034ba 100644 --- a/LICENSE +++ b/LICENSE @@ -4,6 +4,7 @@ Contributors: Andreas Gal Chris G Jones Shaon Barman + Justin D'Arcangelo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From f1e8b23f307752f343bdb9080fa6aeb61611c3f5 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sat, 18 Jun 2011 21:54:53 +0200 Subject: [PATCH 078/439] Use measureText instead of mozMeasureText (deprecated) --- fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 951cbd0ed..16c1246d9 100644 --- a/fonts.js +++ b/fonts.js @@ -203,7 +203,7 @@ Font.prototype = { } } ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var textWidth = ctx.mozMeasureText(testString); + var textWidth = ctx.measureText(testString); if (debug) ctx.fillText(testString, 20, 20); @@ -218,7 +218,7 @@ Font.prototype = { window.clearInterval(interval); Fonts[fontName].loading = false; warn("Is " + fontName + " for charset: " + charset + " loaded?"); - } else if (textWidth != ctx.mozMeasureText(testString)) { + } else if (textWidth != ctx.measureText(testString)) { window.clearInterval(interval); Fonts[fontName].loading = false; } From 609230ad07a155aee61f6583ca7d30bc9f2e75ac Mon Sep 17 00:00:00 2001 From: sbarman Date: Sat, 18 Jun 2011 13:06:54 -0700 Subject: [PATCH 079/439] Fixed predictor --- pdf.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index b75ce91ec..6a1589dde 100644 --- a/pdf.js +++ b/pdf.js @@ -519,8 +519,9 @@ var FilterPredictor = (function() { this.bits = bits; this.nVals = width * colors; - this.pixBytes = (colors * bits + 7) >> 3; - var rowBytes = (width * colors * bits + 7) >> 3; + var pixBytes = (colors * bits + 7) >> 3; + this.pixBytes = pixBytes; + var rowBytes = ((width * colors * bits + 7) >> 3) + pixBytes; this.rowBytes = rowBytes; if (width < 0 || colors < 0 || bits < 0 ||bits > 16) @@ -569,7 +570,7 @@ var FilterPredictor = (function() { for (var i = 0, ii = pixBytes + 1; i < ii; ++i) upLeftBuf.push(0); - for (var i = pixBytes, ii = rowBytes; i < ii; ++i) { + for (var i = pixBytes, ii = rowBytes + pixBytes + 1; i < ii; ++i) { for (var j = pixBytes; j > 0; --j) { upLeftBuf[j] = upLeftBuf[j - 1]; } @@ -2118,7 +2119,7 @@ var CanvasGraphics = (function() { var widths = xref.fetchIfRef(fontDict.get("Widths")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); - assertWellFormed(IsArray(widths) && IsInteger(firstChar), + assertWellFormed(IsArray(widths) && IsInt(firstChar), "invalid font Widths or FirstChar"); var charset = []; for (var j = 0; j < widths.length; j++) { @@ -2775,9 +2776,9 @@ var CanvasGraphics = (function() { if (bitsPerComponent != 8) error("unhandled number of bits per component"); - if (false && smask) { - if (maskColorSpace.numComps != 1) - error("Incorrect number of components in smask"); + if (smask) { + //if (maskColorSpace.numComps != 1) + // error("Incorrect number of components in smask"); var numComps = colorSpace.numComps; var imgArray = image.getBytes(numComps * w * h); From 17574e2d1cd20530e8a933eafbf41187b54c9d01 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sat, 18 Jun 2011 20:11:56 -0400 Subject: [PATCH 080/439] Updated the toolbar graphics. --- images/.DS_Store | Bin 0 -> 6148 bytes images/buttons.png | Bin 0 -> 2787 bytes images/source/.DS_Store | Bin 0 -> 6148 bytes images/source/Buttons.psd.zip | Bin 0 -> 248716 bytes multi-page-viewer.css | 79 +++++++++++++++++++++++++++++++--- multi-page-viewer.html | 7 +-- multi-page-viewer.js | 77 ++++++++++++++++++++++++++------- 7 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 images/.DS_Store create mode 100644 images/buttons.png create mode 100644 images/source/.DS_Store create mode 100644 images/source/Buttons.psd.zip diff --git a/images/.DS_Store b/images/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a1933d1a99313e68b9f0bb33b3fe994b2dc802ad GIT binary patch literal 6148 zcmeHK%}T>S5T0#oP5psf1idYui=-$-!9xfYJPIxJU_}#CXrMHuN$8_nq8>eXRO-Lbu9Oj?){}Rq7ahf^Ko2bi)&_oa7C>!6}2g_y0anIWF_odIn34>gd2ul>mqhoK}XMY6;4b20eqNM)aTworgl+?RN){zjoh;WtiZYgbv?A{{=dLarn1OiPvH?OzzX~^1w^CU z>-zXo=5GD+dUV%HY?^1COX3*k87wu@Dm1Us5&1_z3BnyK I@B<3G1LPA!_W%F@ literal 0 HcmV?d00001 diff --git a/images/buttons.png b/images/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..682212660d388acaa181d9df7102a5f8eaefda22 GIT binary patch literal 2787 zcmaJ@dpMMN8=h)XL_{e&(iq2G%#mRxlW#K0#9){lwgY449VTswJZ4|G=dL_lU18=lSG3kgMyu}`TmRLd;0w5xj?+-x9TzUZD4$zsQKQ#ij zAkZ2Zo8~R{ra0pnd@h{6f`Lo90tFicvbB>6=!_sh4D|;B*gOL4ZDkD%%4QN^URD$& zMPLsEvK_;OfJc}MjS&{az%gNVyP&pGyh4Bri0M!%m%|g`r3Ba~UA$twa*TjMKS9Jn z1lZq6c~jh=_Ix1#wSprp7)UGHhp+F#)E?^zRb5g0HeX(dTPYTo^)17a&k@a`6#xi#K*SFgG8Bzt8LWg7;O&I~UCbBK_6)SKBipV5D$PNLRdxU&0^i#=r_P2Af{HES# zF7w;DSbdX=P$Yv`Y3zSB`pc2RJuAzvwpDDt8Xw>(+%8nuI(Ouil=XzOB{Am%dxr+z^N2^_77y+&wxMvRhza=C$7c6f_rX z;v_HtkL^j)<5q`%bVo*>`Xf@SPqtyLcVOhc#7kBWA~nqo4|jo+baDPE=02Jb;@A*{ zOeXjI#UH3nJ8$L{ZLlr4X?l7(b?)sz#`}?$jIORO?>n!iN829_H(kKY#^^L`TAUvB zxGImB96VVZkYhG*_vpy3y=3~Nu}fxP;i1YD;qBThcFi_tOJAj70yKX%&1<>1(^?yn zNjQ23cXXE1<_QEnPPb|bU;Kbt#(tQe2`aU6a&pq*cKB9F={NH8-@6FvV>huna;dxv zrqrT>0#(8u!^o|O!;AEtyHjRAz8`5AatLTnrMqPB;>u*Q%tzEDfA`DEvI+N%{=EzH z^UYVu$^JOw*d*WT@KKrR3m7gf!%3Gu+cd(D1mwVzkEz}FTUcm)w>dJx_iotj zpqI^Qb@5QDM%!9&CD&Q*@H;a2HBEA63erATRsMMYPIRX4%kkS8s1GyQRXe z;8;hxer7?=+tQIK6y)(zXKU+JkwIXQasA<%o`ZbRDV?4;=uGh=Nw>L?gB;nCX9{_l z8ej5EfLoWK7~>sot?nyk#K@~cMI3M`M?OT`$$OWpMEda+svEJ>?{OxMwJ`hUW2O51 z=;X6HR!bIvB|G;$YqafJF{hQ1flV{>DlFS+>H|*GMK2XUj1HH~P4r*CaYHuVSKi*7 zVcimEPj%l`6&-YshiS9gD9bP_`~-JkDSPX1YUwlr+! zNX(9q)9$OH8@soMoPaCa7zOv#C2m@qWRcs*xNn-*uBUBgS$m+Am-f6NX(wbot7o*u zns}DkS$5eY+Q_8fiA(f;|AdFhRR3vV|1`h9!b)4NahonL0SZr3uzh#9y{_lgo)#WD za850ugighp%c33RH%%ehKplr^AEYJ0jg%SrMO9=m!(4}#e~rKy%|lZbC!a;J*=*F) zB45|~TldRyRt$m+bRmw_Aw0`GW>aT_Qf%eol0Kto5>eOy713tz4$kqrzpC)XcP`5v{)4 zK^Mx8Erk3iznPcU$mzbR|Go6-RauPT`hDpJ?fUmdIg@SIoF=xT&sqFwyHCP6v$b

o-Pbi6T^f->ZMv{{c+Z0vWaVj#UI&u;!5?Gv{lCkRhddK_hfhL z7-i#wWfnCEhiM0`gAMC^w%Oh!z4DqZSASJw=hzK^8&lWhKM37NCdin^ zo2F|t7WEVFODttauGno)UB;Pb)leW1NWX8gXc3MQP^#UDP(G0@#N#c3XE6srh~O$;_`-bwYfu$$tGv7B+v|_%(g{C<4R4?^p7p@ zDnsCa4nw;>CqJ>oK1*b8Ht48M%iW`gqY*Z1m-x0sIz z54|h?P!k`czGI^-y6e7#l4UD*Fy3Z~LHrSZP`YXh65M$`X!AhR@VzltHCdlj(du+;cG(2xTXOj>LobNW-;1rnj01Jc;BBC# X=z#fqprcVMznx?U7gFJFzsUapTNB6w literal 0 HcmV?d00001 diff --git a/images/source/.DS_Store b/images/source/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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 KKc!&keJ8=l^rl6%AVu7dpo(X!JAjQR< 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 RRQ?5f4lGYGru(j#%D8Lh`VwRjT^4Hu71N> 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 z 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 RG)8`0ryqY)dyyZv{|EPrC941c literal 0 HcmV?d00001 diff --git a/multi-page-viewer.css b/multi-page-viewer.css index 013ca6aaf..d81deb1fc 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -19,7 +19,35 @@ span { } .control { + display: inline-block; + float: left; margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + margin: 0px 2px 0px 0px; +} + +.control > span { + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; } .page { @@ -31,23 +59,64 @@ span { #controls { background-color: #eee; border-bottom: 1px solid #666; - padding: 4px 0px 0px 10px; + padding: 4px 0px 0px 8px; position:fixed; left: 0px; top: 0px; - height: 28px; + height: 40px; width: 100%; box-shadow: 0px 2px 8px #000; -moz-box-shadow: 0px 2px 8px #000; -webkit-box-shadow: 0px 2px 8px #000; } -#pageNumber { - margin: 0px 0px 0px 10px; +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: pointer; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: pointer; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#pageNumber, #scale { text-align: right; } #viewer { - margin: 32px 0px 0px; + margin: 44px 0px 0px; padding: 8px 0px; } diff --git a/multi-page-viewer.html b/multi-page-viewer.html index 6afe645a1..aec84a42f 100644 --- a/multi-page-viewer.html +++ b/multi-page-viewer.html @@ -11,18 +11,19 @@

- - + + Previous/Next / -- + Page Number - Zoom % + Zoom
diff --git a/multi-page-viewer.js b/multi-page-viewer.js index c6851e70e..cc4a286ff 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -7,6 +7,10 @@ var PDFViewer = { element: null, pageNumberInput: null, + previousPageButton: null, + nextPageButton: null, + + willJumpToPage: false, pdf: null, @@ -155,28 +159,30 @@ var PDFViewer = { }, goToPage: function(num) { - if (0 <= num && num <= PDFViewer.numberOfPages) { + if (1 <= num && num <= PDFViewer.numberOfPages) { PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } - - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - document.location.hash = PDFViewer.pageNumber; }, goToPreviousPage: function() { if (PDFViewer.pageNumber > 1) { - --PDFViewer.pageNumber; + PDFViewer.goToPage(--PDFViewer.pageNumber); } - - PDFViewer.goToPage(PDFViewer.pageNumber); }, goToNextPage: function() { if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - ++PDFViewer.pageNumber; + PDFViewer.goToPage(++PDFViewer.pageNumber); } - - PDFViewer.goToPage(PDFViewer.pageNumber); }, open: function(url) { @@ -273,11 +279,41 @@ window.onload = function() { this.focus(); }; - var previousPageButton = document.getElementById('previousPageButton'); - previousPageButton.onclick = PDFViewer.goToPreviousPage; + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; - var nextPageButton = document.getElementById('nextPageButton'); - nextPageButton.onclick = PDFViewer.goToNextPage; + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; var scaleInput = document.getElementById('scale'); scaleInput.onchange = function(evt) { @@ -288,7 +324,7 @@ window.onload = function() { PDFViewer.scale = parseInt(scaleInput.value) / 100 || 1.0; PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); - window.onscroll = function(evt) { + window.onscroll = function(evt) { var lastPagesDrawn = PDFViewer.lastPagesDrawn; var visiblePages = PDFViewer.visiblePages(); @@ -317,5 +353,16 @@ window.onload = function() { } PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } }; }; From 6ced547a5f939695a1b40b9c7b14fc8ee254cc10 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sat, 18 Jun 2011 20:13:14 -0400 Subject: [PATCH 081/439] Removed .DS_Store files. --- images/.DS_Store | Bin 6148 -> 0 bytes images/source/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/.DS_Store delete mode 100644 images/source/.DS_Store diff --git a/images/.DS_Store b/images/.DS_Store deleted file mode 100644 index a1933d1a99313e68b9f0bb33b3fe994b2dc802ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T0#oP5psf1idYui=-$-!9xfYJPIxJU_}#CXrMHuN$8_nq8>eXRO-Lbu9Oj?){}Rq7ahf^Ko2bi)&_oa7C>!6}2g_y0anIWF_odIn34>gd2ul>mqhoK}XMY6;4b20eqNM)aTworgl+?RN){zjoh;WtiZYgbv?A{{=dLarn1OiPvH?OzzX~^1w^CU z>-zXo=5GD+dUV%HY?^1COX3*k87wu@Dm1Us5&1_z3BnyK I@B<3G1LPA!_W%F@ diff --git a/images/source/.DS_Store b/images/source/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Sat, 18 Jun 2011 20:15:49 -0400 Subject: [PATCH 082/439] Minor CSS fix. --- multi-page-viewer.css | 1 + 1 file changed, 1 insertion(+) diff --git a/multi-page-viewer.css b/multi-page-viewer.css index d81deb1fc..53a28f129 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -31,6 +31,7 @@ span { } .control > span { + cursor: default; float: left; height: 18px; margin: 5px 2px 0px; From dd5c87dfdc91b5ff075a9fb120fe1a8ceb873565 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 02:25:21 +0200 Subject: [PATCH 083/439] Fill informations for the 'name' table in order to pass the sanitizer (Mozilla bug 660088) --- fonts.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index 16c1246d9..219ada8ca 100644 --- a/fonts.js +++ b/fonts.js @@ -94,7 +94,7 @@ var Font = function(aName, aFile, aProperties) { this.mimetype = "font/otf"; // Wrap the CFF data inside an OTF font file - this.font = this.cover(cff, aProperties); + this.font = this.cover(aName, cff, aProperties); break; case "TrueType": @@ -376,7 +376,61 @@ Font.prototype = { idDeltas, idRangeOffsets, glyphsIdsArray); }, - cover: function font_cover(aFont, aProperties) { + _createNameTable: function font_createNameTable(aName) { + var names = [ + "See original licence", // Copyright + aName, // Font family + "undefined", // Font subfamily (font weight) + "uniqueID", // Unique ID + aName, // Full font name + "0.1", // Version + "undefined", // Postscript name + "undefined", // Trademark + "undefined", // Manufacturer + "undefined" // Designer + ]; + + name = [ + 0x00, 0x00, // format + 0x00, 0x0A, // Number of names Record + 0x00, 0x7E // Storage + ]; + + // Build the name records field + var strOffset = 0; + for (var i = 0; i < names.length; i++) { + var str = names[i]; + + var nameRecord = [ + 0x00, 0x01, // platform ID + 0x00, 0x00, // encoding ID + 0x00, 0x00, // language ID + 0x00, 0x00 // name ID + ]; + + nameRecord = nameRecord.concat( + FontsUtils.integerToBytes(str.length, 2), + FontsUtils.integerToBytes(strOffset, 2) + ); + name = name.concat(nameRecord); + + strOffset += str.length; + } + + // Add the name records data + for (var i = 0; i < names.length; i++) { + var str = names[i]; + var strBytes = []; + for (var j = 0; j < str.length; j++) { + strBytes.push(str.charCodeAt(j)); + } + name = name.concat(strBytes); + } + + return name; + }, + + cover: function font_cover(aName, aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); // Required Tables @@ -524,11 +578,7 @@ Font.prototype = { this._createTableEntry(otf, offsets, "maxp", maxp); /** NAME */ - name = [ - 0x00, 0x00, // format - 0x00, 0x00, // Number of names Record - 0x00, 0x00 // Storage - ]; + var name = this._createNameTable(aName); this._createTableEntry(otf, offsets, "name", name); /** POST */ From f4282f98026f317312e7f7ada1eade17cf13d36c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 02:35:28 +0200 Subject: [PATCH 084/439] Use strict mode for js files --- fonts.js | 5 ++++- glyphlist.js | 2 ++ pdf.js | 17 ++++++++++------- utils/fonts_utils.js | 1 + viewer.js | 8 +++++--- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 219ada8ca..576e35cb9 100644 --- a/fonts.js +++ b/fonts.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +"use strict"; + /** * Maximum file size of the font. */ @@ -1092,7 +1094,8 @@ var Type1Parser = function() { this.extractFontProgram = function t1_extractFontProgram(aStream) { var eexecString = decrypt(aStream, kEexecEncryptionKey, 4); var subrs = [], glyphs = []; - var inSubrs = inGlyphs = false; + var inSubrs = false; + var inGlyphs = false; var glyph = ""; var token = ""; diff --git a/glyphlist.js b/glyphlist.js index 1a0190133..f638ff888 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1,3 +1,5 @@ +"use strict"; + var GlyphsUnicode = { A: 0x0041, AE: 0x00C6, diff --git a/pdf.js b/pdf.js index 9c4344fab..02159f94b 100644 --- a/pdf.js +++ b/pdf.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +"use strict"; + var ERRORS = 0, WARNINGS = 1, TODOS = 5; var verbosity = WARNINGS; @@ -246,7 +248,7 @@ var FlateStream = (function() { this.eof = false; this.codeSize = 0; this.codeBuf = 0; - + this.pos = 0; this.bufferLength = 0; } @@ -432,6 +434,11 @@ var FlateStream = (function() { litCodeTable = fixedLitCodeTab; distCodeTable = fixedDistCodeTab; } else if (hdr == 2) { // compressed block, dynamic codes + var repeat = function repeat(stream, array, len, offset, what) { + var repeat = stream.getBits(len) + offset; + while (repeat-- > 0) + array[i++] = what; + } var numLitCodes = this.getBits(5) + 257; var numDistCodes = this.getBits(5) + 1; var numCodeLenCodes = this.getBits(4) + 4; @@ -449,11 +456,6 @@ var FlateStream = (function() { var codes = numLitCodes + numDistCodes; var codeLengths = new Array(codes); while (i < codes) { - function repeat(stream, array, len, offset, what) { - var repeat = stream.getBits(len) + offset; - while (repeat-- > 0) - array[i++] = what; - } var code = this.getCode(codeLenCodeTab); if (code == 16) { repeat(this, codeLengths, 2, 3, len); @@ -725,6 +727,7 @@ var Lexer = (function() { var done = false; var str = ""; var stream = this.stream; + var ch = null; do { switch (ch = stream.getChar()) { case undefined: @@ -1429,7 +1432,7 @@ var Catalog = (function() { return shadow(this, "toplevelPagesDict", obj); }, get numPages() { - obj = this.toplevelPagesDict.get("Count"); + var obj = this.toplevelPagesDict.get("Count"); assertWellFormed(IsInt(obj), "page count in top level pages object is not an integer"); // shadow the prototype getter diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index 086648fe2..45f92a28b 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -7,6 +7,7 @@ * CharString or to understand the structure of the CFF format. */ +"use strict"; /** * Build a charset by assigning the glyph name and the human readable form diff --git a/viewer.js b/viewer.js index a8e7ae6e1..41aaf354c 100644 --- a/viewer.js +++ b/viewer.js @@ -1,12 +1,14 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ -var pdfDocument, canvas, pageDisplay, pageNum, pageInterval; +"use strict"; + +var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageInterval; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; pageNum = parseInt(queryParams().page) || 1; - fileName = userInput; + var fileName = userInput; if (!userInput) { fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; } @@ -26,7 +28,7 @@ function queryParams() { function open(url) { document.title = url; - req = new XMLHttpRequest(); + var req = new XMLHttpRequest(); req.open("GET", url); req.mozResponseType = req.responseType = "arraybuffer"; req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; From 972bbed12721eee6cc209d89c200c9548c2c5c6d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 02:36:47 +0200 Subject: [PATCH 085/439] Adding myself as a contributor --- LICENSE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 6b2bc4d61..4d5a7b2dc 100644 --- a/LICENSE +++ b/LICENSE @@ -4,6 +4,7 @@ Contributors: Andreas Gal Chris G Jones Shaon Barman + Vivien Nicolas <21@vingtetun.org> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -21,4 +22,4 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. \ No newline at end of file + DEALINGS IN THE SOFTWARE. From 0ddf9a56a0d1d585257e646562b64e45786d48aa Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 03:04:15 +0200 Subject: [PATCH 086/439] Ask chromium to shut up on font/otf mimetype by using another wrong mimetype and fix a few more 'strict mode' errrors --- fonts.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fonts.js b/fonts.js index 576e35cb9..aa0ad2933 100644 --- a/fonts.js +++ b/fonts.js @@ -93,7 +93,7 @@ var Font = function(aName, aFile, aProperties) { switch (aProperties.type) { case "Type1": var cff = new CFF(aName, aFile, aProperties); - this.mimetype = "font/otf"; + this.mimetype = "font/opentype"; // Wrap the CFF data inside an OTF font file this.font = this.cover(aName, cff, aProperties); @@ -112,7 +112,7 @@ var Font = function(aName, aFile, aProperties) { cache: Object.create(null) }; - this.mimetype = "font/ttf"; + this.mimetype = "font/opentype"; var ttf = new TrueType(aFile); this.font = ttf.data; break; @@ -392,7 +392,7 @@ Font.prototype = { "undefined" // Designer ]; - name = [ + var name = [ 0x00, 0x00, // format 0x00, 0x0A, // Number of names Record 0x00, 0x7E // Storage @@ -703,7 +703,7 @@ var TrueType = function(aFile) { // missing, which means that we need to rebuild the font in order to pass // the sanitizer. if (requiredTables.length && requiredTables[0] == "OS/2") { - OS2 = [ + var OS2 = [ 0x00, 0x03, // version 0x02, 0x24, // xAvgCharWidth 0x01, 0xF4, // usWeightClass @@ -793,10 +793,14 @@ var TrueType = function(aFile) { offsets.currentOffset++; } - this.data = ttf; + var fontData = []; + for (var i = 0; i < offsets.currentOffset; i++) + fontData.push(ttf[i]); + + this.data = fontData; return; } else if (requiredTables.lenght) { - error("Table " + requiredTables[0] + " is missing from the TruType font"); + error("Table " + requiredTables[0] + " is missing from the TrueType font"); } else { this.data = aFile; } From c766954ddff51821ca97180bc384f19b3b372621 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 03:08:43 +0200 Subject: [PATCH 087/439] Another undeclared variable caught by strict mode --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 02159f94b..399708b84 100644 --- a/pdf.js +++ b/pdf.js @@ -2384,7 +2384,7 @@ var CanvasGraphics = (function() { error("No support for array of functions"); else if (!IsPDFFunction(fnObj)) error("Invalid function"); - fn = new PDFFunction(this.xref, fnObj); + var fn = new PDFFunction(this.xref, fnObj); var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); var step = (t1 - t0) / 10; From 7c024b89aa60d7d36f31278cf76a0b4db20fd1de Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 18:09:21 -0700 Subject: [PATCH 088/439] Initial import of first test harness The harness (test.py) operates as follows. First it locates executable browsers (or symlinks or scripts) named "[browser][version]", e.g. "firefox4". It then launches the located browsers and asks them to load the file test_slave.html. At the same time, test.py sets up an HTTP server on localhost:8080 (there's a race condition here currently ;). After test_slave loads in the browser(s), it fetches the task manifest (test_manifest.json). The entries in the manifest specify which PDF to load and how many times to cycle through page rendering. This will probably evolve over time. test_slave then performs the requested tasks and POSTs the results back to test.py, which saves them. When all the results of for a task are in, test.py checks them. There are three types of tests currently. "==" tests compare the rendering of a PDF against a master copy. This is not yet implemented because setting up a master copy is complicated. "fbf" tests render all a PDF's pages, then go back to page 1 and render all pages a second time. The renderings from the first round must match the ones from the second round. "load" tests just check that a PDF's pages load without errors. Currently the test harness will only launch a "firefox4" target. This can be a bash script in your pdf.js checkout, pdf.js/firefox4, something like the following #!/bin/bash dist="/path/to/firefox4/installation" profile=`mktemp -dt 'pdf.js-test-ff-profile-XXXXXXXXXX'` $dist/firefox -no-remote -profile $profile $* rm -rf $profile (Yes, this script doesn't clean up properly on early termination.) It's possible to run the tests in a normal browsing session, but that might be annoying. With that set up, run the harness like so python test.py If all goes well, you'll see all "TEST-PASS" messages printed to stdout. If something goes wrong, you'll see "TEST-UNEXPECTED-FAIL" printed to stdout. --- test.py | 175 ++++++++++++++++++++++++++++++++++++++++++ test_manifest.json | 17 ++++ test_slave.html | 149 +++++++++++++++++++++++++++++++++++ tests/canvas.pdf | Bin 0 -> 150904 bytes tests/tracemonkey.pdf | Bin 0 -> 1016315 bytes 5 files changed, 341 insertions(+) create mode 100644 test.py create mode 100644 test_manifest.json create mode 100644 test_slave.html create mode 100644 tests/canvas.pdf create mode 100644 tests/tracemonkey.pdf diff --git a/test.py b/test.py new file mode 100644 index 000000000..46d30fef5 --- /dev/null +++ b/test.py @@ -0,0 +1,175 @@ +import json, os, sys, subprocess +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer + +ANAL = True +VERBOSE = False + +MIMEs = { + '.css': 'text/css', + '.html': 'text/html', + '.js': 'application/json', + '.json': 'application/json', + '.pdf': 'application/pdf', + '.xhtml': 'application/xhtml+xml', +} + +class State: + browsers = [ ] + manifest = { } + taskResults = { } + remaining = 0 + results = { } + done = False + +class Result: + def __init__(self, snapshot, failure): + self.snapshot = snapshot + self.failure = failure + + +class PDFTestHandler(BaseHTTPRequestHandler): + # Disable annoying noise by default + def log_request(code=0, size=0): + if VERBOSE: + BaseHTTPRequestHandler.log_request(code, size) + + def do_GET(self): + cwd = os.getcwd() + path = os.path.abspath(os.path.realpath(cwd + os.sep + self.path)) + cwd = os.path.abspath(cwd) + prefix = os.path.commonprefix(( path, cwd )) + _, ext = os.path.splitext(path) + + if not (prefix == cwd + and os.path.isfile(path) + and ext in MIMEs): + self.send_error(404) + return + + if 'Range' in self.headers: + # TODO for fetch-as-you-go + self.send_error(501) + return + + self.send_response(200) + self.send_header("Content-Type", MIMEs[ext]) + self.end_headers() + + # Sigh, os.sendfile() plz + f = open(path) + self.wfile.write(f.read()) + f.close() + + + def do_POST(self): + numBytes = int(self.headers['Content-Length']) + + self.send_response(200) + self.send_header('Content-Type', 'text/plain') + self.end_headers() + + result = json.loads(self.rfile.read(numBytes)) + browser = 'firefox4' + id, failure, round, page, snapshot = result['id'], result['failure'], result['round'], result['page'], result['snapshot'] + taskResults = State.taskResults[browser][id] + taskResults[round][page - 1] = Result(snapshot, failure) + + if result['taskDone']: + check(State.manifest[id], taskResults, browser) + State.remaining -= 1 + + State.done = (0 == State.remaining) + + +def set_up(): + # Only serve files from a pdf.js clone + assert not ANAL or os.path.isfile('pdf.js') and os.path.isdir('.git') + + testBrowsers = [ b for b in + ( 'firefox4', ) +#'chrome12', 'chrome13', 'firefox5', 'firefox6','opera11' ): + if os.access(b, os.R_OK | os.X_OK) ] + + mf = open('test_manifest.json') + manifestList = json.load(mf) + mf.close() + + for b in testBrowsers: + State.taskResults[b] = { } + for item in manifestList: + id, rounds = item['id'], int(item['rounds']) + State.manifest[id] = item + taskResults = [ ] + for r in xrange(rounds): + taskResults.append([ None ] * 100) + State.taskResults[b][id] = taskResults + + State.remaining = len(manifestList) + + for b in testBrowsers: + print 'Launching', b + subprocess.Popen(( os.path.abspath(os.path.realpath(b)), + 'http://localhost:8080/test_slave.html' )) + + +def check(task, results, browser): + failed = False + for r in xrange(len(results)): + pageResults = results[r] + for p in xrange(len(pageResults)): + pageResult = pageResults[p] + if pageResult is None: + continue + failure = pageResult.failure + if failure: + failed = True + print 'TEST-UNEXPECTED-FAIL | test failed', task['id'], '| in', browser, '| page', p + 1, 'round', r, '|', failure + + if failed: + return + + kind = task['type'] + if '==' == kind: + checkEq(task, results, browser) + elif 'fbf' == kind: + checkFBF(task, results, browser) + elif 'load' == kind: + checkLoad(task, results, browser) + else: + assert 0 and 'Unknown test type' + + +def checkEq(task, results, browser): + print ' !!! [TODO: == tests] !!!' + print 'TEST-PASS | == test', task['id'], '| in', browser + + +printed = [False] + +def checkFBF(task, results, browser): + round0, round1 = results[0], results[1] + assert len(round0) == len(round1) + + for page in xrange(len(round1)): + r0Page, r1Page = round0[page], round1[page] + if r0Page is None: + break + if r0Page.snapshot != r1Page.snapshot: + print 'TEST-UNEXPECTED-FAIL | forward-back-forward test', task['id'], '| in', browser, '| first rendering of page', page + 1, '!= second' + print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser + + +def checkLoad(task, results, browser): + # Load just checks for absence of failure, so if we got here the + # test has passed + print 'TEST-PASS | load test', task['id'], '| in', browser + + +def main(): + set_up() + server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) + while not State.done: + server.handle_request() + +if __name__ == '__main__': + main() diff --git a/test_manifest.json b/test_manifest.json new file mode 100644 index 000000000..2f45a026c --- /dev/null +++ b/test_manifest.json @@ -0,0 +1,17 @@ +[ + { "id": "tracemonkey-==", + "file": "tests/tracemonkey.pdf", + "rounds": 1, + "type": "==" + }, + { "id": "tracemonkey-fbf", + "file": "tests/tracemonkey.pdf", + "rounds": 2, + "type": "fbf" + }, + { "id": "html5-canvas-cheat-sheet-load", + "file": "tests/canvas.pdf", + "rounds": 1, + "type": "load" + } +] diff --git a/test_slave.html b/test_slave.html new file mode 100644 index 000000000..c560d90d0 --- /dev/null +++ b/test_slave.html @@ -0,0 +1,149 @@ + + + pdf.js test slave + + + + + + + +

+
+
+
diff --git a/tests/canvas.pdf b/tests/canvas.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..900d8af2303c6bedd5fd024855dc880ac02b3ab5
GIT binary patch
literal 150904
zcmeFXWmH_-+AdgyQ)mco1tC~)mjw3^++7QIcMa|kG+1x~1b6oU!7Y&B?iyTfC3|P@
zea`vr*SC9&zN34LyM9oURkhyvx;$%A%8QCKurRWNDEs$gazGqp%w)EP7NA$JnBG8a
zOr6ZgIH7kGnZ(VloFEQlOyX7sP7qOuk*zU=pC9Dt#$yK!$KBuq<9}pdE-dRPZdX|6N-lQ%!Sz=hUOd9;45gBnw)IyeidG*#^
zoi9b^bP>=)3-Suh3fKcyms>DRjy^XDPN>6SOl43lr0!_
zq;zt;7zf*As(cbheDz*Yhs@aGFe(=uSSR@1cnqBv#$LJeH6lqI%sp+tj@BH6XFf|#74%n^-I@Dd@x88@Z{33@4^w$#EkfDC*WWJvr>(V-(<5WJn>Sq%W)Pt|Nuu~t1kf5XaaA686`EO`kY?`^XQ^EJSEFccP8kvPAt&=8L-2kL{z
z`?KG&MR>vyOc*U*5}`!nUyEDmW`)A(g$}R1!No{Rc-)V$LjJBwxqwlLkP{`;+iOc0
zWYaQ@$&?a;)O0ECg1RAk@tPCx;m0SkTceyY5&uK34lkS<4X+8orVl;gC>^;7Ai#&W
zUc!E50iAD!k0dvC6_Mrf#U|Vo-QIsux6H_I6e5EkW-Z1@8UPv{a&UgcO~|FS$92no
zBe+HVxUUiEKYgV;h
z)De*ln45_7oUw`dT&yL!%Fi+S^ir}iJ@}YEkH-U8m2I^w!>mbyc};?CS+Oo>uBeJ&
zQ29Vc{1rQ4{LtCb&u=ur&JFxoqt*`I>G-x1!QCaK0wEnQ2nUXlmqZfB&s)I_ykWBs
zREkf8j0gMi%51zo<$MK)zu%{c&ooetQC2a~9zXD5`@H9UHYbv&n2eZ;3{PGcbB<|Y
zey~BFosj5saT1ykuFMj(T)!xy>Gm47D1jYl^EpgQP$0m3JJ*lnzD6TMi_9b0+f7_4
zC4mqHv&K#QomimV#$eI)8~UT?49=|hpa4w@!?9&$>XI)3_Cr6s_V0vX1wN^?&F;03
ziH`}N-+f&mq!GjSn&EK!E-7r%<1QCU1`PQcNVZ2#)m0u%9s<-I0}KJaay@OihbgEP
z3k5vB9O6;3>(lNVY+mE7*s34}FrYp95MAs_9-a%n&^8V^o=ilgq9?xA;}nkIsF1TW~4020W%M71NPk1LQl
zb;+O!K1&gVF%r`UiNceEo)I|vh#5~(D#1KCU&P5dAq`R-bRWR^0UD6r4)j(OH4t0o
zdqoMBGb_bBveaP!hIJduR_=d^wpEQ&vSw}k{vMY*=9(w$d6H-;CdSK>JT=PPl-#p-
zev*Ua=etB-65@$Y1^5R$1*wUUS6%Uiv}`5t?g)0W?FJQ>fu~-}1}qWfw4y>o+2Iwg
z$a|1{=U3`JAPHFl>ea4jx8R;4ehc{)VJE&k1*sRF
z%-L2}Z%H9XZw)$C24#Uy87_4}8oYXvj_vmAPJl~NV;jCar^>Tum}`=j36obWY4f3y
zITk1UAMmNV3h?9zK4o^o5g-*|5Yfw19uDXN9RUu{WA6i-a{=Fpjmq9$PiPIU2~odG
zB7J9Mb9@Iw40G^GklqS4i&5v?7>4CCM_dl-pMq#35fl<~ea+(yKJmmD<>5UY+ff}s
zb+OVoqemYgO!3$6)jn*$ZW^&c)9r6^4RY2z`(%;Zfvh2x4aw6*!EipxGhs?oNZiRn
zA}p~jI}@f0SFGFU{dCV_w61@aX&SPJ?mlpw`+TVx-@DxMoZQ;5g=}2*n^`cAxhvt)
zOM~vkAd)&sRJ$tIxcEJBKRFwgMp+TWH2ShA^V0h(n*q*q4~H;8HJTfH1tHh;1tG!Y
zlhx1JB_hOJpV5(;RLYO2q<>f;=(nQt1|=inS$&~?^=zS5SJwD_<0R*ftAYgp!H_83
zbDqz*l3QA`m7A~Iu>QSw7IW@g_fwH%3%u$_#)CKd2v3C7WyHK%9@Fss%ctRrI?S)Fo4OhC_1?C)Ie%n*{++&#
z#?pOvI9igMa^na3(-GR}LLnI8o*{ArraqF>5S_X~?$?PFgUQdFaMaUSwFsE-Gw{3T
zac1u;49|5OB>lBQ=WzAdKX7Dz9B4DMs<56iC^H?^UC4NM5Z4fWA6&-;I8&UUn%L=a
zzNO5UM{wI7EUMAm+>ZFMZ>?Ku`ckLVs2KMfuN%ngwfoid!`0$!@8vqaST}!OIc&od
zofk)bfJ~uOyeej8U;e`wd$02K5b9-bz9^P$Bd?G{+ow%>e$yU^M|eK9J}Sp;d-Nq$
zIf>p~_L*e!?yB>A1ro&pcl0xkJm!aWeSEC114h!X3qdYWHv|
z_VuT)jC92aTNwxQxd&BF&*%ot!*4t!x1>I(3;I5JEwkfhWb!OqfF!kPdK=JP^yLMf
zTylicq(gc{w?a4u5%}Yqccy1N&h$a6>gT8-c=WDj%dmjwuve`Y!(Z$Ksb}Yz=e{_<(xYPPM%ruW*i@{w>irtp=z8IC
z_|y^(NlpBWH~Uo#qVk%xH@n}KHZkXUO7nnb0tUfGVPu*|t;X)yp!q;T%C$VPwyFsl
z)(P{6=D5Y0j9eTbi@lxeHzmi_F|sQ6YuCwqxk7Fj(Lujdz0j>n681`7o>|w+t
z9DV6V`TAcoslFy{#C<=~%~QaXQk{|TNgv;mf>ES^_9^=gvIl5@X~<-!mP(LEq=G1&
zwKMjNwQOviR;TWVZl#Z+lFt~iBh%q5sjv=AuL0b_i}Xgab>-aDS+56y-ZQ#Onun9$mUqVn*c=XsMC*l+b1fLMwkS4InGown
ztPi7iW9Z$ksMy7$WwqPn;SWzCgg+UUSFkZ1KZ&ic-gXnRF=aV~
zuJC<%Y)p509a=JjG88uRlS|nTZ8Z7F2eH1rUlXeQhOBF4SGVn-;oL4^q8ah-Qw3pL
z?)P1nz*gK<4{r3X$V|}%F9jllLO_`=<76=)=djGyD*nF)D413
z{@5JlSk{Oo;Fqyh&bIG{ib5SzBb}#fKoRTE1wg
z5zQJE_bIOk8+tism}JUCi(jI()Sj-{On$?2vt+T)@9cyT=I%YqYb
z{m@^%&iNdDE<-gjd$xY~#b1zv?`dh5kI4M=8Y9=X8BYiW|do)#)TMzt?A;Nwbr5clq=|5S9Pgf
z2tTK$(!fm*`6DJnxU55V+4J`KHH&#JAlHtu+09En($}YGLO~cTN&RBYRk4jY3t1*P
zS%ZiI)VHG3@H@5~Qf!ZFzO(b@Xp?$%)zdDac&hV_n$0%a2f{X6duuN$Cm5&tYfbWX
z(uvhP%lllmeJ#FMWuz0=TNM`c2cfRJc*KuFn(g`CERCSvOWCTw)Urfm?Rx!E&3dcC
z2J%vX&nCHV?_1E0eT0j>hxVfE<=#pC+#}FF9hU}TWBez;0A2kAC4NE?KR?-7xY1x2n;Mwsr$)DGX%n07C2_cIBB+i#DV
zcOE%GDLhO%M|b<(VfLKwhV+7^-Ev$RJ1F_3)qDl6&-SyZ9fBY4F6ws+#OlE?eh_;?MT@SgLYiIVKmKcz--L^j+r#spxeHaBll4PoFTw`=6I!}*n
zoXRmvGB0XyX+6XRcNGt@TAy#6CZAN5-pB#)>AOa@^+FNxJ5y7bi{Rcc0`ZX1=uAeA
z%n5e*j6yCa(wxTjqjO)1o6WW5X5b9D&eP3k7M+!k@Ka#MG#b`s6UHp>^b7?b
zZkfO)k2kni3SGAr7r1(T0z;{lt!ixGH%ANm2O$ZrXO;`asI92;!|i@q1$aWkM@|JX
zuY>)3mAaRFW~G+s*4FP#sN*Q3(jQS>ZvjIYOS{J9+BJlSA5RW%eY>m|w9FUoG+cK*
z7y_c!mIr&Tty9J>UYsWDlM&NyUpqITupyLea@mQOP2cJ9j%&HeHr(mgSnp&`#9~KgrA!wpua=4QpHc`
zK0Ap9;2Tuoj@i{uQUr%1IGC9&TQNZ^dtOLV#I!7|FS)Faf&dTE2)y82>0;&V4A#8t
zLLF+E^XF9}|0=}mM?7LarTgJ>JS}fru+^e?t1!c%gP-cT%(@^N9p5915EjW;BE~T)
zJ~~Lt?XlWuP4F;h`&4
zz&a|HHk##`WtMA)?zmrc+qC&C$_L{h2k|E((Y4r{F&2*?6IIa)Z6ojK5^$I&%M@?uQf*2eJmjOx<^k
zgH6-?3Mv=kq7`34Jxe@Rfa#tYz(>&jHR}klS)765fq+a9KC2XO8Bx5mT_dGm((xF{
zXObsuFBwb{Aa%&}Rv+k^Q9YxI^$76w#KCM@au%mlJIxhYp*-2W
zE9B^$kakuTPg~_>0f5Z700tIr;xwCQbgPW4q-OQ`%&9x0^r&eTDNN$qs&y*kD|wTg
zQf=GAIDsynbXn10XLs_a%*$f%xzp&aPKZ`G2uIuSp9Tg2JzkLpPr2FS))-#eqE24&
zeu3Ryu3u|T?mg)8G)*abhO19m*jelOmL4nUQb9Kwaa7dCp9=Oo*Yv=HNT`{;HH})b
zaCyAakT(kXAfm@-e7++;Nx-Z5EoD}Ir#2{yL7d43bN9Kxq({{UX;G!*mN(?>VS}v6
z?^6{EU>j8+50{hZj!ZDaHuk)>+48hIAw@YXxWkmq?7r;#wlclaxzz)<+0BIMYKc#8
zow;^lpHW3xjpI}Dm8xpx<%KzkeUp0A9dDmuxpD*V!5|!Hu9$%)C_{o90;`I0ePSC<
zc}t8wmu7O2#kfQ5N=3pw$F_`AHGFbL)5!Z8v6>E-fITefFn{U
zVo;4U=y4><1Ab4!D!OG*ZA;$5sq3FL!^%H#8=k;u=BewF;#eOjG3dq^GI$<=iq57u
z>wZ_m6p{Nfk~asWG%DL7G0F0Nyzc3zu4~vH8}?;BfgZqjQG*Wpl|v#21RK0y{O2}v
z8H7kZ-YJ`yU-%npk45_qZ9pS|Y>AhT++wv8mRuPDswQmi+;mY`WWj!B?c9`>>+)l9
z8W_vrM6AP^M#gl?=RPmOq}(hX6Z13h=MWW$V4WCLP&-XAjlJ^AaQQF8QCVcSnz}sne~uysKb?w)}X^AZ+vc#eRFw|
zHkZOPW9GyiQBWNNeSx7aBt;_6;1K)Z^?TdlH(H)btY}C+ThAq=)f*Ye2aLwjnYA>*
zL+UW3k>?1T9rx#Nzm-qU)KwzX53**)xAkZuU_QJLdowcdIq#9j0*;Q4i_9q*A*UTu
z*7~AQ>uuqRIn9TVSGr+uxFdV5A9A{<((!<HcJ8{9@w@yc)|akVh1&!8r}nzEqyHKQeLUgaXuHNYBPlOsq-qjL`59eKfazwQTi$aZA?VYd!>$3ikV
z1wr&pT;@a`P59weP`XMRmodKPk5_xviaM}DLa-_zxA<^n!%wH`Z5^$D#x*Ra7u=#}
z_Bvu!3@cT>2mURi_$C)b@G#IA*1prZJu8{TS5`%A0;D4IZslX07ArTG1!f{qq@({t-KT>W1XE(_VbE#{C5KL{_hfn
zPZ7!~n|;|-I;4<4%H~*~beieHh|5()QRw0&)n^*7JD%tiX=PgnO%6)xwDO#Ae;YE~
zyP`Uf%n^{J^FW4kdh&f%OfO9XCra{lbZ2%g2QWv7};dP3MzovUo@tLvul=lXo5HYFeh#m?y@SW0y!)Q^l5
z@*ZL5{$|RhjfI(~sF_tLUex$+-YgS!;$eGb_@tSUG>?kKCx_3hBA?gKoAZAoJ4DWB
zFpoJcUAd#`YD?B1yGd23+s~|u(mu6oaGhceIEaVaOqZYQm{cuo*mqQBoO^qe@p)ec
z{dI1lb$bFaGvT&RrMs0l_89!FOPKR2LcYy+##x#g_4W+hwAUrY;XH|M0=vQUmemL0
z7RSi;OacshZsE-O$UzW{a!{aZeFQ6NbOhh5f!UQDKT4(Z(YntB(=v-?W~%3#6AUKz
z&xuHc6jp_06H1L*FIa}!5E({_e!O{}(zKyNpwExeiue?KLAlN6%U%O+z_*2L9?E^guL(--Zr<>l>4bHYsSP~{Umg0S7$
z4u6w#IX%U{CFi`R}&>(h4No-g3~4gC5)e?%j|OVHL85VkJWHc8
zG$l1Z^LlzF5-s)KceQt#0qC0PC0K3yvE^pF$l)_)M&bH>hjQ=5WQjMXDAH#&iXCYwt%Oq-Ba%uMSFo3g8=ufdP6vHl7!Auf
z`NT<84hy_bYbUZp=>L9bi;TP+=bt&RJsFvKLujo0bv_B$0DNA#+(WjEbHLom)
z9;Sk<3YsN;{$jHwT1)I1P`CP8`YB9kLsTJv~~65jTKoLuZMm36u$0#
zD+Y3MLK?p)ecEM7*E6pX
zW1Q4lqkPY=x4Af~Nx;dc^NEkIWn$Z2yMW8ZEaR1I7E}KYT2G^uN0YXvhg)x1nl5jD
zA(-jxT-c4@yHQ)p){VY2yFPlcn)YmiJ0D%Mf_BHjI&>vbT-q{CSD82y`Z&4jDpKK4
zB4)Qy3Ac7oc=s73b3%<+HrY}HwY+rIZU@05a&l|P-lHSdcye-MezKd+0=_FBJH7XG
zgWJ2t-YWFd?oe%EjExylJNJG5yAaF9DTzC0wVTkTJ_b@8mGcyRWs%9_8=3(KZqQb*
zSGsqdf(%$N*P6t2#!RbU#H_*O7@#_==VcB7H^MzKaT|d(G1-z
zO3t%!I+vawrYWS7*-^Gxn>Lrs426!{_;h<#ua&K{UU|S&2R4l&hfSAxxLf$=H<}rl
zKD(}$r%P>)s!X4a8tFS94}zs4?dEvNH)(_aEjE%QOKXxhNR*Tq?Pd5)42ekzbKOAK
zoA9WHSak7O9UyDRQypNEdP20pq`_(JZJ4$euXXzrRtK$%ZrLGnM-25kwGZK&ievSL
zJpWDE*E3zqjFkC%b%3J7jE(-Cy-$FlVHEs;8FSQ*x3z{PuSj0{jULuV*VXfm$jA82
z5D~vidJr(`s(Wofg3Agm#39ZlJh_&#N*OxymAA-j>j8{ghg^#OQyJ;;OT!dmrg#Z@
zS5FbN)S%N5Ia-3de{r~06awzS47DHj8z;%e_P~x@VR#2^+NnU*qS9LAvLvKQ3kP9|
zY^?)pd>R#z)V}*9mt4EBRvE<7BQCAJrx}`i8QTgXuV!J2rgtqB=d1W_h8N)i`&zmk
zw&7V0RPV~*XZJo2pK67+PGeT?(Pq4$D8DonoCp+6EOWLdaD*R8$>kNwEYrQw9`7U}
z2Rp*nH0k6aax-4IynQtZk8fsb`kCvRW^&KrwVyjDQ$=UnJ0nd?=a}0jT>~%)BlS(Z
zs^A-Ag5^1*`2)UPv>Fwy0}+llynGD1Ikcykx`{58#(p!_ja&vEdRbAdfl)}-U!V3a
z$v72LE=Q7FkxVMk0xuWZaklGHTV}8>o<=MpDn-pcd
zJt-6*Hg^qrPL9TW1MFxF3b&<(G|sz{^{l42rEOHqg^&%=A$LN}8qeB5O>lV-uH>zpR-`onuwas
z^+K%gqxF%4nr8UzAy*o$l40olf#RVJ&o{eNF)XTv?==qtv0nDVCxl_iv?YFEE#Fc8
zl##Uk#PTfI2Jae?wZS`omj|>T49*Kfe%wk9hZ67DS^ARqk5?#V%$%Dg)9keOUz!`%
z&<;~xPKrlpOl&q1+`LxPnaPsiy^=H4A(8xMs$QA9d(S}fiZ9nq?{h|-^xX3u9?H5B
z*){F3gT${s!iJvgQXSL{-N>>{TI54&R9CN)1duh_&c~FyEza5~_m0r*mT6e`rNjjsjl+OgNa#y9ONjnw+j~Z%pM4RDJZqc0;n%8r#cVD{K1mwM}ARQO~
zLLGp(C-b6z2vJ9GLj-tW8{4Hx*tft^I^zI+b+~ZFymmq
zJk|Gn<@mT|uqD!rmd^dLZ4_>N*P4j(yCLj0-OLil9^O@(_}(WHhaOG^y)2azW}{xf
z^p^YC41VV@dKU9kH7CPUdeo0d<)f!7Imt2e*o%o2tjno;bd3!LGye*
zy*}SM+Se|e728P#hrXN%u@~#(X;q^ysF%NJdBM(DFKfkxW8CU^GlE=dq+v*2o9e%4
zI&qes-M({7><5x=DflwT-=VnXns%{g#Gy4PE0o^;omF8~f}%{xz<7!!-ZwlK3BjI2?a{EzXue)R>KmQWQP
zVo{`J0XjAW^`WJ#{B}}NcdewjjH!AYcWkowIh`jk_o9W}UNIDRYA)W!P`bQ#$`pBFxi1xdH!`0-v5;hJMt=>KRY
z3hp?txiHlfJcvrl>tn8ojiVMj)$hIzi9~{13TQ;#Q221=@zluQsOVK-WJ4&}mX`Rl
z?$%I2eUZ#{Obu1i;C0*g$2L0;j)zbY@v6A&E;|Mt!YoXokVW9@6Q8rUJaxpf2v`W5
zn{qqAa$&Khm-&HRqmWXiriHEi%kz4!Yg_i0&2*}ZiPxVrc^!^J5*`uR-X=@^2e|wT
zHU5b%b8xc#g)X!IeH>2N-44PeZ(s^xl7SeT8wlIFk!dkQzvkfKAme6d)d4Xn+B!iG
z$B{8Zf8_wNaUx^;d2$YV8{%l|>|g|Ogr2FBcd#{5f;ee0K~LS0F-ciN$%&9LDMQ?x
zpwElBIY}t}BEiP;$D`_Uh87SbC?(cE{uj6XN%jxA(BpSZBGCV#J2{g51i=+S&|AMz
z@&9)j|4)Xw{>dQsZ*Kl(@E1(~FC0RD^HbZeUP0xDs+R1RZXL;(q|J>T$+SQ}1yBUB
z{qdng2BqW-m7Vo(E&na-Pi6f<>Q71{22KW6wx+*H{%Hpph?9Xa^cynvf7jMe=Kn$9
zZ$p5X)8zpV5p9Yr=~5Zh1pP-IeMt5EPw9C!U1CWb2k=t5X-OK{vpp#ihs(Z
z`%wDvUO0hGcbZMi9%e=jUb8=!XPF!b7Sa%QC4Oa5R)Xt+|&$eub*pS
zb09sv#k83`E~83_pqgo2I=0-=GBkWevE(a=WQ)
z4*(415gz#K`pNIl3kYQq9sv;v8H57;K`kZ#2DǮtIM931ppZ|L^`xF_&fv&VO87UR~e(lnV%e
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	B`v
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	m%*7jOy-dwCgJ%6E;_ULrpLp1)Ru!PlqrFPj
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

literal 0
HcmV?d00001

diff --git a/tests/tracemonkey.pdf b/tests/tracemonkey.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..65570184ac82fbc478a403cb8dd64a59c0065eae
GIT binary patch
literal 1016315
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�v_)@^!rDg3@1D%o#Hk5G-tYeQE;I
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
v7R`Taz^CF$7 zAn{;|UrP_xaBVUQOAkoA#L&1C9sB~hZ-_A+%98;}S@iM!kBXE{AS(Uvk-9P6RhZUZ zF{wX$Z6Kh0dG_RATX`@o{k9Z3qQ7k*OoHzOz=l*OH#;k?9uEH?+EXaM4K%49W67Sp)3zc}Lp2Ds=1v(-PNxxQc zN8bJ1&YdCc=a_6nj2!9?eEJb5b1T)yJ?JqJyaF%sb%!u1%;`etzPK}Rt|+e+lN@QR zb9XM#K`zL9H9?)Z!sB)9nE2jx?r4YQSD+D9HeI~8uvK2&ef<>aqNr~5V?@wH!9KZ= z!ik@+ z5|05dLEoxp73)P%mR>IF-|mE^cs1Vo6JE65etEq0PrVog)nTyPe$|4CB(!Gz%orSW zj};8}^Tt;n;dv*)==G*s{nIER9Me*IN3HD0xsPrVTo1=lX4)JDyo0Zbt!?hUgimZh z8E~f(NY4)M53~8%xjIYgUFH|(c{S=A2qg88gxe^khObg_4NnpX3vEM0xXt!29R)A%2!rTejQ< zfo%CFLZK}{t3tjdiDM>_?wscRQs(+itZk;O%e#uK$Q;oI*EKK1q4w15c~;I)>yiwC zegpAj*Pq+IvKV@Z9|J{{yaX~fR2$$XwHAM$j~9cPqK1IV&@s5!d=+Mx=srg39!GB3 zBB^;iwo(@Spm=5Pjc=sooLV->XG?I{8Hg|dwoz#?U4$B{X+ZW5|AucE7VQkdKv)Ht zvb{*z^uY|O@*RB*iG(5doP;pCaGJA=mLEwe#Wj^0TYR179AsblIG|~7ar5=O@(FyO9Zb*@A=m1^sYsP4P@JCz>L{jl9it@wO}&NM44cThv& zKu^ssSjEyWiZ^tXHz|!bR1EP!ZLRnd)-F#$uPR&oQ22+~-C^R%$eG{^jjvL{6{4Tq z%y9g%_2JYPVSl_$e+!?rt8stDR<6v6a>Fe?oqAC)# zLWuBWG7GYSZM8TJ?0LU}G{;mtKB_IzKB)x$0M)o*w8yLzqa^*p}^Qr%30o5y#@K1xwwPOn@cRrA5Z-Um@^jY8#Jj66T~CF z3geGgl*YQFmXxcFU1ySy?OiQ#JQIopZ%?%rBL9m6vis3i5 z?KX?=P$5Np-{?m?^X%2zMMhMjD!GvoP^=J`sJCdNH_1vqk5!M2;PCH#TYH=+<`B$@LgXF9cMl%gv zd?rJIR4Zl%1ohOj8Jm-~F&%)e|0a9lo_D8RqGS`(6)6EtwajMm1%;P4XrdM3C|1kE)l>jc+JrXkK>LJDRnuZ$Fa<18{f1@ANi^2X z)D6GFxuE_FBg3bgk;cIJtcy)%8vq_YZ0zOt+rxGcQ z6!}=Vfqv`WXHYq%@a_7^$YD!j@0@n7<#xjW3UfkZ=~sm$`&r9bN7*W6ud``t053n9 z@^lECl4Q(2^3V@{poo!XPpxgPio1A1UCohT6zkjQbD2!(*LrFfTj$vuf<41GR~Hgn zJ|2AXG=W6;Vb)bAV2sCl%8kU7iaQwmNJ1l>g7e=UVm@kGHKWXqz*J+<5^N>vW30@M zO*CpD38PYmjsompmM9gB8)QxTM-sN$zHLB7b=CJQ7~ec2tP zAyTM4Y7bJbtmjc`7k88un$QVFG1l`W3a?-~lFckkO?!6frZLy@$B2ROgk;9h2`g$D zy!NshZ zk09nH57*${PxE~on`LJ%6@}p))?jn+o({e?t%_PSSLQzf2L)ZYmgJ6k&j?AMi7o5b z%Vq9FlWw!h1y9W1VfP4y8tR9|T-@y@svQyLS4RxhSY(x%k1-{GHrl?_^=`^2pU9Xq zv)5kXu(LtnT)0GJ1s2zlA(1iZ%6uj0IMVW&wXGZ|gtJp z=P)bsQ=Bfz^d)GWwjs(=84~pDlE){{Hy$Vzy%zmSWjaa!h8YUlm#Ug-PfMMM5D5tE zF4)3VN0^oP5@D$%SpVHlU$!-%Z<1WD3i*O8yzosM^s9pD1e{h|Uk2yvr7Om9l)^h1 z&}Kc9#Kr{laom;yzsACk-!*f06tnHhL1<~Xm7@?F`xwU>l}Zs;HakKB$$T%vvw722 zIux94w~^zedxkQFLe`_Fp+@XY` z3X1o^nY@~4v5txV8T_#0*n?6z_z_UL=k=F_gQMh;Fec4yaIHAo3RnJ%Yv&e;wk{{4u!^u(_ zNsA}Sq~pYvcWO-$yP_PTqyAIs{mTR|{z;S}4Dd9%1TSx>=L|8-el<{@ zXqu^~FOP=Sf4gF*Oi{L{Y=;<@e1X`Um<5L<52YBf|*PgvY|KST0cc=_hf5YoD(hn&?#DpUy4Ry zJXi<{27K(vV*jw*HScR=M07mKqQ}%pBr9D6rg}E;zVgG}%#arz&xQ7IS{@zxS-|6ObOM7+irq{G z6C5~@!;WQ2VQtj2h8T)Vs}!h^M`qoJ3O^4{$G<=xM7Nr) zTf~-4sHsMZ2=Fy1pe4j*Z2Rd2>^|*jxwot1D#=OEU`R^Ymae#^=Si+MLZVd96SPxc3o@8t~{B#$4tko6&A2sBjV(pv0c4(P?L96?0Mb&*MBTP zm5M9K*j6YL%9;lOJ!b$qgYYlrDX}D@n7<7SR9HQ=zkZCTB(_Fzf7~HB2b>>S3+8+0 zCO8Z~70gQQlP&{RKEF9CEk-cJ)Cw3x2N zrKQK-IpnNiL>dZ2frk9QX4N8jLWkl+Is7(dAV} z99_UVh?{MHuC|$XY6_~7&OB-FK#^;sL5e&I^S$dS1y!gu?j(&I4_KFO;y`hr-8YP7 zLLDx*cAz@a_yd%>_>}iyt*xNVsio@3QcO8NfaEjQivLh|l|FNRI7dL#G~> zp3kb=Hi&zQuS08oupBIloyGoFGAtq)3J_E@W-y#v-n7Sy-pIx&{2OiV>tkmp7)R72 zPVW+ypiW(j4O!SQM)m{l9uX|VT#-$k=i!4Vgq{X(Qn01g_;*z8!9S<@a$f_BT*0kD zNvF~1r#8PMl~uVCSN2q!b1~bazH*S-t?10#yN)n&m*vW$jWovhh0c6L_UFtg8+<1Euq%X8N5Q>~bNkWFTvVcEaUKrFtuZu5Op z9y~yXvWGe42I;A`h6QhwNnbh!A#>^P|L?mFN2G7jY9Di@m&8wQKWfZ8gnJAt!q`tN)Fg5hA z(!nXGzV>PO)^@&@OSk+nF<_e(&uA}n6O!~!WL86PPjpPCV6;ue@VYZ3mDy=7)+M{L zG*0V*C6e~UTH{kBUHY-g`!dtjiAI%_R*AyflGIU~Q=V9I2GhGz?&DRQ6y)8Ly<3W# zShDX>LZ2$^blID)Bs&P8*9WS4rFBN9`~F5UD}6uGo}Vbb`CZ{ncg%Pu^;l!O^*Nnm>K3TWrpSdNoMBn z&cokK?tf!unE%Qu|Cx&YcSquXI_NL|@NWnG(;EIirM~|c%#4Phik!N{f62^zC5ivp z6QTPTGsFBJdEoy`W`^}EfB4^+8Rmav82_8D^LN+e&pTq__{uf@`lSD~8UDWSKdnEE z(7%`&=D%A^f0&v7W-k7lx%hA9;_pEDS91Tq4-}SvZesqo$MoMG(|>zR|F3#Xf2YHL zO;rC$y8VB}%=~XA?f;w149mab9{zJa{#X2o=6^6V|IW(%VP;t9zu1{Sw=Wv+4<*CG z#E#Fz!SN4@=Bu{BKl<3dh#7i()-Ph_4^zX=!1RyDzxbIiat5E7jrlK2^XGY(7#RQD z{%u+FuW*6Hy2y9D%O6vmK4~iJ-r2oAY|n7unDH)y$`r*w%pp^{KXl)KXINh$h5q~2_$8gs z$x&XRiwh5p!)lK{y@Vo)LYJI__QZaG);n06S| z+A;vT$@BPd$0;>( z=D@EN=UabznxiYrd~C${NJ9J`zsztIdD(}4U}|_|{u4AEuF+$V_CAksHiYsT{mkoF6Tw0BRjo$45wXf?2)>bKl$L^_i zNB_j#2Is%-JpAK?YUbp5S6eXRheX!^5mjik?E3|+ohg#RH~=4H@41+eQ4#7fskvMm zasfW&b>X0lLcR%Tf|QipcZj)o;sP=S0|L>4AZC*S66~USM63x>A1DGv)%w!s8TT(P z25D6Q7auNBH%>QRb+lATWpWznl7Vss=3q~YP5lOm`BV72Cqtu6-C)@00BtHmM zuq0Ndm(O|T{!I^P)1Ft=e}eD^=Pq3)Bj>qgdr?`jz8uZS!T^2&v+W4KmB`89m0T5w z0%oCja!PwJXNV0aew(q`(c%rl8J(2KC@D*tH7?o+X;rEv&T$NGEO?*Lf#C(=cvs7< zCrC@OC4OS`U?1|<(1D~qLQA@aU^(GzRCe@XAJl>9_{PKmY84mG@KW>FlLkXl@P^En z;2P)Y&qv}K$2GROZ~E(l!|YSXf$upVuHy>mYj?}~mnYhwVf`h^Q+)O{7Qr5|q)Ytf zS8*CLErwh6RUuqrhFf?wN4lmPvC%@kk&(Uz*)X3;vYn3+28NGBBR=;CZs{C?Ug8#4aHpG1&NRp~|;wuAN$; zC^r1*^&7P-!79FlCxS!Z{h$}UtXBM3*D+56STKSsp?!K~{@kO{Wh2a-w1*lL8mDeE zF_UhrA2zOG9wv_~5H=Kn{TLitY z0@?jQt&wpg5!}^?%tlEN+-@+6cP7!n=3O zEFfv?OaQn*BkuQNTECXu46?!^i?RIjkPIN<9hX`SAkh`m!X;p8C>2mf9a-G8;(;D; zRikK6&;5_AA98e5jRd`Hka9_Q=kh^9*I_8MV1DL%s0KZDViHE1!bG#&FN574w`nLJ zm1~wm?#J6FW8yAdBab~o$1a>(Q1aTX!ZZ$Z6wEd(i@Mnk{D=@2GnEzU-n_U(`7NHE zrYfw079Z)}t|FE(-mBZ#-)NvGAsd9}Cv507u(Be8P{^0CS01}> z#cc%wQWLfBeu_ot1BYDY+&2kjCVcw!!VPng$h%B;g~%W5d4cTl(wDC}^!=+Mm@Fb@ z{Rf%+8w4QoeQemMCP*0kslmjIEKT7$w2j(%B!l95+4>(E<3^AOO6Z|hGr-d&wyprD zSluwcqzF?Obt28w&TsB|>Nhi3@ooegC_CQ2C%{6{!Bk@0PxC|azRzzWA)M|ApodX4 z>T~mbl_h!2N32Z8l^TluqQj-KLSD_vPLuO z^L}fH(PBaVo<^P4$@96%+}{S*$AT%NPY&wh;&AYJotG-iH03vR6r4VdWTj9&fxp@*XIFxB0+&35jv9* zDyl(FZ64fIJl(ivLV{v&Ot1^hX4^k$Wi5{iaOc);ROY<{pav!ws0BBwH+dkyRKcw4 z=IGXv)0LfOP&S#SOKd^d$O5ztA!RL>(LLMAatQ1N;J)pRdQAbPCXt~CnOX<=&o8k5 zvd7ShHUz3ash$`a2GO@_%l9=ybqZvVy^COwRh30qQ8<6fyuezmOcbZGzNmrO?^{vi zy39v&je)w~tr6jY>+4u@ws)0HD%8^UwZ3vA4SL|-ClrSF<~W?-R!2s2tjj|66CxOH zVvd3!?4%oPe9^+R5Ee0UX7Cn3poo*!0HTIww)rzt zx(oFw$$bY5!lE%IsL2?2N$+!!{H=OoSpv%yc$R`&ox!}IhWHxX`}#m69Z(?J%6Kgx z61;oT?omigAz&L{U zF;4-Cs@sCI0yki{R)T^M#FrRFV{Sk*uz(D8^*bE?x8HGtiBTbC>Mn>jF6z~b+~x7=0^dN7GA zcmW~O9wR*$2`xHGFl_=dK!^msBxd0Evv(xYn{??@D0n4|x{W0;On@%9+M0XNT zyamN<11?Ue-Zrk@-GunQ$XVF-b4Plu(kD}b4M7WQ7c4o5tHoZW_3ffQ6wA^Uq}%Rq z=FjYLN(h|%LbkG9ocd{AYibA??CkP!ve7n$ zr_4PSEluTNBqRUBCqJ*@;hV&e_u6)!wymG0@5P5H99)Au-rjKo_hU}5? zaG9zcCTC>zq%w9PhrGa+bQMdvHPS~01RuFWK|ly8q!3cxa1o?jq4&F|iDKOLcSR?} zSgrw818Q0thd@#3NmSSzR4|U%kx}S)uXA~Y)5jQz zas_=;m9q_VB36W05_Lfi4@+gV^&u7!&@I+WKMCi=d1fDJ1%8Vxgni0iVzB?Hp9f?= zycudfh@AT{b4Ue7?SV_#kEEQ4ojZ^hXqQu3E&BW=4D$vMjk5t)vG(N61fcD%=(Hjn znJD=^|6wexM$OXbVlipg4>i16pyQT0brIn6c8=0fJZ=cud|rKZhR@j%#`%fLO?p{6@*kCs|5Wb60#v3R9Fa1 zEfV2FAGnGP%@#=wFEPFu+AUGCHe=%i)(l6ar%Et1MF$Lbo(Y@71t#r@Gg*Knv2SD< zuiW~a8G4+}TM03dG=6m-ka|0Zx|_0Wxpc5?w~R;)d_@}j0LsB&K`e;4J2o>l5odB1 zeI-$pW?|&`5Uf$DB}zt<9eielQb93MNgfa3RvSbf)nRF=8`M z+6hES#dt&OON1k1VlTs6qqjuT5sP`>WK^DX^I(Fx@>v&4u$J!0;dsf!ku!4`EV|?-GmZov{D5_8UF~&!qr`>l)oo= zB-fM~N;`gZB{aRa90*OU-(rcjK7pn>DV2^EW792HEWJd3AAb+nMz+vpXfp8Oz%f4vYS9!a&fP8;x95~~AYk2^1RuPMs-j$G^ky$EgzaX`>@4y>a z4%lK@5PN~s%bLO0UwmVaA8M;~RgZ2c3i3!aaJsP}=vG7unG?tEgEBY!+y|W9dghBx zo(+3b^K@(+i#HcLkHq8GRg$?djj>Z}n;~P(If`sDz!Bh*hZ4=R+QNo5|E-Y$qrxCh7}XJ7Z^JhbbW%Ld?VJEk0|m zhxxq~(@gVqPH)0$7JAaA$@)=WV1bn2r<{R~Are;B(ES6=S*9N^&h1k+$DAuE^!giB z-U*6Ioxu0c&o<`WupcQDvzy;{Cs0h{3lLdFrm0mbNUZee$Luxe(NI!SZcK}x9f3H8 z8?2#@YWOI8A44|JWEoAS#%eLLRE^}YmKc>a_U2iVD{D_?-Wq%#`xVwVG7`4(6iwqM zU^?29o3{=ZG7f94r>Li@$D}1D#21QRsi!BMVu?7&ymk`U5*Q;l4g@K*Htmci?%xmz zaY)PRTMWrZH-QRM!q|nWd=`zyhH#tbH5c z*EHCaA5g(XRddA-lILe0&bi7ID==@AXJPQi#o~@`n@$`?p=8St@LkFZLZ<8Wve*0A z2$3@T0c#o~T`V#4UaS)1a4IB=@uAljq2?6Xrd7omuXe9S1>SgKQ-tGQAS`RcN857w3Go17Gv zxrZr5q#o;VHuw;l$S!eMzm&n0u|epb#v1?a7|VjinrakDISs8ax(-$Vr5|ySuMvJ# zmpmp%Unm_P(aG z;Uo&RcHu~ARiAiAoGOZFX23fcPQ`M0u(`NJ_52{EpB`yf6j-^TQ(imXIQ7^82?ka) z#zer}I$eFA^$OL=dfq);9#Io(^0ZF+M@{W}k9%Iqpz#`ncgw6*dV0NkZrhUhaaEMB zj`5UzTZ8p!$XQC&+RsewruT8QaX@Otrss?Q>7(JQW4ObfMB%6Cnl$WiAt(q}sJg5+bT;6b18FcHTEd%i9TL&Fbq$ zK0p;P9kUbFDr&GaNt*|QkJkn@2|M271@*anyPq81>|siMd?8DDthXLor|%10(W`v# zeY3Gwi*w%?Y1Tx?**&wacXlkPQkau*@R5}{-0yrG@8M{s%D8)wj1D*=hPn zHm8}|A+s9C(MbjT#`dhOB|kP5ugTj-OphTe-2Mv_{WzYHkgyhh&#ONwMCxR0}7QNsdN-D)Hq+~Vlz&RX{cy)vHpGJOaws1ef{TM#=#cKggQ_WsYBu-J z;c09&J~s?2Iq~Vpb$qsTicNtr<>`lb`__;7$8$jG3m$utbDh z_IG;;Z28BZiAkS=jbxPbgS}M}RHOH(Mdk@iR9-I=y_F4Tov5}p6KV3u*;#iqBH4MU zawC3iGnN6r{ebV|r5Z-l!{Z5pv4Z)*yeh(Iwot7ZG9ZrxX>jddPQ&M#_FMsw@*r+z zQ871qGrutd97VQ0M#RE~2YVY-lf)}oM_Fs&sjKpO?geH}$5heeW-z0;EG4<7u1$e# zE}?7|m*4-6_eN`7vW%T$ zB3TW&dY(?CuV0Zc+R#xeEJLPX6-%IC0|<$+)kE~|SJc+YDRFMAvM3MQ(`4Fd6R(NG zVye6)g(F>iV?e5<$l6=Db10THG{EwZ%qZPH;`M)JOMI&TfQ#qQvOB~s)A38^M=a_a zFs8?^_^_fzQX?aGOt$ZGBQ2^eu%mVou4{BWsu(zzDjTxW^Yk_-0S$jiOuxW4Bln?S zB+G%OIlIFmef@P6v`5hQ!1vx_81dOE8{H;L8A5wTskM=0`%@elvv`dz=sS~SgF;v1 zI_J8HCseA=V)i=iJ_!{uH{CLMQcuLs_b9>CKGn^wRh^5%827V7(-RsMMSQwV!-RG0 z@{YxGrO@rbR@Bo7fT^%A~)+Qg_t z^?k~wg+S557RFGwZ&o37WwPquU}3Z7vy|6UdZOetL*1 z4wsKnSOq&oaN>wHkf}9FOZYIVrSCRi956OZbuiE+K~JFRzO6zXH|96oTScB?tdK|) z+s(d2jVEO5pk|y}+N4k&I4G8s)xuc$j`6|ly_A3D6NX46S<_~3Fbd>in@uZxx1O@| zg5(TbPi(QZCQ6D!?k&p6#9M#XmjeL7&&#`HT5teb5U}?Td`BuikeQ;HTYLZ<;Ga*gnrf39PrbUl& zwT8vygL<|}wn3}#xFY&Yl5TH7i;4fG2fypvuj#xDQvF;+rvz@w8^r_aimE&dz@%2N zMPRXkL-eO*9ub{q5)?Q`Uy{=kIA9bg1x23Pkie`Z&!__wTGe14-d4tly;PijVC#5w z)N{tkEXqgRg@#^uTeM#ufR_wZdPjq#Dd9kFt8#I0oT1qiW}C3C6C|e?a7f?0UE_B z1i=&hnwz(cLCMS2>h%BFzM%JXL0= zuWqN%yzY+PfOSlL(*o(@0*%v7ob(8p3B8&Vms!q>p(IG;=Zig~lCLdkqcaoanT^e( zLJFs}?TRQ6qG(f_(l=4(TGFWsgGaP6>Wcx-rJ(CvcrUlY(otjhcZ3O$A^WI}{RE(3 ztk9ZnAmc>jGCp7Wu^U|soFQAK>fT(!z)A}0hcM!#J#Q?@(;!V!>PIGR9j@PVQtk{( zmut?llZ%q>Km#lEwkkM`Hn31+Ko#upkvNi68$oS<&+w~8i9b zIY}Kk-by~L+Lf0h$iNbS92eyR; zKEd-ROo2q93H(*Y`ac^vxc_6sqL>8?5wnY|%{9NH}iM9m0!sWO4m%qF#A|0Wwh-a8x z{9Tm6i7?&2@Rb`Nls&)=_m`qpd)++q#rqNF2yjQcLDu8_k<xC3(D z;5`xGh;Ri5;o%4$@xN><(Q`pzguS^Y!C5`vdZr8&;F>ptCxT0nbN+Yk3>5(ROM!Rj zh0W+TD0{M9*g;u@R>RwM_*TLeA{&8?s5Xek9t3+J(q7yzK+QSK5@A`dqY^=tphox| z-5zAuVbD13fmOesM!$E!HK5wn8blp58RQ6) z4vP+h32Q_+Log)}ML2`EL?HSi)CR&><`xmj2Qk7H5K0MTM6v?ZqR|DjqSS)b!qxoI zg{j4$@n65pq(874N!U=BNZ3|cHMHc zW}*yuM}+7wP+^`wUQ}8jJp3On%1Rie0FePo9-&!<|Mxh8ahQTIL;<>d5VAY66ToxNnpX|i*_1BRF9)1g8mm z1wLciBj2Fx+J?~$Ezi>pV$RLX-7yW8hRMR?5yjy13cjN-_&>vcv1VunbdW zXx!E_0Yj+8*BPGli9Y$msks6EI@E~JqV>aLpS=sH*N*G0n}sZHbEhXMD1A;g=L4mF`T`@KM}g% z`^2=7Sp@9ld{A3t0JUM+t1d2r)^HV;y!deyl(_tmEi3`?TQ4L9w8Ii@M=7)#A#c@7 z%49evjdCaIu=$a;Oym;)Q6r><#p2ALv#fXf_nI3d{Ecp?{^}2^aL6JYycJjXk3Q*iN3g7|u?gxfsMwfZ3SgmlyOK!SFkvD2MC{gnaBVRu`?oJ}Y-ABCTRzS{4t!K5?oHqls2$A+Y;;E867U6MbQ9mze*?k+Y*bdj z2CN-sUnTAWzqKqRi_K39?iMNTjK2n?9rR06tK_c%eqk6z87DY8z)$tJ0%}Jl7M+PE z9RQbT6;4$1)eKd`VrdZN3}8oMh*Aq=2eRkfWgaXKQ-oIz8!z)WW`&aXCl^a1kVGH} zGZ027poe^on)@cqOZXpGQ*;1~fzlsP4V*;KKTfQ9vVl>b;kp(d2_G-u9b_LU?y1kC z7swrK-#V_9e+$?hXunl2cv(OP$Q^kfAGfxq>m` zLMsU6;8^_;&UN^c{n4|iq+gcW3+6ugsH)ykufG?>Ey(B*ey+b4WXc=xzF{0+;5)>A zEPklK2f(dooNHeI7=I3!JM6wH{!G9-;+LjYDv|JE+w zbZxSD!x6S5ZwL>~6U2`3P!Cy;SpSV7Of3eT|Ne_$Od))Q{|+CC5DDKMhC3(`792)j zfQ29kEI$G$jN2bODzcB?fS?YJ*B>c5ChYdFkvViJ8noWWxqz>Tf8{T#3-SUpDiEj2 zuLJtRGWs2#E}#nl(+7P2+twL(E*z(?c;GZ1vo%a^tD)udM# zYE%tYx5quc+vpYgCQpZNl43;cHiqLHo6KaHs*wnK(Pj3yePcz z;t|2#VYpg2W7vsLKkj#&Y}kLxy~aEFuwRH{y4GZ$D$YoEb0;qkfQ90*mR>llyR6G( zD$(&?XY3SJOKjBHSH@4UK@O)zg+?J7bS;gZ&@J08UoGBUyc)m8-Yw zzRACT{t5;0tHRM{g*5N0ce>C>IV0z$2b=hfNBmoNNBUEB@%D2>QX{p```j1s!wwYi ze~vn2`B#Pv)4vB8{)r|06JW?d&&c?nmGT(>1jBxHlj9Me8#_7Ghgkms?C2-pn(6C z6GQh;sO|3=B&@$Uvahm@f1g0Yn(6D#KTi1Pz^}^IhKj~c_?q~1Up1`p>6DD!oba{3 z3NPaSD}#pRpAox%U-m!4C0XcM8S(%A{g)wYPy+G|6We=$%RTO<5!1Qmx{!V2$a?8ef_?444Vt# z8VjDjcAHp3;~h)Hr@wvv_<1VdL6K48eTN)Sn3yIT6WegU=FRg{dt&n1h4z&v&`pnv zm;ObHh$=0s=Pe8m;H_J^uB4!^dO5~j{7w%jP(;@rE9+YpEgo>!u0p-HZnhs%_>(j5 zp0}|A{K6p9=Mlpv`$U4x;{i9jS3V={-=1#-Q zum>Z>0+Umgu8B#eeygTc+5))LU0{%FnwLt8;tUe{Tj>CFsQ3WP^}2O?-a$EN2ak# zfQ4;#`CyJ@oeVcv{m`9*4UM%_)EWS*5r=m64PggZwBiw{5NbF|+1>1n?kJ+ZR(s~T zVL$|YJ*3Ai7XbVeMZEhLP{vQEO1m|KDtnq7RddhIZvJP4V{Q(DwNAz5{)n@Jc8=uV zFN=%D{%aH4Id@cO!^#+GV2pN%{}n;NQcJ!WOx~^HKFpcR9YcC=v|Eq67gq~ zfM=BHo52Wfm0dV?YwF|6u=pcF43c+Ld?IAV(`Q8(&bryZS^|^jRlXS+(N%CjJypXN0wpX_`d_h(5%OEJG2%!=z<-QZdJl%d@jLw5YN&MdpV2{( zPaH}6Pm#=V=-M`|xC`w9}pTjm(e*}u@ z+4y+#DRtTQpdAu;5xMa5-*4~?%k0@r0f={{ysi^xLk}gPAu>E4`M*Sv|7Oe8+$sT0 zeRNuqmD{1%Hnz+XIttTR3D&$I1zj>f2r$@RiP36c^=DI7nH5(3tUAU7qsKs6BG1Au8T>ni~+Slt|(75e59;2D>V zi~oM|#v(HHGvP=G*h5Ync+HX}pt^GcrQP*Ajyard2$c>-LFgP(knM31QAoVG%~5lk zk5mk+o3jD9w}aQMBw(6-=Ge|7`2> z-I|fAyoJKm^SjTG2^bnNh!FOB6t`>0=tmo2u6oii{bAH;Ok!RkccV_svd4Hn*%43l z!8^p7GGTD}xkxh^oIj?zI^Z>Ji0su=mK9@&nwHwN6)p+-Vmcn7m@KoH?5~`%v0I;N zkEk%YiR?`$SQjQ4pG_MdjZNw6ll$7uDcQ=-bYe*w7o@{07*aJHS`h=rm0LqL6~qa6 zq!WulY<5!F$zH?gkvsgi?=84eGPJFxIDwAY{;#=s3(1$J;M12b(-Nrar5mlk9I^{S zx#TY@8rb2soa4zVV?1++p`NmQ6bg`|Gk+5E!cemZmk&c8U0W@Xe`oj=C%mR{^;+q) zBqq~5-$uQ{Jr#4h25RiqUZUH{_nK>mh3@u0*t^T9$hs|E(73z1ySuw<;O>yPySux) zyCn{Zlem*OiMzWyWb=J>PF3Ao)m=Sqci;X~zZh&5BSx?T)?&t-@8iZ=-0uN9)C2=< zqz71J%_tc$rbBE&REq3wOrOELLJ!`bAbMs1t{W55gosu)bWLvaA0dGuJXb>dREFgk z+>=QjBas>a!4jJf?v1Yt;*r9w2`SjoO*@WGE|pv|pMbv-8PBr2cw6I*xb!^ooUUZT z?=6IA+u*e(P2E2=NJqpRLX*gQk0*NF0TOVE--IOD#`Y3VjHBm#p&NJEJ3S=54K~gA`LQ1oiM@+4=n*oXllWu2 zo=*IJB`>8gS_s6d?$MMDW{wEhkT#?gTrru%79#RDfTKo1ldt{5jpl{*BdRG3*87rl z&$Uj#lR0b`C3TZEf~NhhBKkmS?x_t1!xAkX4C#?W`w`kPX&GiAP&Tmqc^EJOw|d`N zEc@A5##C2^idfKbXa*Km8YtW?+G}Fn;C=$4XXLdsG{li6ytRHVm>}~Ba;ND&3X|I# zbZq03*LDNhH?E<8L@_gtp@^2j%t|Gmo^<)KJ_$~(TkA&ZhI$}3g)lasyX&>|ga
guI`$U=Fp;#4Y}%Ya}sL;LylSO!Y~$y8%-HtlgNrL2)t17_&^ zSoOGNeH$dqXbSyzk^M&=R0Y)Ih6nn2tUtzFQaTpw@H_};I8~+s z`*5Yl5kP#(Z+kb@3Ak`eF?1vBH9ZYgafZfAh=j0h^lhfRK7D?$>S+w=*H4OD z=5daQ4cVQs?)RB0kVNEs(LsUA!^q){WTw4?lzO;TU8nh_Ek&y+%AIPIgBbIO2cKhr z|M29VQZbqAaD`biML@uox8q z3bdbm!j-JWf}gFPd@@K%^pl&%>h61&?q;S~cq8B7n1%>9Pb0;jGVGhZD13zU%<)G1 zR226DLKc7j^o>f2vcQKVDl=mvlAz}VYnSWAa?-EJRVM1+@kC}V#=G2*`NuSdzDF~$ zu*418_l_$r0%jshuzbw#9g4HQ?7gWhD{&JJpWDepo3LwBAoSlFq-zBlJ(K8Nz|-)l z<@5*?3_;LFeV;q(dhIPrEPKnRw`lUE#REPBL|irGN!CO5R#-IE)^SH#k-}d_J01U& zA$VelW^(&<<*g}Oxy0myiGb?5{-K`ZVUg*#ph)c}3A4p*5IECX(>POKAnyr_5vZAfuETE>djgav} zga;mGxJy)$oN!X$@-b0-7R6}oL*-S3!Jg$gTy0DC=|0`&WO`LHT@DsB`Xh_|{9_+n zJdu=+<0m4Jcm@`~D=8l1%pyrSr{Xrr0KiCfC{&1gdwQ>k#E{?!cjGa=k+>CpvepP$ zl&j`x52|$)zRMtqY;c7<5*|C*dnK@><>6Gw0%Cx)j|<1d**xb+3IXzHG_cYAz!v1w zj%hgbcZ+V<7{GF*=97thOA!1I|=d=u~;%-L`Txry_q(}ph^@A?WT>-rbNH~3Jf8h z@|c}ui_`2$H!p5zE5^uUp)VoM6mkU`7h^VUkbQn0pj^#!8 zfXL;6{a|60GJ$yH?RZnGILyk|tBOiR6ruHuVuTDVX-qz<0qy zc-RwFY)^gUxTm*B)J8_x3V{S<0lZzN&A&x}U<5Z=@N$o_H>5MDQ*Z$;SMq39)oHXXZFAEY5Tx?P3W zCgm)o(2$u2ii~pXw5WMe0uU;kJ(`;)vA3>NfFwUtqF~?K!EjFw&GMtLk*r=yq^~JC zQSZ`fxEE`q&1p3X&At}bWi*=V&67#!CGKy-!IYCY3@ss6qnVu8aLJCZ;1DkNu$Nb<|sPin^axS#In=`E{ zm^eK_M%skWwvN5@lx?$%QK}*FyvS$r-wj%iBFhbPaaf17lzW^pP_@4KV^TU(anHOE z=e!*zbQOU=&R<5PLNJ`C<*K6WDGXl2<#(joGUHM$;V%RPrUx=XRyYdZjvh1IW+2x9 z_>xtFzpSvw+$%Dyi1bYc15!p`2#Z$I7eltth?C?4<0O=hkJLK&VwWEv2PL()wI$j z*Z4s8L5c{bGR`nBp_s&DXs=AFs}ycH#Rr`dJS2jjk62rx1=UbylU&#|G!QqVPWF}G zl#ES&%`8j7rKU^L!9zPT`;}_;7z*SXp1=Ni!Fh&B4)qI2>C;z7vFXQrftOHOs9_`Y z85A5FyAHC3tThQ|oTcdJ7+WcNqxi&zs;oSrboiYet8F9g-ugC7iS{ozYB+7 z0YA#7&i1ZOUj)S0rN0A)zGw&2ZHlqt;;YE{SJCu;A4S2&&i=3Z#8>74$G?8^zfMtn=@T6P zm~9tz{wf4>{2c`KRp9-1C1_@bzgGQyZ~iBWg5w_{O%j&>*Qp3CIb)4vBaY%vFX+;- z0n2)$o(XP6O0bs}y>T;D)L2s1bVPLbZ#*L=qdx3C5V0kRdIyaB{R0ExX9S54&Tk`+ zM?X60^xn%qWZ$N){7%*sem48QKcy>Nj97L}UX1iynSEZod0K?~ZLR(J$bW?7da^q% zue3fb4_@luh~F^HE~~_UyJ=LISoj39?Y7bT*=o|N`{=iVI9|^>Hltc=w8k*MIYmzj zzh}C(J9YIo3--6RgX9^ZMEL(q;nXN`$iTl=vk5XLD6oKh< z{SW*U%g+1Lx_WjC<5Na{7@LWi2k+c22Q}m!8k0Kf=`eteWnK>w0=9z9mT?>^&LC7c z#?-@w$pxFi_uP&U>x;HYgF^h+Mk`WU0e}0r8qavQ)BE_A;20}PwqS2J9*yvyc{b%& zzbANh09YfY7p>BuuhUmZEIPkKJoUmnbA}so8JzDn6fQXb3_TVdUHMu3e4YAz;qGti z|3_~y#3~U{a?!X&>oYvwgp>7$i}|uYS6DZu#U*&0jJ4*$uZ-Y0!P9Z-p!!}*od_`# ze=Q7BsnYHG0WT(Gx3DpwIh!+6{Wl{^$o^k5sKV->8*g#Tic}MR*dvac(2k*XdSMf7 zI1XWKE-#x4V~DjRyXEuC^FCUTB%{p!g}QYy{GWyRNgq$Ef96MT2052KjE}ue7S=dW zxjNCfBMv&f)-Zn9usNxY^XP^#lQ`~byUPuYBG0zzc=z{*^>c_y{?uFQ7DV+L(b4>7 zWFlKO5w=@UT6p(#n31EH(iRorp^ELL&2Yv8pC~+c4tZc@dUXw-JiNRIJy4$@koOEx zco~Ph^%NUky!kvlxZoc4G4gYk6HezYpdDjC78`UcL!n2wOE%?OZ))YL$NY5XFUQ;1 zytYv19G?NraObX@Sic+>ghd=XjUK`tM+bD|*euiYUFebbRHv54>sXcgPC$xitI6ft z%4)dZ((2K`Dr~4G5`|VKLN$KJPEfni*y6JLx}rQ@3VggW>d-23EoFw`g-XlgYj=nC z0gsk9J}<7j^Q6IKH;iX}_aqo!RJ#f2%Bp;t0*mllkKDDz0$j7|f_cf}9@$`aG2D!`L3-vm+s`leOv&uO8#WIRUUC zG{R}!Dj+@fs?fGu5({tY>0sh)-_+%4j8oT2!pzQZ6cat%Sm?~q+j#{W)$B7f-zuX( zz!3s;Sr(;5Gx%}(Bhl&E22pyus0l$MZSLk~JWwvA_zff)?B z(cuf7m!)$;Sxj<8;t9Hvp3O=!SJdTTkiia9l;}(jKpnXQUW9@3p(Z2eQ*F0E(~}z~ zwjs%3gttKWcW3T3p^H3FomZ7+dPX?m3pyPVXD$~%hhL9;Ka zJBkA$lM?h)DhN(sLg{mUsHtHJpdi0zcaX|zqV0~QSEBw@^bk|>P<&1nH)_gXezs6s zzI45o83PeZiZX7Ds(dP+&CazMzz7CJ0i`OI(p7sSI#3E=bG@2&C>q*N4?Hwq@s1t& zGOx|J+aE(RzkM$Md3T3f52;AR09i>jb~_J;TE__s%$DMO2=0q<3ez9pXniLH%0GQF z-5(~A6@gACm%9pf15;jx%Fn=O;Ed~7msq-b97R%b&s@qq0s@*BlNZ(PPqlB)hbT)* zaVrPoua6@y0xM>DSyl8{US)#ge!EQJ{al?=HAn7>O!&RdSmYiVMy1-8gm%hvbB!CS zO&C-7%U4s)5pFZF?T4kc*WR4~*84`GFZu6>n6^M#kF?LhM!1sVya;?HMzLS($8Ao3 zX1c~5%5clz=r1-pXqgh7Suv^-O#$4glS{0WSxw{()DYYc2v4x|LrV$r<&ODTzDT%= z6HL_dgiF6lK&3mQT~{AYHRWfX-7PJBF9P%)X?@+SdA%s|aXuSwo;zHFaf$?kUs!|` z@FZL~vG6<#-y4ERvZo_~1_(Tb_~UOTgZi_ZNgclL2~BYnt>*?sxX2LcGF3P1iAn~2 z(oqxj)z|qzRlg#KQY;-B`r0;$4FtD!;_yL;At(!o$0hFSO5u5)CYo-lVB^5~7$o@{nB5MJ%!j`Ii|#kEPKlkLHIW`j!NN30sVTb|!g_DSks$ zB(sMF9a}J0LV`nvxX3HFTQMp|UQefQ&rusSwtp?bF(mP*Z(x^>tyM`E&LSW|;SfvI z8FvW$1b z8l*jf401suI<;W#FvN)CsE}0E9i~iTV`X*c5s5wSiBM2%)#f8~9QPf>WCYHH99TFo{TsLTzR1y7WW{F)srf#Ctf+F6^xwl}U zJW{$pY!nf=0hF6N4iW3T1gK{~3D__0>wST7R&TIa)(@_ofT?YOiDL}QIj$ZgTpt7k zC=9b#ITQ+bu}2-#9EVhl0&?t_l5{RiFu64IqReA-Wzun6Cs2z?712~B=1m%ND@6Yu zUjQ{_zPq4!cOo;qp7{^r!c{QCtR9^}HntL)l0vl>TYldn7^_}wq7D}q4Iy|jR{MYjkSF=0+1tx2CugL>UR%sXo{2xGf%A`H}8e^Tx4(0Mrw%#iJ|!_6hD6 zujA~QNN|YG-mVU^-G3>eQ=+MDtMdD$#!Wcn* z#Gdnm1Dw}jGG$dH54}xpy>;Qo3u+NV8k16WLe@}F zv9-j)qh)8yz`!vgoa$T6)teoxHNE8sD8jcbZJlyYO;HV$yA$Hl;B;=?wnY0Uled3p!A-&Aj?np)( z+;C)%ge`Sg`#$t8KXwg8(m^4#@7%diJ$#n2E(7Tb@Tg4(n!=^zFdI9xbHH?ue|V9q zm{&xIxEPNk#Zzl!mA~Qbl4q$2RKl^ZH5rfdu3xQ4rS%WtLYNTexD1udx!v}SV}o_- zc53 z!9Q*0M+xBdwv4kE&ixFpJ$ z_u$QtG*?dv+zdL}f&rWYLlcYuKgw?LCe>6-MT+wRd8cBEwn9O%j;Y|M>?ex7*&)?9 ztJ)M8#DhVps=sR=gvSrtX}rXC*rw*vqa=1`n`;KrZp$UOaz5ES;$ZM10YdlT0#=eQ zhRWBQUWv6GH$zeA_^Zb?AeZHldEy4TUQ{q3A}%S=^_+2yS$TLyz+m?g$XnccD9prS zV+z+n^ZF!)0A($xlXnK8|C_nDTzWIJxy+_8P8lc#oPi`ybB(m~uQhq*Hl)__=csLL zkQrEMw0H{Li7dJ-?0|l=vFEE(`L$O>31R@P; zA%T0~SZwnY_8>2_SQ4mjSiMLSvt-|Jp=CxTtv!?p*@mRh3L3=5AS9-7UiMW8Rqy!Z zn8K#}7DoW$;>^4p!~w5RQ6mh*C9hBd2=+mU^;H7BnPz5(pbSr^qR@xF;(s)vWx-QB z8|f}#x{Z`O1WsxlCI@R31px17W#0>Rp~Z|ik}uK9Eh24+uFBRrYO@N_>u!Z+7c4NALAo; zU-0LP?UaY7R+|GMi8ym&=!wDRLd*|6uOxP}bQ&vS@CRodzwQKFp%yf&+jle0RAd`k zz$t(vWc->b3SV+wGR%iwQ z&wl?pMk=zXin2M(;oqxQa4<(CTO-?D6$95SsEyzA zSgMZZuhPq0&^XaZD^h2cT_U7BnbsGI!JH9>AprYeV?r>;UmQU!vtWqMz0nQd2zUK( zd3qNt1igNadpp{Qx3M3gD4GGvxRyssJ)#}N5%sK#Jp&GEGxF{FI#E@OPd<%vqSWw;O9F*P5;&c8VbDsu_z3WpV%WpS zC=qvs*OaNd3`mQv^u1h)fviMQDFFgvnu^p2VtM*OBEoc`=ceuo9O}i&avS(ZiOfhq zUY2gR?s+k#Fdzv_+k>RXBBfGUX$gslRG~%@G9>ej98{LJWI*&oC8OvfR)%gS6hT;8 z%#1$dcCW@0$fp+iQou(z%qs>P<5$lj`#c>PvUp&cuI-FKL?p=BN3~9Uq*M^#RLkoz zUFYT9nN!gqgJ?4phM7{Z_ZlRvs|zwG`~1;V>n|D%E|JcV(A%XEyhbn&T)%8;(lLjP zO!Sv0>Z8c0jLji=Y8NY@*4GOPf6nr*;PN9y7J}^#2_=e(Kj*3k6>0fbK}kE0=wm6H zqYGn7shz>^>l7D{{0WI?e;(DR3Cb8SwV5u%vQ$UjrlMQV8P~6Ziud7N8n=OJ7BMHA zoaD%2DP}ewm^=rS_H3%}y1{;mylwA~d|Oliixu$>eY*B(bvxogkYy!lFWwg|DH)16 zOpAHaAJSPBD1HQVCKzX^@t{eVVoRZm1GjxooCVFhK%;R%Y(Y44b4s)m*Ta_(mmW<0 z{_SJ^RV2Olc5Jw@R)VZ=(q$y}hu!nT`0Xr(Q1{(#YH_gYZ0^jL-@<*IijZkGqXN~g zJTNdYx(4UecL*$X$+?VBO2m$Ks?)ePwK|7^XVr5z)+FoNuH}!Ty+@@{O0@01eC{vRKE&G)S`K7`i{vZUwMpfWO>y!s2&iohHgAE9!QSgW-d|;y8($l!K zfMHU#P6QACTY?Y5082tK5|YU^JQY~xa$h3*0HuTqu{PebYB&UBH4-(J zAnC?;MlBd|?d|-Z4{{Rk$FOvRu{~P3lTeA4A>9~h?#kfVoiepRG1C8COr1VSs%R=t-k?1e)cX3xH`gyOY-zIxj$&C_}Th4p2Dvioh_8 zt=aN;k;KZjuXW#>wo=-p6p?1g-s^{EEWmKyg!Y zSuZK^{JkM3#vng6@+Q$nC~WPp6n91NX^+$Stn6e=SeaRsNu0Z>r|c=2l@t>m%Xm-> z_JuF3)$uJ|P(&3~B~b!qd^fE(u+3cdo_SmdVQmlVpW^I-Tj-Zq7*TFn#WUAzTgdH5iACOj z8u@^bm}b>UInqL6$&oN^xnMNQP4dI&^9<0uAf@*r!Uz)-G&<60Ju?B2@^V4Eh7&7P zIv&t@VC3hTwZ_2k(6(oKA7H2=6()dA;b0>|9?fI?id3O#3=&a$csc^(-Tx$1NhMIb zFO?5@E4~{i7t4xo0jKvpUT;e;Ai6}JrLIyb&wuNMq#a6XDjpm-XCYh(9`eGF#9e)4 zJB*Jxk5~d|t8qh$hbwb8R|PASb~MmHM&K25LY7JaU5@#P1D;QhhlLF2_{m1mYP-?7 z5e48e&iWoMe~NJe(VAJ=DIl~hNo?M}=cD%P-i+|NEI2HUoFA^OF<)qG`TORieM}PU zbM!q_SZzHqzdQSe$BAkwGpQY4)R(U@KL$~M8;8$448Uaz|Bg(Da_Q@%Pk}}2HX}X| zDgu`mJBZPR1!xMn^*lHrWRDTAT(a-H1}KlQn1wC9+YvFinK1@)?v;&wD2C3qzg1lRu zg0N3r69UOp%kmnv@Rz|#R7#rnvLjp^u49T!s2=zznomW9=XJL{)!>l92M=#V(1w_M z25d!IPCTikL3WF`s5LScCX9VlQZx4k?{a`LSkO#vSmEV02@)@a<(9LfCuHb-M+I*! zFhqU_X_K>2CQSvLKD6uSxOz!53tez>`7ypDoHF=mN^%C|R<(~wK7%n`H{5!Wx%ZVW z*V}H$ox}2zSxSTMT!q$^X2K-hJ>XI#A#PBdk^F5$HHK~_G*VRBvUe0oDf80T6H_~Ei` z*&!M|=Zyf&LZLXiM z-Q${VyXG7f7R4-a4VhD9IaH>f;~J$48|xrmNR@A9CX`l~>%WUh>b!<>pcTb zJjriJV`D>2W#s%je=r51&UN+Jja1_qx~BBKz@`Owc;QU3r5Z89oh!_vC2wECeKZCa zttNI|WAiXmoKmd~{}^iykU{EVEgJGPZo*FYvU0V-kU0aeQs0@w*ocp#W8~aB?`c>@$iF;U0`kvSiVOfGQglSRekws~ZtD{}oVHnnKo^oX_iVqr zpMfDZPvjDFqXnU9(xpMn`DjJ>mSai`dDE(XP=MF_F2IVuAul>R!rU|K{U-Y3)(Yl1 zoxw#Wgs|?ydT8(ek&%G~X`eHuH}SGFFfzfZ=N@yeVDKJ!RQC9Dt@ef0TYUmgusFhw zb!*+vE6dh{v$vS)$669e6vi(&%h~ePvKax<0W*G@y6Kx92hXTC2(+6iVPrxrAjcmX z`TehzvsYc&&zg^1qSt9YKt7MW=g5??m&sfN(w^+Iup*Q=v~zadrTd{A?Ju*T;}`I$ zE@`inE-RleE2g25$I{?_>eJGu>wq1ujW;;4ANGArZ8f$3^k4#ZcWuIn^C#bc^nx%%_-z`T#ZbcM7j;DDbc z^N3$xyuwN~ltd~+7tq_f{kUF>N7Q{Q{r=6yK4wOzjo?1easzPRgDpt)bh$T}!PLs?R7u zu3ku2Iu9U>DSrKWKMTIj`tr%kh3ygQOF*%yTuZ zkD9iKzpnjVqXJ6bw&mnzRg?(e_sc*S5FoC7iW!F|%Jv?hR^3-31dno$fRQ+2f{Ss@ z);f|*+Z5`1;t>}W!-CdjtU$)%Z&r4pn(4ds*`2vH zBZ(|)u!u8=d7OdQ%)`yCfnH1z!8C4^oSZCTYgRgT#e_>S-X|*V6hA9DNCVo)Y3CLM zA^BVgl%=Sr^oHY&7EvAV4ch8;zQ7l?riDZR}}7`UtFd2g+t z=s+5an+lRig;H3|Zuhc#?QL~8w@>CIyw?_>lb}!hgzk;7%N^em)qq*Oc`=~R?62e@ z(d0-PPABV%Ifcj=&&7#pqa~_~vM<5mkR#}A@>M@>IMSHZyh{f+e^0gAT9YKVGwWI` z$*&nCAbfht`^{&;3u*4hIu9rDa7YF(h*6cGV4a5|Y2mh-zf*C=!Bvd(m|(!z1%W^D zntk>2vkiW$3raa2@+l%Bjll8B>-@!T`N7LM97z;=%BZ z^N$~#`&B4lcpT7aA}Rk zOgnIK_wX4R{%XIjFivy(Ei5@`Ir0qGIi!?j-BX*vX1<0^$8i*V@7*t5ztTbK!W)gO z*AsdeA-D@{xioFTp94wl?Laf;*b$+Uk{7yfQM_z#Qz9!vXoi~hYr z^KS~qe<4n3%4-Qri2s-36vscwwrL$onOwX|rCTY>=En?gdGtjDjnEEi}kpV)Y-o40JwX%GzshTh4id3s; z6v|~1n*NB0JJuY(>R2UekQXmJDn>R^72vAt)!TjjuhMi`@K&O;1d2x0qSN$4v0#D1 z5)wS3OdSHIel{$bK1Jymh};LHbSbMP9E9wy2j`ASaUklBMe0(^(F_9D(Y&S*NXb}F z6u4+z%Y+M}<~adpfLRLAf~5#bcEuf~g)Qd(JwvS=*b!P0ZlnMmVo>joK8*qIAA+YN zwsfTHq!U7!_{n%qu8u!uez)sHH=vJhO_%@ioc{Nb?O#rJEdTam`e(GmzgMRIe$D-d zJN%E%*?$A2Sh?8#%d`aGgKTIY6}8nbP>S;{kIg!nLwdeMcD2O&M8x|(t>uz-_0jv6ZxTkjd(X>Z z?n}?rllPjy%T`nV8{ZM%(YmwB-=b9Jb&28F*azr76Maa=2N7#}PR}pYXSS{Yq$(n@ z*P+`$RE3^{j}C9>L|=snmV?1X+_c~ND%`Ovup z5G%q^_Mr}kQOUn^8(z^4@Sv{3t~(aX8BPqIR#sL*&;k=qli#MXX7~pAA$LlV9&_gW zZyTMvX+uF0arMlGtu^&H%V-0Yu^>SF^z0{>bmqL#S@4TQGWQ_|Zg;5jzQ2!*tB)UF;oEV+=&Gv%BdF@ehy z>3cik@RR-6fZ>Q_Ut@fvBOL|yXPvY0=g1iFEtqE#pSYhwURdG{o#z)RrBB3|pPl-5@ zU&s~EXMKG3BKTJcPlGrJA{*gj$Qi#4l;eCPhj*g1u5e~Wen-1~Tj~Tpck8S$H;d0j zGQ$w5VO?8?UI^fcGAGzuS%@)I9 z^1#Pecw;WkKO`0{z+n_EP0NJO^3g4kwCZ`sh5s4*uD1X;e|c7Pxyc9cmYa|i3Z8`d z9!Gfk$f$@>GceAQ%bH6uQQyo-@=Es>RAR<6Qn9MjdtuR`? ztsp>YAoNTd@d747IBMF%q8xYo&F0pM zC9PBuI#n6_nGIY`8GTWaeo={^U1$LJ4dhCTRavl6d-Dd0NW zk}bERGTm%ujBP|L3R2mJE%_Do;JdN(h?o}VgAm+O|Lx%nNC$yHFq_zbgPxSE1vPy+ zI#M#?4hfWoh<4y8Pod>(|0ej|(SwU*2hWj9^K{-KN0Y0B?A?9YU!atwi0#zEY1McX z^?_;Wj-sEwTW|i!gu~j@|Kv%%X1(&weu)4m*X*1}P4#tzB(L$&$I)IyRbL!U5rKLw zVUk~hNRL7V^qo(kcpBBWr|&3o-V=Yrp}Vy2_g-XN#BbZ(7BV7; zW~6Jc!jSUWo}xa~Qs2B`i}@4UFq}7>+q>g>ZMCavgR=2y(g7NF-Krg$tP5PMvK4mK zuI)x#+HfQE#YVH@uAdG5md)M8oeg~_504R!CHmiKX{zJLhdTIZi)YN88qB$_W(#F^ zAsX8lE3{5^R(}@ojz5VO68AV-9QRi+V@=(#i#c-;Gz5dBi{JUc$IccY@+|R~7Xjm> zzQPMk&!mI#T;aYTdHL$f`IAT-a{5SXl5`G1vx{5$-)0GI6@)wZ>ocBB3^@kUg$cPh zOLB(se`{cs2yv*V9Dis?kxZsegOXjzk;|moJOZ8Kc*S``@h`8dm*ix8+&>C59TN0c z-3@n9NI|@(*KZ7J@Lx%&1HMFZk?!ay{+jTF`hYg&K)?(k_V*`TACxHzi@UT~=0swD zJ5^jm0#1F#)o^o*7H9gwY*ibd)I%PrJnKN35=uPBH3&DrGkSXK>LMr=HG+tk?vc|O zB@KOI^bw(b)<+dMTzFYJQG6+Iq>Pn6!M_2pS3L%PczEtee_*10ft$@4n8AAw03K3y zuooQ9orG(}Pklqrv->sn#AGcTQVuQPZfj;?`U!VJ@(K;jBm1<Cu#iVP zGrThE*`Au*o~1a?jiMIR;*v8+V!8YvOQl`gi&FqZn-^BFyzp%8CVa zCRunOS!H%xj7rl(;KqFL2Bp8=Al~!ZhBV9Y1&U4jKHcG1CMrHRXQ$sc`6WQfxpJ`Tq}})G zN~uF>X&1><2xnFRJF!KYE<1#X$o6s=3N^f&L5XobiFpTopS?`|E=dqiER*G%YUuV| z1;-FR)H_VBhlHb^*jn}AXM!-aFKO-u)?Nq^8w5i7#+N9?Z?GF&LhegY9}q%!5>gn~ zqdIgB!93ARE(0qt7FL1d zg~kO)jRYycm$EYQ4g3jPct>}3rOA%($TH#%(I&BE*+9)rCfV|t=I8LKsSnTGLp|27 znBG5Kq=^s7r2gwt7u4(ML+|FM(+4*LQtEU6=w*4g7lOi3017nw9`1vSghwzVzx>(p zyLt=(jVJ^`ENPOlsT34DNm_iI6AE!nF2TQce1*NtZDqo!XoVhzE8`bRr zqG$ps!7Ck~l8RSy0?AG@z`UkT)eU;f$fh#Ypx-rdb+&cO3q>H0Q!OOFe5X}HAD=l! z!16m(JRTl3U4cZM5?WJS@`NdifkXuD6if;_Cg!3;DLJq~SRCq}%=ozV^KOw#TzC$a z%0L6t0iv&9wmsg|K8Hs&4{RyhacjE@8q8*H?E|Lw7b(@#_-~|?RxV?spTsaMjdvO? z{X{KDS$jZnytM0xK=Nr1ukhUUhTmm()Mb|33Pep-G7UPXX}Jyyte%Qai&u^6QFCd> zK1?wnb!}bH%eQK)OnK$Kl0mR~LQosr&iL^e5+!y4(yJ4T!qK;c_mHG7yuExIs2}jQ z<3YmoxoOvu_X}>&(txg11tj|iqzvpiT@?`ka|G-_*SJpJ78jlXuhNtdt=YApzPJ64 zK}|t@!HE4AHYh7+YFfaZNnR*jW)jVf-yDgPYT=PNuFdOTzw@q9XL+^xxb$KwO9~H2 zjY+R?k@2lC)lyjtlhS_yq}gMGDvywYtrtX(YKw2AL02r+{5S`~rvhmK)hHY~~uQ)${=M-S4^+?BpTBA0Hl z7ACJmoW(0^?ABhzfEvZS33;YQPLDtdOg_kxX~+rs;ONcd_^DN$(V@RFN(%=x-qL zDpa1XeHd?mzc+RBC4rN0RnPk-uAerZn2I2(%-8!U`dUpZW>y4Iv+RY5ivyWL@LC0@0rhK?9gu2rGykRT3UFls7AL=os0SQqn4W$Zc!9 zA7;GD{EhkX_*z@|h4$b`n`qaHre9OIPIXZYOksv$btqvn3_x?^N{6 z)TTG`x9WXeJPN;BY0>wV@dYU&W#zxotOUC)XP0V(-g`Oc&_7*3^XV@ECuufC^fr4QgTYaVUX;uwT}+ zp@SG2`Gj|+fMilJ#DE8D^ii({XN!tUg||G^vZX%hs^RJ#=Hh{fCbM&RRe|ss>a!VH z9;lVUrA(~IEtE5$Qd7(8CRa>K&b;kr&%kF=%KP0Wl8H?mZWTyBU%T{T9o@FsD6ck^ zK82TC$5LU+(jrXW&V{#BmTnen3eL;B)|6dqy^m1|hf}F)qS!Y+C*Y@gn((?~!x5bm zrtKG!(LT}(baGuu5+|)tFQj${8eIAm!rmjHk>Is_dYf`GUX)Y)xgri$ZM3~wd_ zd(Cu7RhE4FQT*HB?H7AZFK(^R(dv%|M1I@sw^#q!%ZJJJ_32SP=ZR&9t8<H?UCp@|!o4j>!3<#%kMsdCjHB9BQ_gWYX>;=+ ztqvWjvl+48zP>po6uP1v(BkQV2&~WW_9XY++~&G;`o^(LFnU(buRJJ(G6ul!xC@QK zY~>rBOp~PbthBuuAI>6{if=5>2_+VI+?FTp2ra9L6Fw-CW$}au3P%Q{Lt+Ko9+1qX zHDtf0w&WWdrA%|I(cmODB?McQbaYijelix4-`q%omrBT*r=^6H9Sm3MIS~9RcrS~g z$IeNZ&6`c{J7ZnP&XGt;B$kejC&X~U(S(~jhgeN>qhm9nv5-&{F+4^73zK@RuRyCd`?dn@3c@WT)H2EzP+Q4JUe`}niB8Nr%h>u%_kO7Vk#l4PhfQYr1) z7KHC?rTiBoVyv&Z!E{(%xrZlm7&1A6$oC3uUh83yixM2p;km9~e~ z;&}DjZO>&kPwOOe_m5`E{Uz*ur(ioTwcMYku6N&CYBEjRTiVSu!erBN>f2f8eNL#k z6JasBjK=960m$Pr8G6$Mf;7Z)z)7(BmsuftYMYI|x`Yi0MDBS7WEg5%l^P`UQV1%` zJRBqMrNU0xU{=25R=0{_B(VZ)Xj9jovoow&ObEHq!4Tmhmx{0rOizTKa8DL z$79uJ4B#n=$)g#w^98NFOeo;CUEJeDOQmVA-(ct1u;JmSR%F8fqXciiGIR{isi+ua z87~;=ZALlg5q}H%2sbe+X3p0wRgeD}vZ!BxdNCfI|z6I$8qf<^%FPNs7#&>Tr zbyxUuAJ?NF4m)2nPy%)KRipB#^3py!!Wx~1w6h1%46T*ajylP>v`drs+gKo{JYtg< zfyfdy>&&!Bn^TwzSRtuHTw8JFr2etO-{q2f{@5EaN?hdFd3XtEgIBOao_IM@eavxD z_#wLCaS?Q&ATCgbguYojFSiaXd-q&YxlNFP)Uf4l6|MLa+jxLtpEmH;$Y@s zmyf;-!O^6*ZhuZB{3DN;ae@Qu8o4jZrJ1xU$V4(NoVMv2u|yxJXTKx}>$w4PuJ8!9 zXYL$=4rwVq3)N3_T`n2P;J)B(AqkY8lBed-?!Ls(?t-hLR+KeD;TQi_TgQqCpUu4= zCrrDjZ!d$VIcgNE(!Z{z#_)Vcv=(`5>?~yi^(&RGbHoa3a$0NcK5AL3tN=gXN&+t? zV0*TY7-=#H+#K#Tsp^W{wI!nH#qDl+zS~vno3~wbzn|m}8kh+hcu>=`hxV!oty)z57l#Ms==BkbMikX8Ev&FL6nuAe_G~>h=5s~hv)KT3Bhv-$ zItJ8t`!Uj*G^e0R01ongrmBFr(koR5UHwK|e<-XX>qj4;OGOd74;#39Xxg|AW1^431;l5_CltGc&VPVrH~h7PDkAGcz+YGcz+YGcz;G z0!x-GkL+_#-}}0IrYGK;H@~_fDxxZ4XGUh#rpUF{_j%j(?hYD9gm~INez88L&G$*P zd)2ipMKu;{AB)fUdMa72o|Jy@bhxh6old2wweA?B4M?)}v>>;9JcMpzY~Zqa*bM}p zmek48U;*Tw97!e(_p?DHHbxR0@ddov5Q*Kr6Ob;n&Sp>MPZCElPqRW|iI70e&Boa? zgr930v;l=PBzlZv-6tVjU8ZtXS;8NS=IofKVZA0n5Z?&ie8k+tSy@+y3g!H6fjFq5gaOC?Tv;Q@|+YH%t)L25#dO zFw-BCP7U=BY#n6$^iw8r-1CY~WgjL8!5A8nFR7|DmFZ~}jOq{W5gW&o3=;t72)ZQ` z=M#6WZJs=_#ssT3;cJC4hB8vs{49J1>?UQ-!4!fM^dZajx5NEJf|6_P?qe1!CLtIk zMokC3OxYNyZ-ZP2)%R|Q*mU>+F1bN`!XdwmoYmT21j_#R2suyW_#k=(iMAf-b`fB7 z112mHG(0d4DdjTVwrv%UiN}%3RJVwws#%4yG?NblKt7RhDh}fZdDIOfdWjQ@OlQNL zw$QDyy_d|#vn2yZW@~IqinUx4MYplv633IXRPgaHtjyv*)Gtzh)Gyj6Ii#Y7%KADL z4Yu+w4iR8plHO9u8t0~dVg#5iX?E*R1!S317ITc@8}eKH2|r!=6SXQRJd5SEuy(09 z%h1(|@Hnk)qP1BMesIFDHMtFKglI>PeMO=?rTRgzRjP>FyyPgqQ$;ePcDXT__=GvItn>o zjt1JvQ!PgfSIJNbTX7SnN&bdWLUS@#f7w$@@2_-fTwC1)bN0?pC|qd%`-`l-#&J{I zIe-aN1JSQ3L-$3t5-!+i8ak+7{5K{=GpH1_-ZtZgbPh%Hvr8tOn@Q)R zLrtSBipeN(H?i)WtgP~5)yiXqFWe97G&H#+$e$d~fVR9(KeRS>Rmu=qA6gsyi$Gox zjLEE&UD%31mIRV9Wxe6&0)*2xHl_e@i-XPRE$kF2#UF?+be; zrY<;-&sN==Y`fhbQNT!MNmz*6rEPJtB`xQc@!jR8aiyqhHb2b!?KdlwK!ZP)Pqcet zv1UncsP?^BDw&hy9b%>ADj&-ku_+tMKbM2^JoJ(9sC}mNtw}iS#X78Z>{!Pn@bN$p z!B*TI)lbNMm>QeIDb+9!UD!RO!Z0l=bw=HW0L$T*o0MhLZ6fbN#b3|z=cULv7T_LX z9nyF>50u@=V8T_}U=j2cjp(s#g?q3x~IJ~X-v%}1?xkyu~^jaLa~`*mLCRkosI1XKoF5u>|R*GKAI_=fivWn1CxKDIVl8^86 zRj!VdHBy9?2ex|CB2!`SPKiU$wLx#1vYX#lC_NX@JT85Rw6`*tW;$t$wfrMQ3bC%&~_rlxpoM?b7s|#5_ zq$^jP!xg(plh?Rta+iUiItPVG!`|G!;+Q>ncUF}s2m?L($508(M76etX%1)Ou?AN$ zleuBVyuHE_v}X1U&eJPx4oj8xV)j|pxI^LV7PczKz;QFym3K~;>wEF>dX%PfrZWky zmERTd2i0-wG$e{w_?qE|xJD zUMgf1NIcEd|j;$2}bbv^R|j=A&?Osb*wr&*HgwKoRqEF)J?eY3>G%&SpYW`E#H`^9xjR*aB?%Ye zR@(H8m%cqwap}mfcf&5%O0PoT#ij3A(u(kXnY3--5jhg1c97@vRF@Sq(kMsIDolq9 z1CjF@wFq^fxSoy|7k?Mdj8_}sM`?^TbqXfm)}Pt}_;tVzpVe>qyF^pFZNre$#)!`Y}~c%R2=|S4@?R7lT-Vt+9^q zw$!A&8CFvAdv9Ix2;8t?T@&#%8{1kc1+R5>(P8r3rhWQp_^IeG?kVYMlH0iv8M4hNnQ7d+ zR>N;Hq?ssKb{7+3n$tTi#qN)r_9U0Mq_(Jq<7GD$HCjq3X>_zUWm<_D$G*%@Mv|_} zb*Uqgo>6{DEm;~8HecOF%$D3UWNhrg6xJ^6GA4}at#TA*HR8)9CicVYz0wzT-JRA} zA&{$W=g?R8qGKq&J7vPkYNbYT=|*3I;O@^4bj2WUI@Lgk3 z8v0FTo07nMC`3`&P)_lq_8rBq;ia8YVTv2gPF>GnG`-d+%x{gI$t46N%rfwyKBnMaDTxtDYBd`n}lmW(7O3 zQ_F_=TTYT{34}Iw8!v)m?=(|b%TZee`dLK}Df}l9#BU-$W!0$TaW!FV+M0!Q$R=ps z1vp=t=hz|TvtGKqE5E*Ut0@x8i=>M{PlysYVN<0$dWWV?lJo3}Nw7MOK6$5lRLQeovwXg^x$M0f-i%{vYQ4cp z^YJQJNjP}V`3`=5_jOOTS6&6&pH zVO_6Z=SdMOm6J8xPOPsXv3g_#C*4s+C2a?r>~#->yBBKi_`5WNDWUWXR}QdV!Oy67 zzco@~sSaRwM4!EVT?sxELHPUHgF8q*!nk2YG!4i8oPlC`v`SLyTaX3e>kTCLRAszN#1>3q3($HKV1&qhn^tL5NG!p=L~1| zi17ruBHw}S1MS-l8iei;;eXhpocJQ20iUnME`@mlT@jJQczjnQRs&X}R)a!`f(@#P zXLV8Qn2)K0XMcwNrTMuIYl9}5*b3dzZRLB!DW`^z7d8S+fF zkHKgHb$X=r#~syxl!0hMG%aE&Vkwa6rxwG3_hEbqQH%J{>A*4iav}MW;rk2AK*^iZl`%6KWt%g`S0yi;(04%g2-oOAAAWYKXw;Q|DvL2bGE_4PK(z z`Y0kEg))gy<%7vbQVO9GLnG>mK*q(43WFiFh2n~^5yKz}JR3AqpGuMUV>HxZWg|5x zgLGn^3HCBFPo#Y)b6OE)MX3AzYDp|1Y5M&EsdYi9kt{@!kf1^_vqX)Ma6(aXM2Tu8 zAVeeLSVG~kgsxyAxsb&E(Imr&1)(=cJ4De$-J%~VDGkeHZ?bKqpU5OV0-n*&uy<7Z zD1#%RF^D9g2uK8k+hVw)oguCm8?PRd=ME!hJBVWXDyd8lHK9F&m5PK9@cXut8VGs( zBb9KzAO0w!?MQVTqHl7O>tG)SDT=`hwciG*x_W+nqrVJN9URlmqJfvD|0Se-Rkz1Yz+iXp}q+u>a2WZ*#)@v9~qA=Tm9du$^;bF8QTFH&gLbz&% z_kSzPwEVQ&aUHCOGE<1?qSU!^H_<2Ep!W3#Hv4LUAeWpBD)b7^HyDt!?JN^54@X+YRtshZV+v%3|FfHmu;x=6 z>n14^QzQOsR}A;#J7`3d_htCEuEba?m}&k;NG3vw_$@VAU4?uS!W)bU|l@e59`->RjeR?0qgInMb4xM2QQxCA@S+U<*`kMH=p>9Q{tXipqwDzRAYO5J3-Ms@ees;O$4)n-LMb86MpgIf%*nE z3jE;@*(XHsRsQaO3A_eZ4|Di=u0KO=#Dqv?IFg9r;bV>{jrpHX5&@^5GksGdLJ8Y{ z4{WE*e>bw{DAOPb{vMVbTcNfzY9_dbu!p>}rxk=gV4RTOphqVNeSqAc4n<=z1O^cN zGiP46PCjZk>CHxeMjTJYIk;FxXD)P7**`_gAUzhB%T#5!K9W=HPJT$E@YYGWE8GkY zC-HDd;-ikEGR=kWe~e;rFN-Z+lpQ}D_ld9U#`V#IyWQ)q?9TT&1*pQ|2SUDF1$00l zz<#?lN;I>TR9-mls|v`(n&)H^f23XKE?s7=vd}?M?=X-NsV_E!Q*|;4DOtX%~|wvI2u8*plnM+(Fdr4&B9c# zI~W}OHakCBk0(VUB@{vOGp~CzU(UvGFM4~_f3|b<4ey?qH}85BD%Quklm>Zi4($xq zN#ywQG;|VvDtyxaxmnJ_@Hl#TG*Zr?&`8Xouq#a#fmIayg^9g0o$TzEJ+_JH?#pEJAs`S#A+;m2v6R z7%+AU&IUneJZQAARUTCgtZQ6Z0({aw6jE~X3BMImC}9e-Wxvs3K5zAMfCmU*N)XXMjuARFAV4_NU;AT)9~-27v_H{ zBl$=*{Wpme<3AG+S%2rZe&ibdu`&IXwEO>xgKBN$;Amv{zfD4A|5MEKf02aB%=AzA zDdETO@_&Ye%KoR^=mS#wn}o{#S2@ssB%yNrsSEmdBvg*S%75tptBl>M%!%fsX1m~% z4{x;dz6!1t5|Bjff+-p3OlP}EvKZd?_@+WZ&45nt?jBpRHu@9Op=R3a^-7^UxzY)Q z%X_D{iD#!w>kGqQSicy(zyGYUetWw(z3l1n#_w@@wZiIol>cRKeOKV}%J+VMbAW;Q zeXPSRdwpTnl%eL{%7G}FZ}{PM0&~ksqsw7-(@H&MR$j#=V*nRsV>jjKxS2IFXT+!> z1ffRS}h-6-2T zeef&uueU_$m!D#mC=@L-b{ zRhH@!=-p%R@wH2L5G}@%iuLtgg9Ikhp%_1q7TWF(zH^+C+&kWT#<+1+EW5q4-9HR- zq=mS>qu=YEKpbQ7#W2OB1;cSgUDkx*ZKQ=v9j*_B-r#Ip9nU_|6-y~GV>bwz+L}dGzLw3Feuv! zhOvQEk;6k*Wi#_-V1bOFfG71AN&KnVeTy5O4_$HHs&Wu=B;CGIGnp>;5#6l>1;3PUApC3X|*zeG}{|LteVeK>b=qvv*ahbDtoaBtU``|O3mO8 zPOpY~k%+IPQb?h#Jt*`-x&<|;^m54?Yyc7@qcloYWFvLR-G&aUhQ@jBgoMaW$&p?s zdOB)bqX>!HVr}#G}tnZGgFaqDG^&TiYaFy|2dLKkDp-t2Vy|WAs@@ zvk&L#2%BWutYOBRA$9_)0r*iY2yAbKL}6BHgN#0KZZWUCg4To<+SDTgt(+>+ee@yY zcCboSCF6FG@Y)DT1_g)6wFVVLRpZu)JnwS)2Fmp?_I|b{LM_VCNecd21~}142aXv} zm;*dig4-UR*Ke%ow02#CZ9$U`wAd*hJipEQ8*1#km1^pALx&v<=OBfBEn~$xorq!D z4jPh)XVz&nvR96l!819Q=xRB0SR2c4B`&B@fNT?_!x}_2)w|X~l^6ceX?c=yEXiW*wfrETTu>P5fe8wPa8tjk}Q3Hx|Bka-o_t|-%YR5B? z8)d<$0{cLJ_i9Ipt)tx}mgX<5( zHyIhcDfwUf3&T>%JKfu*J%t45qdyoCN+i&nfCHuNe^m<=B4*UQ^(>!*4T?8DIwpW^ zpd5)>aVxU7b#!Nt2HF)h(&18?j5`_n>PikI}hvDIC?!mM0?f z;%pSnwu9K)T$1BFp<*4+%P92XR#dh^JzsW=MX{o>us2fEC|KYMn-nF^V!>#tvY@V! zInFm7-dQ9mCteDhknZ3Ko8&FdrmZnOJ!F(uGTBei%5)`LjH9lPI%V51e33%3VMGAz z2;V!RX)%6g_hwU5WTOAcYii9Q>|hN(>MfSEl-njq=>;bv;E+|C(l%6Hc{k8=wCP{z z(KclJOLcY=g{66Lv=yd6WpbTdXh_)fT0W#=m4l-^9DFLyF}kmjyz zm6l~9t~AbuoUln8uZkpIk7Jec7+*S#H<$Ijj7-L_5#ifC!75U zXR0+S^oVY|A2jYXCmYkyOQt~rJ)Xw0BvoHyy%U^y@>b9alQ&$k=*Nkyan~OD9BqRX z3PcTPc++Ip@qu18Ds&k=e-v4aY1FpvKFiD(sM(=Ej+{7AE^`MwS#kIH-blz}rEd5W z2l;aHKK5qv!DwvsE>bFnJV-~RmqC?ptV)j95Q{m$r7C{r1aXLCmiBGS19r%#jR3ou z48xW$)58!56>^KyA#o@-g<%piHSRGqjBY?i*oKhdW;IVXN79yq6pKLQ@Vba=%RBJK zo=6nOZbqj{Kw%o;DJ^6*1Oo!v$rlf7E+Hb>1v!yoJLI*VdWLgifOLtzvx5f=YpPGI zNfWe_Fqrt1?=$5s^#$!6IVLIYgJhP~-4SD_vv^hnRB%x_rnF2ns->#dt~WHONtst_ z$=cxJEk8J`GD+k|hlHfM)pC`bbgXAPUX$Wtf|kikoyg)5QMB|6Yknsuu{sQx7SGI~ z5S8+7m}v%LD|l;;Y+OBi{IWh-5pyrp*?RwgDK8g%!YXCLb73E>l6P9pZWe}br|e>HA){m=mO)E~A0z7Lyn6B-oAyG%Tsz}L z5kFr$!~V%;b8Aw~6iZ}jf#Osd@w&_xyK^eO1}J%Hikkfemoaj3KV=M`dMH#`RT(Mf zu)4CDJ5(J_rZA`-Hz`!+Fe&c(RDCRlo_-b)1&1@A-7bE7-5f}9rj*tt) zEz(k5GoOu(lT(Jp;3v8|?d)g+X`zVonYWkrl)}EC&puhNYCp=iBOJb%SUl9 zJ4Ns7m5Jc$Z;*rXnrN9IP@f&ijVuT)1impD6hjhdn9VlB{fv~EZm?J2acCv!zCy19 zC)E||*`vb#8j(hcIo`-JH=OJV@hg@y-Zo89=k$nM0$8?%u0cvx&U)F?YD&%qlT0)y z$Ern`9RvrTieFy*oAX?dNSh|UN^8RfRE!=0%E|1DP#{IU>UT zS?hiRs&X|6NQ3^w|OIlj7mBoB>FAX>#CiRARw4z$$@UG2!0KMj1>(eJFj zD7MM&AP8cKm1)pQyEQ_8&KOvX^rCX^!;}i`%m_$zRCpV#)yHrab2Bu;#6*V(gN!%t zeJn;qzEvBm&qqQb6#Sg5A74PMRm?d`eU{h?x8H3JJApROn1290I(P>e{k~4y=<#`Z@;Gr!$rWoQEYn`!D{| z_N>N6u=N+_-Nthu7Q2LlVDNrx+L?i)*mB~}i^2FKuxi4n%gQY?r~>F|pvcO1`Qk7P zG#;2i>g&}MIBVQoP1{2ytArk@l*~E%J(s{ieq&o3T?pjMO}whj*T#nA_ukNOH>_CLQ1(3Za@T*%ivQJ%rb zTFGr>dm7U338|$xI0wxQKzQ6?0*b2gqf|LvPVPiUk{8Jpk*3EgxP-H?UK~EU)rO%JRt@=V z@X0%fVy}rr$OLXyu{crp^&nkLa)Omj^m)ICFBR&KMzo#1$MKL#EG>!b&reyM{qkhB zimi%JdG>YDhtlE1#Yu(`XwA^PM$ey1xzOo!6fR@eMIDJ@t!^hKbuOJ1TE@9i)z6Yo$Volrc9yY=(8Zb`EfFf^Jw z@5@m)kkgq6D8LyXQ4C-QZLoPq2iA{+Zwuy;UJ8Zj_LH^NNGGl<@g7iG=4K0}4c?*g zCB7tHoqDxS3U`jrb4$(%v^*kzRY7T{&iqCzt4E%I`ibd?i@QynT4CFE<63m{_V7Wp z*x>3;^IRuMb{9~OTI5gdQ=CmzSiV)?0)B=5avXAF&v9g@ zSv;RAP$3VC0oPD2zR3t`3uX74;_NqncY{%(z5YV&Z#JGPX6pc-kc|yLgWSMc5)p6h zSRMMrK0PaLJ6Jpd3;mi9>Mn(Pa3Jd-`irtI@e*WnOnZ29+5d<{*n-XcqW2ZZlZ0anIE!@%1Piy{CCVXEChtjeq%>Pbe4QPq0g94{?ho_h+3{9Kk% zj={uBL~Soec-qWj^CdzUMZ&AT@EvMd<#X21Sd=NQnyKD?J?wd=n?oB~C94>ET}P?D zNdQ+_t19o45=|*kE5&uLn&kS`a3FPhZaXaOTQitb7%HzJ5Koi*vt*4b-<53Ru9IP$ zr-_?uaW0>kuREONo`Ddynv+P9tUP;7COInHsUJ1jnOQKUr{&9ody)>7GAQ)&!JE#< zhLT~^N58xsb6QcuJ3a@NIAoPoxS!-j#)b^~U1-P(oXQirNhqRfq8LN<$0ZfH;9AYM zGl?QGiY%63Fv@*)IO?J^Gtc!iE^_u)(RI6t9=syc+2{E;$?tP}qhP}{`ERa0g~upn z@>v8^_-OY2oOxFnxF8J4^^K@MRQId|IE(fwE3U6a%NbP&^;)g5#DP3%4(ano3&rIZ zxyV^k>4sJ-BLJ98w`3R{aJH!B(#&PZy1)|B(#$6s?Cpnv*vPvs?T%T43P1`{ZK_LY;tbtd~a}5T^iU}_g zxrAKinB^-|iZAtR$g1%0&hss9n6nrJ)o!=Q+W|pIjO1+r}2`%x*e?0S%HQL04ZW4qZCPOnZnHBRrk?K5wx zT~ye_W!W0IMMI*JVzDP@U}oUqkM?x#j*#+jW?IILU}VN98^KVfYe0#VrJPY8?to{%C>!>N9OR3aDL zqgL3PDJQEO7z?H30opZc8kS{{baDm!p!AE^Q2VN~T6>r-quQst&p9!ABFIQYm6enwNCb}WE^h|pPer5`5*ol8i)Hx)WHq36Hb9*Z zYa~ox0*))LO}a(o+L5l{-t3Ost0^1v1WRJ1GtExTX}t#~EUEfI#&FNnyzTsHU|E-q zNVZzkXnXvU=LyA2@CY^Di*_03YN^U9D#Z)zl%V`f@a7StqZ>Ssb>>y(XYwpZV2*Xw z?R?sDCjF}HxSA^|51|U=V#|8ajV(ueu6HIa65Rtqb-jjA(m7bMn*m1fltN7l**S*r z9%7WBo|o?u$GSYmZ1)#7l!ga9+3>iZu>S6RL=Mw4q0;y3WK?fNp6>IP#T6j|8 zmg!iw*a87MTiM ziYHFI9a1{$vX>&hO?|iI<_Sd)?oEx}g^o5{(OMP#B&LtEpde@S=y~{Al&i|NFAnwe z02wN(5N#liiEIiEhOq2Td9hT|235PUE;CvN`Rlymf$~`#WZ~r!OKD;_Nzw~h%DJXd zG!%T5z2Aq!fyX9gMzupnS3Ij%3~;Zm-=>y+6Vq8@6pj%L9)J^=MdmYN42|+aaO20s@p=34lnWb+X*P3N^#5ryOo>hF*+LP2}UGLePSrW!H|shVl`x6f(AG?aWi&0^dcC+;yLOzXr`UZF0^NoAn?G0z{$wyor zm%*;NTzKIkp%%uwu?W-cM_ue1vdNbb_%~clDxGQ3F7~P5`#QDrhQ4=GoVJO)0Y}ND zrE9R*WdE&7edlqDMAOZCeVa4pA{2=rsg%_(foTe*`h*hNf&h#mh%i(N7)m#G7sVRk^gc4=uj|vKKj0^5L2@}5xtNP=HRp$* z{b5Y>$~)H}+r@|@Y=a16;ISq1tP4!6w<|XZUWfwNFsPb;y$a*WD5reuy28M|fI5-# zX&GJP&0Ijj2<||qqGzCfw+&6Sshx z0Tp2U{PiZ1{kOP?+2^(WD-q5)aJuU|z7Xa&B+zTcjgY}fp>?tHGHxHHz5Od0Q3qhI z&+wb0ui%~)aw47HQ@TJd@0HEVeD@~Eqwl;SFKs{50$04Ndt^n|PmQ%F1v>n&Qd=Mk z$v{A(lG?rpmEp?pf46EU5fI%Me!A*=CtuOtF;?vyX{m~1Ud839xz5<%i1BVDJRFfN zoPUwI+2Ge-o1ln%U@cyyz#@F>6 z2M~v_8WCL%ka-oSsiL+|43+gM9eXXF|N4&5A!ZKwp9IVP6|W}f_aW?-sk zWJ&cA*|9g$b2PKD7SVGwBBT`I`rzDgFn+uk7#TVKLf-vp@%x}JR@P=>_Ik#~mPUkf z_BO^w4h|m&>RA%9e(3P@jU4p|Sw2oEV`KR5&c(v?e;A+lCo1)uAM&sGJdQuaxPQUO z{Ek-rhem&}R{w1DCvx?>5f9G?yUxwli13f)@4vw32}vs|sVe`M_&kok&^q*gQTu(dY%ClM|3+B(bKig8!r!0J88%qu6Y; zBn_pX<>iuvYf_T71rQ|;JWX|qq*DzN{EIuG!$7H< zfw{*m``4>y*8q@mj6$@5D2wj+bjR3ss^H!-Wy{bJ z;Y{>wV5KI-1ZLd-#^?PvKJWimd>+T&grnb6$iI!hf5gpY2^s&B@%J%_y8UkqK!q>j zsPee)Q*6kAp@KoKp)Sx+NmP}Ux$DkO>Pc3bN%Q%bCOho~4a^G}Ypg>FVA}aSP6+u1 zj+e7}87cX_l~OB&WrUDCPN%O^m*pXu90)?Kv4_jIf*o6N7)Z;v!NzdrFcB^l`wodcR%5PuNG83Pfd z=HuT~p*R1jZ^QggBV&9VFgCeB2F)YkwIu_Lf;uMeb{~Moo&~`WU-}t?Q5sO(o3Xf zNj8MU~H!WivZ-Dy1oW_{@Yi_ z^gxBd&@i=7`!eK#x?KPkBd$~#TxV;|PQ+ft0osmgK0T2x&e=zX{~btW!K>n3!U>23 zzf@*%{eRqX|Ji)~?&u$m?tgZRzbUK#3c~x-d;T60f3F>!|45wr>-%rf^v6d0zg{jr zKzLeOOKTq>JeMagT@_nJM?*6`u3&we+Y-_!gCe{_HC`EJ#7^ZIjJFZ*TZKJ$@p zX6-u7PfjQ_-I9c7OtZbYCP(Wte84fG_|kk7j@I^QusA_oqV@&wxbtnh3v0(cwMI3*}Pj`LA>^@E%DKH z>$xlI*+JNYfnqEPi0&uwFbj=D1zHFVqYR59MFeF`5P>v<6myIXr_c~DAhstaf^IdS znjr6qh`qyERlanBY72aegiYWznIZ=sTeqd1B#9EWug2apV0r!YYrX9jhLtohV`!VDCAT5FB_=wS= z!;x9$-=w=7e*j(Z#Ru=skh?8iOSqbBCGKJj?(nlcN?Y2dkTqFL+{PH5?g;mowxJkp zbkL1|PsWfMx&uO64v#oK_`Cn6)HMl0>{p>@qT2U?L;2Y}@PQcLW9x4Yv)c$~YULqg zB!(1kL1U0%vD$|0&#(h`a)~?=Pw^w-iI<=@_`ZBUX})nh-$~qFD&|LfTF`UcJhGaiHp572&s-pgAg zwe&mTITV8U@8loz#86Cp%oxR?)ZIPl3+i#g%oqmZJ2VRg(F2rccG=JFV~cOBFWfJ| znIH(>V#Bg9S>99n!=oI}sdAE>;|X_V6;yzTJY?!3rql&gB?)CE;U*=q$3>uYW`o59 z#$lh(v~gCn64VKa+^|Kk`=X?EQ)H*!&NOL7Q)-!lGe_!aKCAl zIvbmu4Vs$iCakQ}mZdcnRcS;@sxmc|l=K-Y8Vb0uhsTEQyja%{N*QCOvldI#MM885 zlCIJ5neHyaH8hu3a8jMu!^2wW&fop=Z&*ZaRzH;oGcN>c(|#oo$%<3(O{D2gQRq$V zHmUP>w zyIO0Scx90Qs-zabY;h50Im|nNv1P9l`pSD|B3i)Yms&?Nw25qW#&e*Cg{1w@>)8m1}^wBK6 zJN5H1;|KkYv|~tuImqnmTe`qTZjh~ynOP-3_4B8CFpxbft1L|CII?I+B>(qnhLs8Z z?8uQ+VOnEN9%Ckt8XQ{9o9dgWF81pBpca7L(Xp?|Pzwd^oj@neq=!cet@hAri|42| zgbQRdDPERd9z0!OcPitB*f;;!?ivhheO6{+O%smOYlMtVR#PiE0ix_5OIKO?=!?rC zGEI8(9W2Q-xRoKDv!drAsRnAG>gw0c(_V$P`>Wz{6Ll4_sBv`5(X~bBnfp})=UUCg znd=v7;6ELLDi-3<(c61HwXdg-v?rykg*h%Tl_2PCb5miiuRO{Q!uFa6>|^?u#yFqp zjsbG5*t-MTicm=ar6Z|GH%ov-#mY88UA!P<1ed7?)N4IXT*zANVg(5aSn5_b5?E7=SRyflvk3NW zu8m$3v4;d$V2IH4<8GFe>gzPN^&3`KEOc#d9R>4|PF@*K>oueQ+}OOfw$_}ba_3%_ z;+lrkdt-@&NoYKdo_6)E2;y7a#rQeCNgZqwzBi_O@I60cf3BJ+sH4p*RQWm@Oa~Gnl*RtN*lDt&NlR+#J>(rRs*}0&6_5UDm5s zAY^{Bfkv^RgcfbDWI61P%4^ak#29pusg)JT*dPP5V#xO-H`Hrf4L?OATv%I^;Ns*d{k1Bom>9Emrw~Dg|3674P2vp5l&vpLwgq(N_`z(8}CE`?Hix+CHZ{_#>Xx26P zVWl#)nKJE!kD&PTvS}SPr$|Usb}?V-8)FYP%eC3vq+D|UfKp|oaA{Hl_lob9+ZQp% zecS8IclRNa9?u`5~}lVX!>D(wsD5vSTyCkn~LZC+=Dfx4|0x|gXS^r zSG;w9mvPlU+ZzkJRqE#=iakx%Sige`>h3fp<%dfopH%7q9rA&+y#B2!bPBxR~-64-|f6v!++&Z?z57uFr7(J z=ov{*FO|D3qtf`2C$+PAPB$hUFNw;eQy%*&X}*~!(=h*4Va;>eFh}N-v@^&^cKo@l z7x|KxM{?oyM!@E)QI;}R{gehPg);T^q%@<+A$JM8#iK^qw4RLpINIkd>W(^_%VyFT z<)V7`_)L72WRpse;;^g0TUEa+-2ohe3Y^Evw8=t9|zFEv00>Z z5VZ-X3zm;%m^Nt3mTZHoL?Gt81G(T_%36M0>imKV&Z-$kDy*x0N^sl{=aQ0?PZjX9 zgb!NElab|=+LV+N>oWORGV<#vNdET+#<=$cc&z?pVn4kZj!x%<3lM>XuV23_gB};v zO;5BpttEoswH7X(f;(UcnxI=*vYe5YIN3m9ik2yxPk7K@X?b379-*1+G!mM0pG<(E zFmr4f)KZjBGP|o*({&$AgrGkJ_q0_Rm>OjXlazg#ZmwXeXEwHU*L`V+fEbq{PfyU? zf6!Pmmnt{2q$Oh?GgENleSW#(9{!B3xzIT+G>5Q3AuEwT55|;rDae2Mc%}^8wT*fd zPE6$o(rX>hWTk_y_Emh=qb<2|QlNdfx0=N~jZdE0NIkWA4HzF6f1BQ)c_5d|Uf}@6Is@)7 z|4@|{FT0h)v|h(op+&7UMgo+u7Mar4bK|wJV9gc7y$<+%JYF{^gEcSO@RI~dlFVVL zPcPEL6yKmy3Fajz+4vFF6FclurYNOCzkoo^dbq%hS*0UBsM#H2% zOevDta>33}I^cyhHy*gpW&0#8mzs~qU)sM{v0q~Zs$&1eK3V(zs&qUzer#7bzO>GS zti*6*$=rhtrvf*P^A5Nt&L;{L+0S?nPb6_UpR&c4{q9BFEwKXQ1KK9Z-=bilq$tuu zlP@|KM)4ckrWqa%!dzdlNX`*mr08w&MQ>x+`^vSV#zZeZ`jfq${GkY(Sq=P0>|Yw*qW^%;6dW6x{n-1WV#909dKg8^2m z^z1Kw>!?-cwQt~C)f~-}j4`O_7@u-oWa-S1mj$QnGYM!d-FMm3-`3jHhv%>EO{}?S zY?VnZswNqkXR_MyE9vQRm$DL*(Av$XQGt>Djb=hnxHS%iSZ_awGr2wVhI*)u zRhtSffm$#(@ejell=U?N+9yw9PwNkUqVlYfQd%{H52`mq3Uz$au4p9NwpepF0tC## zPw=)2y?h0b@U^Sk@NETuLccf^KknL320mG)u1@rkH=2;NGg@DIY@yYt>!N9}9ed=R z(xhG*bHo3Vt>{p0XeRM4-NQ*#QB6tJQ#+Vc{THLH%W=7rGv!L7{p@Z6yF_)i=YLT4 z&cT(mZ@+JB+qP}n<^&Vl$;9SLGO=yj_KK~Ejfw3^GAGaT{_1^q?R~1wKI^aUUVS&J z?pn3FKi}(f0VAGtR1Hi&yN`w!XB?R4%F-;@x~9RpF2injsU6(&M&3V*=3b=-X6y*u^4i)rgge{uFAQ$n?PSrD|9YHb zS(0S%E9&okz+m3dXA$$I4# zQxl(9petZBs+;*GOwfxx#630_?lAestc-Fq)dc#&MXE-$p=A>uecQ!O=V_!oz75p1 z;RT&U|s$&2|kkhar+55M|v1yf>8jraR8X)30 zat0*?-)$H;zdfWhC)&#r*v;yD`G$*Ua!#5Uog+4=gaGd{NQOb#;jr$aeNY3qFQkG8 zavl1NoAI~pq{$pA_Bw#1?Vr;vinxYkwbLxu2kgosSn!j;9_}gkhONS%f2!@4moFjV z@$VV%BE^a{{)DN>dN<4-W^Awj;@eWMf4Pgj;1yFU{4b-~DWmO-JhKySx2Eg*v4)qm z++_HgP|vc(%(Sd~*3nZkg@KxdTGY;w!YnG52E6UJMow6Zp6zU#AH`XR7FoJ!hg>BV zUD?*WVreJT=RoPr9|{(G^1X z&U0Kp1>St?Id~TQ#!CinuS%&p)R?#}0Z;2wzcfB|UzofV?ewes z+Ve|Y1cQZG+s4aM*Rzc1VL!OY<@Ea6d>fq^mE`uhq@HIfg#B`(>XMS~Q&>NjP`Tl& z07 zvA>;1JXnMD*}Qbx5p}`beilufK}5wL-))36?}rKiR{oOc5E5nXM_InbYN40ebZDWQ zxHRTV2#sTj;xL*i4;T(5tKf5EUHO1&b({^iiPZ7fGCaq6f$ z@_WJrB65wM(^?{3oYHlk-@wd$PYow%kJ!X5T#noUqxFRCxucV+yzb>iHl_9t^SC%_ zvtJN7l#*T+dQKKBD#Z2kH;K?(E0!&}{BE;@sei6}9cuEID6J49mDFugHA^_H=(G*z z3tcmtDJN^MnC%$d%loZuYfqiZv|HG1cVK?=8ds!1?9T#&wK61AGBoyzZc@y1U#!4$ zQSWwbml=4PR#QyW@xT7_UVxUcq7ogo!pS{%f0cw(mW0zhDhpzUXu?&F?&?nkyr_`+ zbcQSg+|)hOoncz56*3_ov$Zg*_VQ@s*1GT~Pp`gOH2{gg;Em~$225cTKuU->I@iYD zgo#rteoQo=g&|q+wZA<8IM-+nF!&H#WFEP`S8`jacNZ>Il}u&}xt~$y=2yJxo-eDJ zwyvbw%+tEd7Yl^7NWWgvUsy#XD%Ed^RzzsbLtOl$_Y$Y{uVg5jV5`LH_w>=N!z!no z@at}y0}m*+6Mkk@RnA7yV30!;R7FI_t9r&OOX<)zM>^TA&SHl_JLsg3KQ@Ta)5RT)OQ6uu;k`_`QxYeUQw&B0@otmdW?$g_oOp}B=pJ=AcwN^JEjim>$ zAl&N3=SCa?83KR3|G{TJx_nuJ_ThJ~iL`&@c|O$LDYiIcF`D=|#>m~_Kc}8=;l%Hp zK>t_ob<|d!uDY(8a8dhRu<3giNSXYX-mCi#a?t=Qz#!jBRlOj*hWktJRr$?V^kDxy z6{|EkPgBc7$(8EMwt9>?965s#GM)e##}KO_tya%P-_|fk+xDWCBuEujWK=3#Gw7)N z*nUXm7$rDuBJ*Ie>blO|rcs^FuQ*B{^_wYzlL7qK>wy~jc=+1w{VELiIJm}D85?!V zP@I&TMrnzSbD~BQQv!4;axre<=ERmzWa#15?_?m`ZAN~WOf)%**O_2I8^qNDaml0y zy!E}ttt*R@*IxQxlZPyz-5#=v_=uIx3~cpk^pmxm?nd?DdSzKU59Kfbf&1!AkD z)#QL)sRxT{yy~Bf*7XHH9hah`52Wo&+-xjb`e(HlUJi~!A2X8$9Hsmly*JC7PL8?> z+~HT`?LRY(jEi=fw~YwDPsboHHl2hI?xWxKEWvgNp14BxoJMZ4JE1WI)s(()5ya#r>>;x$1IQ)WPY<0AvDEhN ze0U&jXGmNu{kcFHN4X9Rg0{R+2ahAnX)-0m@o9H8!iUDOD~o9YUZ7Xnb5V}^@e>uaoSUL&0nYH*m8z`u}$&BnXqi#f;pR$x}u+4 zEc@gPnc<+AC|uHL_AU;aw$nt|`U4&P){l^y-1`}ylPV*2rI;D=K2O7SQ%P%_Lg zf9x6G*^-oscAVn|g+^*jD8 zzOfbI-3$VK`sk^b|FM93gUM*i9rk_K1X&0{k|uKBy7wJeE8>2PwvEQkO@=N6F$`|<%C0$T|(dnpbf>*B$1otK^k}t zSV5^H`wZlX@`Swg0bZj>f9bLe2c-z4x&fY`w|do2UJ9@HKv#ez>MRKoX|9w&*bC>r zED&Ai_yF*|;ErS; z6wf{BcnILTNiQ_YGx?SHX7mf>KGD>tD{u=y2>8dHPgYy&bz&C#D~XBleEr3~A9$;EcPk22@57mU^ezrvdBI4_*y#$8knAq2Ct+ zLIM~8(}4RgX%_yMpa=0w)B_6i0{8eY847SDm}_1>LiLh zsyvDxz)%9>ZXA0j2?^0c0MtAx&(O57m3R5`h8ONMM@q6{4vI(MTst+L=2AETWVE&?Hz3VN?M$B8TL6 zD54S|3DIMsFQ{t(1_`Rch#N8iR9nbqO7Oi{oi!NcIGssQ>vA{JU90#K1yKs}Y#3-V zSYzo`6s=H5;}JXs9dR-`bQGyj&;scbly9L>1ybcGat!K0@kMIk@njS*L<6KW!GL^p zfHM$hpC8x;PzN}o1W5ZbYRUJZT?70hCzw(4$c4mxqj(};AZ}SrFm6%z|9cu4`vpYn zY*whgX#;Nokl_d)@cXlNT(L7iUOJXO=sPcsWHI>Lxy;XW~8#q9=Mcz?w`LI6l z_B9zUkabp7f%JeKQ{%oN-+$+n*ndr_`wy&Wf1+D_yZ5g-)zE86mWpS!MmlxFq4j{# z`nIC8ngpOmi6i$9;{osluEt4T4;2>aJecY{7y^la4%JrJWWhKCHba0MfONx&Gzv0# zI4UwJ(a&__&a%Fr>6RcwBAdjlZDJ?A057iHZGacjE;j1DK))br6UYlMRR@03ML&gy zaUwtKm1X)J62ew2t)uv66t08lCIRbg7@OnZ1vi<4h<==6Cz85hG;N)zJ|SzHXzykE z9UU+QPynbv-}lF3{Q+7FNXG(Yic9YVO_Nk;0!fonfCm*GXeTzEAT~~v56y{xDDD+{ zL^m)!W1YTODiiTXyrURHKYOh}jYo}V8B>av79|4p!ZE`+B#nm_^@qI!8T%l44%&pj zgOB$S@kesu9z%-n(x_5%gzi8*)QZ;=ae(T8{rVlk7paBrKsx+(RJmj;QVX?)^yTzR zHYAV@#Z5HCkTp862RHEpj`5v>>KO6~qK07ixs4kZZtDiUq|>H%~RO8I#_a#;eB1i3maPg5H68 zUMrJa2X-UgVU1;xI0n9>cHi)g*^N-cNIZg%0-(@JHs%)e$fUTixQd)- zr0vA)BoN4KP&ut4aA81IW6H%8M)kPJ6#x=INF95AZ+D_!+u`Za=^^PcR+7ymnP0*z zMSv7gK?1yxNHs!6y4V=p0H7fOM~1s6!Gj_T!#^1QY$T}@%Ae2tGsqYEj&Y1O-m!l+ z0Qwd0kUpMSv=`)+K;Rj7tc>J3=pFH}j$~By6YS11-eVvnLevn#3-qv!WH#g->Oaz~ zFXtDB48|er&6#1mAW4^~d(bASwzzPy;7^V~Xq!XkQs}rshr4xK2{y^r9 z5{d5#=B*%eX6*ysuby22gN%#5pk2^~DO z7>aEdZw!BT)>a?;jMxyHug%&1cYHok;YOb(9cy4eHvY=MP@`OP~Sa=Q<4$&iY9o)XaYskKUH)yS3E#DE5BjQ_l zmUt6bOhM`1$lRtBANw3i4K<}wnWdibk8%BgyN1K0ao@iC;-s!s z(MMTqYJ();`CiBnvQOm)-XEktN?jVvhBuj?q4u!)ea=}4lk9LKhBzElUDZ*Jr6UH9^LlveR}#~8o|dkPNJ!cv^xF&hfE`+q?F z^%nLGWH3a|L=3sX65T_uh29G>K$QU#e*gHgUxDZfud>5Dcx#=J=+}eLe?YT; zBCGzlBg=a?BKCO_J6bX|Lny@!uoGGpX4jd&io(y*1zYFwdeTy>OTjNwdW*Z{a4qe_V12gB?hMI z=58cW`wev9gkx%&|%j-tO+hpcJtW4PSZWs%J*7;z<}fwZw#+{(tdt+ z#I3hoFIuW-%jP+33+j7&)RLsP*5rQw*j#<0mU&$8T4b{j%~4NfxvlC-jk{yq)F?v6%x+U7r5s=E2i!h*^4huScmqUuDrC1u@o7wq{^I2fwx#*zCuO(^bD;lir;rO=kBYvdHZ_$o-`O#|wnR<$% zD#_ZJ^S+bCLw}PPfqKSCV$S)bxXZn~BjkH{<4cEkXH3!ZmWi)nXsz)fk+sEMB@ahV z1A3{l$5fSEB7otSjeD$lV#b%~?X0di+F5fd6`$-bE!s&a2?s~Ix9rZWvT@`|bRT^D zBmYd1z62oX|3`d#BUzNlXa7vnkloX?*wdYVqX)|ZkdC6Ci|{-=rXJYFB{r1 zU28puk?8AX-yMFs9E9JmaP)q54w-EST#(-|h{W`9I+Z1FPc|wRet&gWyZo zOs>*}BjbaP_A4!_`N&bhod{1S@2Cxyn-_Z@kg`jin`5=b4G8YM9a}xJ1MDWZozQT_ zsjKYAyQZ7#huY0pg}|JA--wDYd4!HeNX7HqsUIdR$8e`Fc6&?FVfrQuK;jpr5S`h5 z5MGHQY`)FhwDV51@`tl1#nS|)`x(mrF;KUk^q!R@4^EquG?Dv*i*luL>kzCklXsx< zcm&If?`qj@QC0bli#yE|E00Mxi(I5JGx)tk4vyL^wci*ewq+gp7vUr)yJ zA9&)!w}~k=Wyy-1Olq>l6+^T#?*aWMfss=T@r^s&k%+-lv!pHyt2zS0gN#2hBt$zD zETTHv{icLNXrZ(}5p63DG+O)Q2zaPfG->sJa>#on=GkD`6JPB_#f#H%iVMprZUq9W zpKaBUaQVpLCiPOuRTenA{261gTvj^H14|2*W%UFqjmTn2Ls$-y;G=(=x}uIt(wt5) zhg8V&OR-eSZ01vYHE=Uob6n53GS(Teuj=@xOZGW??d$|tTI0OR&s>EgPBy69cE*+n z1nvp&r*h`V%}H(b2q|F~jqFv5OEyS+!|b4egkd@_#M22japwxsQ69vM*6A652ylm* zO_GLQzPEAY`hvWT1FB{8e-g*2;LW>xJbtfU;eI2gf#@KwE%+^^ePJ$|8haeM)iG(< zEfVD1dSXTjkH(CUaw$<9C=XFSx5%e&FjFU3LyW1N>>q7&Q#r%%_{35a8(_UI zo{o}O)b;DA*+%e3;Bh3-h85Ul6S2jKKHRZFwEWh+$G$U(-H z^XHxspIViAgBS=`JZxA6p>^-ug4KK^3kH|n9teY8nqObP3*j3amuHiss~g%YP2JsD z1^svshrCOT4>cvw1O}Yejm0u&v>T9)BLCo`_$I!A@MmbOJUg9XVw^;~Pdq1NJ7#F+?=!vI z&LCbsk4BaK_HSFBI_m>S(A6tMMmUV=WP~_)Vk9*n5N4z&I4obYpelCHX`w!3bZ>GH zwfRRyx-D6j3TmpyG&eXk`Cf%aI;E4fU>>O==jfP81OIZa;@u)y}8q{+>_E$TH z;VSGLj2|K0k)f(>zkQk1H6+$rm;_6Qa&k2e<{*uNCe#7d07h3x!SJSY*e`cS8)&A3 zrQrtA$P8IzxgLWA_Ukb$EHwe9XP|n%x{NSlfThImE7w!!iy`l4{Xc3?ig8N3cj=ci zT&IbaDrr|`2a-$YTXV=YOKtb@>f~)V-DH0$i#_G)YHcPhG}bCXTC6sI#!9*SzI`cvKYnxnwqq( z{|)*o1dV~aYc_%8XOy{12&>3hd~L$Fq2E^Zb-|WUMd_@+{j}!*40?u%{ZyZ%j2o0l z^)ePVZsZ`bjR5iWXYWUzl-uH>)`h8JxwUunr|W(aXwwJZjcQ^5;JuE~uUkV}_+( zyX^)Zk!gDG^$%+j8IG0I@6yF*b&ELM`Lq3L#4nlKn3(8EV}2Zw&(x@Uabc$1z`Zxi zmt7-T0$ie(={=c_0hR)#?Y`BLSb`SE^72#i&m8Obgb-@=R1=@kpvQ5P&eVz)Ufdmn z8nx%UsYoz1pV$gAiwKZ^L?JtE%Liez=#7Kati%!yKco$*QQJITMfSP4(E6~lK~HNz zH$l4}6rCaK5A^yqww-i6oP+J+_FbX1)w!M9l$8y{1<6~qWD6PW+%L{+XE`3x&2T#8 z%P=u)jw|idM$MgN*?i#g@WE#Ll^P~9l%eswWOZgg11u41ZD&^(&Y&eQlR1?WPdioi20(W96NX4? zlcR?H(R(5lE%&3&VYQ3+mDoPlGxc0FjKpsWP*KucS~I5h$$qa-B2%eHq;}0JFL{fN zVPk_TWrF=3zs9T)P0p7bg4>%@p&;t=)7zzzd#j?FPR&#VT8>&Bb%ElLHQ~Oj{AC6? z5t_X@5XNhzaXuy0oQL8Y1|)55#xhs|T<)wQB$aO5Z}uUqXoy37{_BqQ*5<2Zc1;LM z&#AAs(M*|HO$jg>S*8d!pl@N5jL?u0>kGL^|Mv`8mj@=`5>$B z1U#(Gw3Y*b!P@W3$X6|LqR3kQ?b&Hhd3}3)d}$9C-nOPQH&EdhM}{+_?IljQHBH&F z$+1voC~N%IAWBIQQ$==?>s~-Ux-Z z156HSJwPzk8T#43-RvD#Sz0B4$R*_UP%&B<2uVj{;GHnMR>u4@wAqtrG6Bn#A*Xqj zYp9fsS(U66lyij^6 zg<8R=A~xnwTwzFzzyj?zIclC)7(1xBA0y+lJ%gq_Jb-Q#H_goV=OceBN6k*MQLFZe zo8SRyLL%mGPd@IUiPFn$E9p9Mg-b;;-Dx20!UeJ)rs_@jcaa5FXhxi=)+$c>13bU$ z1lrEM9DqAiCpgEpGbBN%_kvy`i6}H}*1bO=F`|Z_gX|4gp?0%UAo>@ zQKRL?!Ja-Xn2I?&*Nod=-`bq9V%$wL81Zo+eH}yyQDq{ajw;rLl;w^ z5MYVL=NExenFz^k=~uM3ktuFye%>4-1OWR${7lmC>sEct6iVwZ8EnNIeO;E zKXmaVx8sumyeEc~1xj#ZfQM9kmN1$5`7w&$NM$B(eDC<~HX{F8dccuf{WpbrcDb1n z6%tClvpN9(RKjBt_X5#iY|j7@yc*uTCKw|_Deu+n2#z1Z<<5Yx^d&(NzzlzAs21&E zr5jg{wY~zOVIe4;p23?X5H7$&%!G-^ai*lm$ggkdzBMm9IYb)&#Nm5HH}CC?tH)3u zD}etih{XkNU+PT*EDvG;A1^%nFB9IvYb)3j8^5^^1 zs|3=H21iO(^8Ij!w%_m)_9xrOXe|&`Vp2)U7(r-W(%jonIX$tK3|tDihY{Vm4H1U| zI_4{@fvXKaUlt76i?{{AG^4#}V0v`I1a?-FY>$zjzDnl|nUebAw=pZ1e-W_S=(V;W zU4*OCvy%#<14_@^)AMi!J*+y6{rOrH4GFGrK54eH1sO`p(rddS*2E=hPHORm-NL%J z4|BpC^UmI7piAIr@tUf6>`0PnWH8r7Lf{Eczv-__i=qx+3wqJ;nw&Ydy=>Q9Mr1?$ zXnmUxhc}|Fq}s#DOIaJZ;j(2V!fZ4nENW(3Nl#OFXd`Cjz{a|2XWd}5k4PqF*nb{9 z{!TJ+$9e)KvXfS`#`&FRFdE%JpiPJ`ZMBLL@SK&)1rdZycecbG>{oK@3QbPzio)Q^0JDv3HBJ2!G(|( zLXK*LE1#V#(16TIf&C@Je;K_6TG{TIxX|tF$fAzc>M4-SXPO%RBJ0lCGA^$9y{hx< zRy_=hAC?$XUbuomxig!81EzB2~PpEUv{pw5_xe2E~S#1Ul!_}`LJd-vk!K} zT6m8T>$x|qD`u}!-_;AIlzlXrf7U(Q0*mZfSQJ_fmobDlwsc~QK|d$nJQg^wlqxn6 z9=ROl7Y%mY9U5RyM&Wl7e@B?Yj2vbQ|DK&wmu1<4o!t-rL9-MBL`CAtuMLdc+nt=5 zeq6PgG~xkMF1^eH>f#K*Sf(91`QD;)z?OtMZi6j0^Y-o;Lg1jxgWj<8WR$Ikqr<}n zfvgJ`B#ynRjN@~23R;aK*!n8x+_&KOMfXrG2{3&&oF0NQ*4b0nxyZV`?q!^SfkZOp zA^&)Bi|B5VEFSH82=ceOT}8xj2to?!KRmmM4ZJoP zDMCDFk8ZEGxi;hKl?{?T$7)BxK9Et&kR*N?h6B?MqdQV>>03J2`ckO3s2_1~Eo@jg)=n%Az93WEO&#Co`6fvN|nRQ-&mU%{4glxoc9(IVy)0miXQV zyO;-4j{2CM5%ozP_*Vb~q*$Kh95`TSUT-xp0rSGahG2GKTgCpfGTT?n2T58g!0{Dc zvY;5}Zg7BUUwizWmo|U%iU}b<9_1_<%yhzCwWqnIHJ=r;M?H)=?U(Rku$xEeFemQt zVdOw2FiqhyJa^ByS7cnrso$8vIsQc(k2By%Q)hn1x!2*06R&vet$6KsN^<{_l5P6Z zdI=0gk}9AQv*;()GTvC{6;TYYF8fd+yHH$b=_$mMFg8n2sbCoZN&{GmZ)a&rE&}#B zi}vm?S&KuH3CkvL&q&gc;PLxIb}~W_5t<<#ge3acN=vRhqLVSILG)UfX|Ri#{93?{ zSDyN6OnIQ4k)3@uq!qzCG(YpYPE%?I(cjdF!qZ54P#FX|Ou!18pwM76HmGVs+Wtpj z_lm7^;rk2JHw>?!*AVqwTILxIjwDNtCH;r7m*NpiQ0vh`f_oe3NbE4t_T8Gl{&9Pk znZpptQH7x-C<#PmQVT!SI#TF{+u2qzzUz=AmoSt~;i%TV3bU{@u+9W>@#`@KWj9_Jhe|Hc!~d(ps$Dbx{#`fq_FF4jPQy@%SKk&JeU%Z6NhvCB`m-xNO7e*UTr z)tp!ze-SLO{vIz1eS3e7Y>^|9P*!-X{l-b$JK`#~AAT?DF2#C-G7DdIcZ9x6ge zt|#Kjb-m5&V&xT3pRnv#=#a1pxt~Qpc*Q}Z;U~_yiKz(g6;bPRH8Qu-rN)I$tT0`Y zSHUgM7Dc=efJErW{%UUrlzp$262V3EF;(v-DUGWfK_0JMK7_^2hEitJgo5HIdz1V^ zFlu4gPqUp+j8v~trz@7FBDX-3*!o{d^$`y*Z^1T)2-UZ7t8_|zzY}joGluqPDjPKY zZ;0Ohg8m}%cKmydAk)}e*8rGMIe%&$-oJ!LepRKROjKJ zp{pZvBP+y8Z(BDpLHK^1=JgLoOO|OP8EiCS|aSuZi3rmv5-B?7C-2_ zpL`AChym)1K-lRq_J(|g6`i40{`t74;P9h&Lt~1WYd6Nx#&G907xmU+)e^^uM(H~2 zU6|6H?u`J?hv7z5k{oZb*?|z=x1^@OY!2=M%BuBiwG85M_V`D)$I6i3KJIDdxQEjk zn^uTkWSC(YPf#YgLBDqujv!d6@C?L6OYZS+sPx5^F>DFQvv0^Nt{K+MGkrbXRvtFm z`Pp}EYb=E$sc0>&?R)MyL|C~d|JWt#Y{eqjfl%>A@5eNEoYxCKVXS4|uVUD!UGT4Q z=eMQasLolEFx{X*6c8-f!t3xGF+^TF7ULKqxe`_3Q|_dVsAZ4gDrWqypeSj0)YRNB ziC5v#)4?~8`DqT+5=>}O788Y+gTumwop;!kzWjR=R>$#Ga`6OtIdal4# zw#L+4_I*jnnU|DA*q5a792aF9{8Dya)qO>r{kk5NDP>=sQQ~h)<~=RsAMaIt%?}um zMr66G`bK#9*!1*^Y3dUB^cA6B9AI5|f6OQELdtrszT*@Ju}i@XL*hd}3@3{*(g3^C zGsD&o9L1>v1za;H_O~}DJa^U>=V%F}a7>RxHaj4H^cLxgQR_c|-CCe!?yt8{d)q6` zT}$~-7S0p7WU57^!Hppv>3aWZDjGUE0Kd}LUzs_Y_{j%S(d&NvJIGxUIi1x-83F}< zzl*%y=BUlu2XvzKl-~!~fZW67^0c%{970m~7+dsM^Y`-f>?%%TJaNsi_q8`+N6gDTbfUU zz=`0u%cs(fSRh39tAa_!mX;KpA&b@dLBu9kl(n4IMns;5x#$}o#*yokhBQ&BUN-euitnr~l>%F`t zl498O&pu1q{JchZ$5G~|QEso|4;$ap%6PUIh};Qi`JqEMVh>cSM+VDBGp*dA=a=ZV zF+K`Y7Kh@F)iSCif6cG0%9V8{NV?p&LsIL9b?7HHiD0Oyj0~^j9r`~;YAeAUEk{uV z;z(c~g80KtX>Y$6b`eZU)JMZWUPJYbS-(F(9K;8`~VIx zDWePTE8z$oY7va@mzS4G#|!sZ(pHj;Np(j7e7oVmHo}PoMCTB)-A*){yFFT0+_Cw4 zB-Y};Z`{E)zLPP2Nf~wBa?B}%!ZBe3aCO8;p0IstMgLGtsfs;RH?wSiFRD} z(N-6ATwRBREF=&M4*KnbmV%2bFt&YgtZqeF4$Hv`u%_CyM53y06*gQ6`r)OhNgJJ5 zLCd2uX&4wQv#TqT;1BVFPVHnC7wBiXk<3z>p4@)&=AaS=4`?LBBP1H_H4!vUc-=>; zx9S1c@T1ba(iK@%D?d67GWvA@VKEE^GV@DzsBkgdMXa4Vc|!hNs|Is(M(EcqY`IWo zVfZF^wD<<T0)*@;DKJww|3dx=&|+<(n;K05B`?(0p~*7A#7Zw} zq%WW~>SoeR;8nAs?})(-AgAxEUrsXTP1PhWA~{c3ibP)=N>?`X{se_HxR{D zgY?tr_y^9G;GSBjEBijWeZ?T6If^Duc}o~mqh@yB4@t@u1+k}M@^5W&KYRs^`|m_Z z`n;HBRCT-e>R%`7CAmUXMa?u(^@i>x=iij=( z-gcDfKL>&Qs|)uiBG86GB{%FkuX%SU7#7fodL!>4ZP$!A9dQ$j|f7n;bjt1|h_z=9+!FFmZVA30}> zj;3t#(R^*I5@xuvk$B2ryclQoHKW1YU0Ja{e67%7I10%_^({Kza|}mA#_T)xR#xUF zonCn<)e}xs6z=RcbjvMs4*mN9ly47Bf9#Y*Zi1<}Cc)fI&$Xy{rJOe5bKhPq1L@^_k2NmBOZQe#2=~MC z5^dv%-O%kz43)El-RfgUyrbYCL`E?^Z8j{cvk9jHvdgX%OPX!VtZk=dK>O)`Jbv*52;B}3T!KzF((Rqj@hVo!w*q+77iQ6+D8 zp#LFMxvKmSGu^cfA)_@UO8S&d01v&~{ASr^tvk!7j)zIt=I4 zm#$@`2;F3b-+1E?W%Yv(-53q^9Bz=-rG`2>py1MxII<%nI2)!~a)=9#oD^f92ycEX z<;1A0-RfIpIO$uE;MZXCcXRvT^hL#Is4Yv4-v^h&?LC8gBO;^Z!NI@ylQ0z6;jh(s z+ZOtbYN@Th{lQ1l;N||Tf}>f^0f2vODZ?t0SkRgY3_1Y&w3y?Bc@ghpL2kSGxRTS7 zU5k}Y9noFu2sTNi^)yd=M(*PUut@l_ME*+~tAW~zQhZ3Ly(gfugCK74OzSK*{`Y!V z&VdM<>AqGc5g2s~CZpB)(MDwiEO1nrPkjA=ou9ut`^?9b(;9RLzz!}LaNXId zI#clpwx!uDqrB;<+l02p6I0HG(Dd~G400m=sIZIVx;Y?b}7r=AMza?2anqBe+%VYZ92Z!OtL*>btj z446{r)Ud<8K!c0d<0*w8h7_W&vR~Lh z%qlrFKXdGJ-W2khHd@Mb7Me9`0FGZ>wMvEtu^!76=rl0iGwy1@ zWJ}GyF7GVRls0IFeQaIZ(8BB|J?&13`zIj(R`{77>zB|fq-r7I>M52o8^zP9sv62{ zjt<0yifKy-%HXDhScGx>WpHvTwdvoMm-C5-J>xXOr;1kNM8r}64J};r5r=|ftKn&a z1Nj1F^cC%~MXkl(9yl6{0nqk=w)cLq4B&mv`#T1!m| z#~A{OXa$E6jt~fB0 zI{cZa%Cb+Y@3?}@eG0w*OUL;fb`_LW0YM|TjrT}!`h5E_MFjUK%SPOXKFl|MEXF50 zlD|{KLS;=LS%4i#y|~D-((*Ii&O-(X+Wz-Sjp?}{Xtozf8!2o93v!xt>1!azX?X6r zWd8EQI?Z7236YU`!7|QRvWcom->e!*V=qFXP9eG4Wd7`3m~?_rrKV+mqiXtFO7Csy zo%8faS%T<9ECbfPP?Xq2J44GF(fHsnqh(tZF-uQ-c}YFsuww^a4gJsRT?cUkm*fGF z>o>o8u{GB!DwFRCNg_&T&x%rMf;qnD8PD8=>dvQbDQ$cMc@FKCZ!D%ii>kd(Otf9m zwlQ_5&G_Z#{63{NY~uvUZi4xGtIHya z)U(94^@d3C)3rd$H7fbOs%NJB&qA$%Z_RB2$cVmae`F9s{MuFh;gbb4294EA?BHHT z3s{T24aODR7gV~(134O%AJtK;hy{6w#syzv>Sp;{byTOyK;)7EMPG?`{B)aCV~6J3 z$j@;c7LSEw&RvQ$-%hiqjKKAr^C>5|u!uc102u25GR>R24P>b6A8G_mVp8iN*u9eL z;Zw1Pb5F@C+(16~p2iy#$FG{=mit0{^IRm6jkP3mbus~oCX~F^Mz|Qu=wN9!LYJ;q z%s`AmPVzZ=z^qHQnEtr`RTZeAN0GEp2V0`Pqe)-Inj!cI#*FuZ5pZ&in=Qt-+9iPD zqAzZdRZHSY9=TQF{S4)Ix(QW&*Tol_zHo>OhB3r}F`!t!;xQP_qAuN|pv5N~Fr zaW(4LOomdEbVTBu2C=MYLpJ3~D2D4ZO@XO%JjgRp$HDb_HijXF$kU>1>k2#b|KaQ% zpet+IZQ+hO9ox2TcWm3XZQHgww(X8>yF0ecfA{;oXMEqi=iL9h<0jcjtyQ&aRn^|> z*%@;_H79YzNz-P-Ag|M#-;4yK@1y4>+LotmFRyN$ojlF@x@Ts$9N`LI*dE}m z1&v3esJO$-suNH!esy-$`Q%oaOZDCPeckPgF{ai|W_^`b$XWxq@9R?7TEm0;cj;o6 z3W=?>%}W+2^&(jt1kZ5yoX5Zh&-5M&yBsW?mCg1ET{oPJbW?1bC}$tuoA*NRk3__E-Uz`DMA z$5{wS$=j<*Le+$W2lsLsocwDz?8TFeYUhN^I*m4@IUf8W;4YMzrt`ZAUZ%)lL@ z1_HSSC8VZs!>KzR4$#=zoN7ivRG}>hNjF0@4DbS#Z$|uNC_`#AO9_8Ez4pAdPiU-% zu?d<0FQ#V}Y#gHkX2VOa^FPKbYi(rjRPK(x$ho#8@bx#H;xvl+fhR>nEo@uKt_BF> zA+Nc7UYpMF`ybG^M$zvMO|?NmrJac1%eZAtjscbuf_x$@UG3Elql13HQp=9#6RNoF zTGZWl3QJ`OR5E6;J3D(lxKxd+dr5f#Ppte($;HB_E#_<(so(iw%`I|$G(&z)$h_3m zb{>LMi*oY3-ti6evU~3(6h{8KJnFV8y71R|dkv;zBI$d?3C~LZj@S(C&jo{s(I++8 z?ty>o`|^FrtM_^j@%@7`{6Z#3E`!B?>|{?7au}LZATjzf%-EYts1w6j)i`&foXNgZMVq5`# zH_!~;Q3$qZzrxtYNor31s;e_*BsJC)ewJ)rMXiFHAZpw@q|!$ftD1ckpM9i_=aOLZ z=y-GFt$n5(yJs`GgTgP&Xttx2;^8tlcnO1fB`?OPd8d8jtt*GTLvJK*s<#jE;1sd} zwHETvh?UkY>8c=>FXKAH43zB%EFpWEl(O&lSLYw}LY8xhDQ1SB3j zUPBSPx|>7>i0~f-R4@*B>&Nfi6wW)b$a2pIluAI*#AiaQZ*6mOI5Y zM&qsAySR3pV{rKVh{XsAztDcMV1BtTE3d%>6^lyX5gmo<=y(aZI5}y*z2BX@+z#%w zJ~6h(-r}{fEx2NZh&s%q?(p7tGeq#5-DJG-_Pr+M!yfZ+ZDEe@aeFPITkF8rSa=4C zb1m`MOqJf;e80U0p|KE&d}$f~>7kxRTz`-|ChO|oL+)nKTAEQUT2*O2Yp6M6>k2p1 zU$=pLK3u$naW`mscXkV#j6K+F9_gTJDagj8@i_GqNpczOnmD^8MV+~N)AyXgW*9i= z`x5_ovFS+({1uQ*KJDo=d!5OJM3cjLmjro<)ws<3C64V&Beve#yg9|U-fPVRhfPx1t( z&a=*5yl{TQ-u{p{SSY=fQNpwL?mVGw(pxw7N2fRhIWx%AGS)!fHosEh;ig2Tc{#`B z+%As5%=`J&;LKwc=VX1O);^O_mVZQ_vzonaq+5Q)AWrVQ{yA6IWVQZ=p`0_eU;f;e zOO8(GukK~Cw;!rF>wbjRhnjz|^ej?1O4chS`D&9nZ*z$`2ps@gKq?13vFru;@}RhS z2{gP~=3tenovC_6=Jgni^#f0zJ=a1FW*XE_)z>{1!IZFVD=N)SP*al8ogMUt zEnZ}^?^nBZR+L{i9Js9QUyHCVNZaGbQxJk>IGkXlq%p}PBMByybsrdmEZT9TRFKsF~)25HOeJdEw@(qle#_|f>A@In2hdyn`0N88ifwB0=My#W$> zHhnGU*8AL3x@iD&`j0gFK_N@*WBaPT!-(lGGnF3|YL7S2rT1>81z-eKtwvoN>e*?Y z>U~z-`gm{62>mnu27}psAWX`mL`j5_LIi*jvQbMUjels+ge)9wgg;-C7g4j;qZ>+GSFC&d=@vB z`}H&_C^-Ic?&LkFYNj7wi}NWRzz;GyghkA&$Z04Q)O37;eLEzDEgSj28(tnAdvz0C z4~KEYL9hP^Z9?sv%iMm4wI)4ufYFmldfecbwp)w$I}V=-cLEzUwQ0O;*?`%Y#_yt}I_^eT{8iNC3SbgR7&v90MXh$h86h^zm%{4W<+66`^3mo?Q?;*~ z3TaP7!aRkC(7kZ2fwuMbNZix3@BVQ9+aVgh+H^R`>!e5}oXg>0={!mnn7X zZ&E$^S&HvfZ@d#?sz~kwC`j4Q^bKx%!AqR((%8Ieod(@BRN#?(Q&kuq0|J8Cb4NqI zIqPl`MAAQqwx=plJj&|IVAZCm`HKPnN86i_fnLvVGBQT?jG=DB9X*i}D$q$4d?FxR z+X@6-f(^NrM}jwmGKe-$1}d^LORs~SVL*UQiBhwx9$Q)MwYgPH{qBVXFp*+N*1e) zdJHm-`8k%KKccT&?a=X;4fi3%EH`I~d;0Qwr&THghz$NVH^% zjEXD{VKqfX_@dac97Ua3K9a`)OB#;BMgQ%L-TSb(e7|5W$-+T6E~{IVRr=~v{OJ18 zIAusuyZ~Jn?ijnRoVYL^mTfNE>B6Z61Y?X(omViJqtiKQp73+t;;R)&28Re zLJ&vb^Jl^N>F=YG&S&RI4eS3jSSOkZkrHYhR#NTx(kC_xL3$)V4Ro%( zU_+U^rofG&gyUqr)2`ain%lM1wqC4_22co!yf3pBzjZ3Lk#&Z#j0CTHz6;>%FE)Y+ zGahC!&2uy3?ZcL4nvok*0c+^)^mbu7ZIbbxbI7iF)ChJEYmjAmjRGwW?OZY;B@1Dc zELU-CrY;nS=x~t6J%3BAT&uydFRFv}vH&NeilJ4`l5RbJ8DKgzBT> zNED<`l}OxhQTTr1rBL0>DC?4f%QD#EGm=WC=1|Q#CtEa?vVGlp?x45T4a~g| ziltll_!ds5&D;++pk@0`pyho`qL{B`iyGY>1+QPTpzWLWU0!i%*jol5GD%Owu$e#8 zQz1;Fm_S+&TJ_`nT;(|Eq041+V!>C4usmT-o=xTj%n@{D%RX`&@+Pjx-Yt@CBhtwt zwBzBQ_KC)-kK{+?;l)?ILOE||cPf81`oT&{O={?h`)vu2Z>0u!2H$)W5aUBmysXT$ zn9B5_hKtb5< zp3OZm`0eVkJ3+9ZxPqayPsIp}9dd0@VL@GZL9<5C%zWV5IQ&nfya{cUQ{9 zjvC`ojd9FCV}YOFse&I+~sYbimuvoD3q7%wqbTtg${ zMmHuiP@CX+<@OZUKg8~VtD)<@*<=mk!;KCvQR)?xqBXe$Pl1T;E=GJ9OSk?GzWYW) z2(@|_;f+U^{S(vUo{T!+7YO4l#D|Do8z$TgIM2LSY2vjzcO1kX=PVmjSjNKBP%yr|$}j#9++majOc6G)B%9%t@iJSt7row9kM;SVJfXGYzlk@VJyr47HTiPqX)``~2M%YC}34Dub|8f0s~n zy{kpW=0>xGpE<(VW>~!LeA#AOl*JjtS+&5YvH0#ipA$Q&y7Sm(*bbc`$kg9b0-z%a zrjHS`yxLh`rH=;rPdb(H7JB-7E(fkc6Ms*u#`Q?PUpo58?iTg_dg=@f6j9c2nLHCS zv<%lQ=PDuTyp7y>c>@YQL;anxTaM9*<55 zgWZR+pv;0*r~Zqp-RZ@o&UCIf`i7^r341APLp|_IXg`XEfY&1};!ZyKj_rO%CUK3- zS7qr6#YZqXO~@()y|7owKsW8}oTc}yWPGoUp*xF?f`$dFe5+HZl^-oQ*T_c|49s#N z_()_SEP{@iiWPq1)Z-v_-$t+H=rg@^kob@dqWT6AjefhuLVvYgbw1jwVY&-etMN4F z4vLz989Dls- zCnnMopV18!A1A*Fz|V_l3bBa){juFsldz7Lk(p~_B^B!?Rq zHa(>SDF`k{_GdaN0z{E3_DyJLtWJWR-N_dBvO9@A4{&wPYXH($&N~#{6-nSt8Vnr< zDU0^ERmtHJ7P)lx=4>-N#t=k=u!HT_^HfvVxe5;C%1Yq`)q1QD3&8l$2Dn(BApE;IV^ z+?6?WmP8)1P3fwqc)G)$y48DZ##F{OG(JbL(rl9(>)lYvI-7Mz5FmY~{!|O`=){WD zLPl&WxA*}CJtQ(Yfp8)6wW#gt2;w!7Wjqj*y6*B>wVEZAAC)2gt4X+@Qm?+lW`0od zG>XZ(QS?SZI^L9F-bF6>aH8t~h=%r_uj_7#cFeS0Q%$A>4<@uToNznt)DdK zijjwW&7<;`&&kXXtXD}^TM?@xf^idl2y`I-t%YpU?Wm5M(J&mH!&fRAOGdhh{9jp^ z1LmYL6a&{v7xvQ;jRE(#sNnZZu$OcPdu9#9{5u0*zsNTj1(hoS)10;mWl95K7}0?e z{dm(7(E&?IlpBuFz*6`kJ38zqnKJ$40x~{J zY>*_mrzAHE;TB{haRZO5yZLrAK~@g3M9S%|;+Y9DdQ=Oo;(GeC z1#{Q$B8!!E(MpD?)kz$bqwJxEf)Om{-wl>bM#2`)R596F$U@*6ql(kWa8ZBI%p4xr zs#Q7=jUizO;%MB+MQNv@TO&eS_h18)K=15L2Ob!R;a7@8A9W@y(@h~Tt!xzv&wbX_$7Dw6 zD5v;~H-{(qE(RP+@MUamzk&rZRBwu5$896HaVgCjie1)egY?pI(wE8uXFRiOYb@C4 zw_U|0V!d~>6a;xDOE)FykZObwaPal;I_j_-RiUjGZWcmp8pB~H=YYaQT!_nWujvli zFi=d5_QKr&M}>JCEe%m=T{4R${fc_s>KmI&d=)Te>(f@#F4?SA7JCg02E%~E1RM!1 z+%-2%H1O1Cwy>}DvLSX@+38(~Xf_Y#kZV+XhHdcE@h;S)+Y71iF}pfDE~WAZNAGDh zx@?nVKR@PJ6-7aKM5jBmY#%~>KO^3|&9iETrC?_o(Lxt4_&PKJ@wnZPf+`hcI(U_)2qHboxzE^5w#XbL&e~ed|XrN4sQX;yZFRRYADApWXr2#Xr zWxc1Xe4xJaYK|b)NEq=n*b_@t%ERPDqg+|#&Yk;|Y}{WttjT$2#_B{*uUvn?Y@PzjxYsG1@7%oA2qjGo>Ym^et%bmYMBMkK z1=s!b(d&;gQ_kN}S|{{pQG`>_%#PV{6=x9}(7y20FW!and7UDz#FAz>ux3`sh&isyt&}r5ki}+$21pP&Q=wp(?!)j~ z_nFWemPHUWg=M(B4Amyes*&;X!eifr3QQ`n2?=Xznx#Q;ufF#;Mjtg-e4sgCZP zpSZyD)R_0-zLw7;h15zG8MmEP5e@9+m`yB@ZOdF^MP)R;D}F?aO0DDIfz## z>n+xHeQ2fWuXo6KI%KO=4YoZIWoFHV!Khzt#E0lTNe|wv&icjkf3eY?+epY_ml$1y zs@fVJI2v7M;J*$n3(!RsK&2|QOb4b99@P;a$3egE7}$I{ZIHD8tn8ULxFO4at38uh z)GDRB=hActUfWkrZ! z2kfr!o`NI!+)k2Iiu!NxF(duIXN>=C@AtoDsQ(Sb z{x2EojP!qJp8vmOsQ=^d`)_ddKhi?~=H4q}>tGGg0RsH~YeWDuPB|rEHChpKD`Odb zYk=V~EuAZ-t+{VOK$lTBg zpOOCWG<867y}px!IUu#3ftLQCFMRs{vG|`F021;A{z}qk0T?PXu+al--{=7)AF|~E+Xbv_9Te^K4UPX= zH$g{0B0l}!5I!&OU*5-n^MIs$27skABmH0cPXLhp56=D%aL!2o4+j8PL%_lTnpy#z zg@ud_ZHT=)m?lAoe)$%cM3#~6Rz~7s`0`5Kc70-hY#_}i|3!E#u zIJekct$2%Oy!P(%b^BfS<@4CK=VkV8`+X(z=`wbEk=Lcx@QewjL0#1&Sl|A1ZT9*# z73-Q=nDyMsg2h{*HGPe()dLhTRd$n_kK&{?O#9AMS)?FE6;-I=DpI%2!j z1=2{jGwod}Fp8`B=h5HVL5K8dko1<;!YIh&EQC&-otqF6tU@%1*k0&E+gKAuC*mxa z-4D~viW0};EE=C?)5};9#W5_RNx3F>>lZ|hl<*hHrPPY6qT`s2OIdD+_&VgU2+F>f z&+Z+JMgjWr3ehOAW$;>6_Y@q;NFaDM7)eC0-_qax`E40Yk@qD$+Z5GmVYMw+M1$Id zKkz2I+Q1;q9Z8xf^IP_yn&x&y_;YFsdCSC#PC~1OWqX;Pc)s2Qoi6N3^@l|N*5gx< ze$y!-Rj*r$dx2rElkIS7SLsT-%8@r8jSYQ4_RHvRonm!Xv)T5Fw3N`?UYPKZD%<|M zG%}OE=UNQM-n%p&-R9eN49EV)fuCn9M?ylw%#mR8h#eAw6-)wG18 zx^;Kj0~}@QxD?Z;3vL_cJDB;K+8GYe8kRf2RcN;F-H@yF`;%Baq@0E{EiEh4E+%K` zWgCvvs%F`woEinct+b@x+B-PJD8E*xr5rui-#RYT-C3uJIi)q7^N@0K6>CCKr=gE&1SDh8$U#tMnmqw)+4K_`dxs?hIk{Js;f zE`^FG-=QL=G6-9t>k;c7l03Qui7GV;^;C-gl`1l!ol$X=Gzf1|y_^~b+dW`A1L{bb zXh)~=;M7dx7UdJw7lsV}w|XoyxawK`WA_BO`2Nk9zViBcBs>u2}U3imS~ z1em+mH=VU|R0#BMIl>zXfqL`skHbUXRt;;>SHb!)hV>%CFLlER60Y|e&;dol5Y1PC zp-MpwNWVCz1paWbj>BZ~r-KQXOZdrt5K+d^ko~piDLPhp<@MwBgYoW+I05@r7v11% zY@+=DF(|)D(l>L3AtgCitgU5{V2NDB>WYIC2W2+rFVF zaI<4&1Y(*kny(l1TuSv4B~fPC0hufB0ZBS2?zzC72oAew;e1VnL1yCYNNnLL4Ag)M z`GU->Ys;AeNwK6PQE+pN<;f$;d}4&eR*GoaN6D}hBX-de_I5^D6#0a!CD1vI62P+y z?$uO;=3d$(n8i^Ib+q;{6z3?2Boeeu4%v?~w3&s(HK@77V`FIO!cv$u)r9IJ3lpot z5`q{wD@09^@=5GlX@b-xN+QU`x2ShJF|-953r9iWW|b2t=gz_%qw>r=$HFd5uWJ~z zC?7y+#>0*p4Ya?On}q4lAKhRR3rR8##ZYWecTolqtAUpwUc1uAAsg>v$R|udn(x`^ zIRO?(sKlLR;KKxGnc-;GSV+=<)Em-Jq9#HtjQ&Nvb!lQ{s8Mt7h!HT7+F9(vhjOtj zdtMN*gI^E4RoW>@@H7x}93HDQ6K*HU@g`se>6E|Mbog+}+4qwGvblaQGC#C4Oy z;_HdxVJQPa`Ozs#2qfWUxvE{7Qh>SG@2qSbDIu76^)_BLosL;e1+oSLQ{bdHV`k$S zyx_Yk$<0UhG|;!IORM-NnaC-H_5RQf2*_ysc}&noNmBJ)B14yb=YSx`fAyFmOmIya zG`#pQDvg9%`KvBIivoIgc1fw`aVdUb6;laPr4Phb`(!7In0Ny=A$%-4|6UBF1<^i! zo&M&8rvHK%2?qSZWGBUu_opifksW;jff#P+c&?a;5~m^(T-F=MXsx&iHZiV}ZgP~F znK*Z$9{6R~St3Hfv60YeMIr)Z)o56P@sUNq4*l&+J1!}aLuo zRiNPz1zu7d6aUOk|OP?ylJTj9aM4 z@nW<0#kdBWjfLTeqI#STN1f6cJeCv%D|@a;;;p%sNRz9xV$q8@P`$^zUA}=VlD!EF zJB0N}FZE3zQ=1+`%h(2Gm6D`R;*}&`ov}|LJIN)H02YvcA(fwh3t`RBJ@PCu^XU}> zSCXiCQIR@TBllj4AJ2>-Vvzr=EYLa%8avMX32E*gJZI{T=m60DEcHzx3pWuy&ipQY zi=tuflXt0I^f8X=1-fz zTx6qGuz;0-<2)utGSj3goFNmfpxT}##+pE>0O6FZ6i;q0T4p|2h2PSjte{$mXch+r z@SLHNh!#$)olD{*N>*6@6aD6sGN7ql+cOl%3K5Se%LpYBiWl}MTk)5ZI0=%!14d<@ z0O>nab*A1t@l4`N+sB&J9)KkweKK^XDS<;UmxKJ5MqcT!wz2`H6jO*+pV61=BHm&N88=)MG7CeUZMkw2;YU zDr>ExlwicDh2nM9veNeCxr2N$;pD0X);5vgN@2=yd1b1q$!eisRxopG_N*c^l5vCv z8ZqkzIyrfgKQ+AjMCpD?0}8`F@;UjCD&<*bKZ)hnTNwpdizXb!5qONT>Lm6l*5#Zf zd`$-xRB7_6g$0y=rb9E9JtU5OtN9f%2BJkWkKXCoFYN8-La^v}7Tw&_TWt7w>7O=C zV6j=Q*V-BZfdom!2FS4OyLn>#T5-P+32LHb{~Re%Q#A6YymG^{iii@{E)6OA^taJ$ z#hlc*Bld==!uq!8+3hj0#D00UapCvj_6aa~>%J350)?e?Au}N*tTQ)4`0Cx0(yYiZ zi+%ueUfj2K#f>Oy zSQ(y#Y{gkR^|?q|!~)ACrjVtDMLIWNfi;MGB2@WS5n(Z;GY*30S(;x*U?Ic7mD8a5 zMH9o^p*3{S5_aQaS-48hl11^H*@JOW`W&)Jg;#1Nd2A%{c|2~;VkaZuM2@CHKsseV z!TAPD9ZaEK0wI5{LV)Z|isMW&-l|=Uj7tVcuT#-fMO^(U-HN4HMEZ-dQPx_IuOy1T z1^#Ep@2$7<;g5%CjH8*J_wJsTv+W%1N88UO-*;9tWZwPLX5*l1PTz|Du|c6ucwdE3 zpOSt@`TSR7iGg10q@U{YzbR3=)FB{rX~_&~1`ZERcLpr%LZwO2X-moNZCG@&R1H+u zvMi~Znd&BxZ+5nGRSfu$bl=Ly2{7on2HVe#QV&yhH>YbSkWPD*H|VSC26hk6VqBMd zP6F7)Wx2>$&ScH&bmLM1$G`eRl+8@!cQyjv4&J1))Zk+3{0+-b>^gbU!eqEAwsV&C zTX+Vf0b8Kf1MPz5R&zHBUKiayRtFu>1%=bY`In_0aJI*#!$G-|KvqDcXG{vhcbDkJ zYFVRKz}{~YsAoH9cuaQN3Nv3bjcX<&Gk?1i~l%@`J8-TysUo3 z+Scu&J))U^=9WG5y|?Wd4K;ieoCf1*!l|@(j+|4$l@wDh zSf^ng7o-dq8W|KQc-%a%>gvIp=-u3rwN4q>RtT9Igmj7n}fn2OW*`HJQA0~yiAlpXP5JlWoiRyL$R?TNvBku~HU^xpIIp&c@nN$N*4zt= z+?_FNG&Qx0A16L;2ngdB{Rz6;aB#7K;l9c)zn!PI!v#HES-LtBuASDee>qbZnN4&Z zHOQ?GnvV$wqtv+cts};bY$!s)DaL)gN{{fchS+yP&TI>HW!d|vCS~{t zq@X3|X*ZLPdiJKL`(lqdq6E=%U@OJ}@%Q#6-pP`WPiqswR8#~*xJ-<)AE<&~xOJ`u z?3AkmncH`XYlY8q2Ql+@rEDD9VQY?{xv8mjuhvASqvyMem!B8u_A%Hx&V!e|$i~X- zDQZ`WF9yu@jwGE1hZ3LJ-2?L2g5bE?OTW~%pAR;ZS0*Bfy!Qc49<)9&nx-e`b-Ll2 z(`Awn%6d3m1LAY<0-8BTb|vn6yL@@)@2RfSxg6Yv5oInh_Q`^QE%n!d1H@J`7YS*_ ziYN6Pqrl>>Zxr43CA5kcBH`At3ta?BJ8r|@2HfH9D-UI}c<$*6)~8c$hS80A_*|}X zu4r_?d)K~c$b|*5DmvR#)Jt^k?T45TfX(@~CoHLyGi=;%g;Wmp&FZ zEd~x^VYg90Qn5AXgmsD#qUhNvIb>-d2ibx?xGns3p{b3-JI1UhX~PC(s;k0_d3-G>+N2|uLCcf9Apv3#iBzZ6 z!h8RDpb=Rmk#osgdg#LV)}lUTVS8)=Vih30oHD{+52M94C7%Auy?)pGji&A-4Cwd3 zS0BMI#A-Y0)uvO&Qb!{NFoYx<8fQJr>L>E?u17gdQ@gtr9hz>$;2+A@c5Kldmy4`! z61WtD(}+S7JM=$%uf`M=qx;2rhoLC*#xMR~YO8(%ZP~b~ovW zu~VVLs=JoyFGQDKlpNdFn#?o7^|@qQPq&fiLBM0{3~v$i()M^#@V&~51x8c5k3+y7&LogtmcWxC>WF3cq0w_nUn| zf}m~{y11mcO#T=J=kccK^LQ79T~y?5=%)N&x`y?X#-&aHV{d= z_IA(~I;iQP-8(L`BWWmFBB33gZHNEHn5|WpWNc3jr4EMcnyrp1N=+mm&+YoAK7Nzy z>Ps1Qq$p|kMrHDm-g1|9gM5rx#=O5=d^O>>z1vrC{e26*WQYbdnar{2<`W$2C7A7h z0G$6(e~0{ocPg1XSpneO{{nOWhH~Ak9Nhp|F2A#rnXLmpxsbk#xe>m!zKxNwmAMU| zLJ$B|I{m4UHaB#zb+k2c!WVWkG`9MK|2o(jIU54-O>${{Lws39d^LdVJuM3@E55w5 zzJrqoK0uQGFXWvue=OlL3AJ?WApu{zDT0 zf(n@FA9ee`Vc9<=O*(NwK>>Y7V08Ci_p93~lz)N7OY-9ch1_reL8`b~!$^4_u z0trB}8U8i;KePEW#Xm3Me*w&Ydj&w!$>0O7!2btiw)wNHbV9~1=7z=!q5}U>*dHi3 zNm>k9AAR_ul<`!I@rSB~mB_;Q4zh#b)D0DF}mXZ`W*W(~|T}8ezhqqcrCz zS{0$tFqz+Zf+d_npy|%xKMI85!E^|lKe-Y+43)a+nR?uFK3~1M`oAd0D#REHGwY2_ zb&PJMxp+89t-oO^mx>^3QS>`vd@-2?9%lDBc#pjay|V%3H$=q znaSH8=6hsdj+Zi2?N5#vE1;K}FKm3kuXw=gcp%{xdZj4w<5p~~H#>xfz)lBQ=F1Z@ zdrcWWA)72`{vbGL7K?Nq*Cf&Q>(h`Zn2P_ZgH{?Xl=v*Qm%5M zNKreBBx7Z%r19v4lr8SkbRvh>fv4sXqs5e6Z{IKd5(|>uVXS$F8?7vSVP*F^(P&6j zi3~6CHjeuc1>9I_+lSVfkiWW!ha>$oHA8!2otKGWfGMF;jR`6Hdi!mNhS+$^dtt+w z`ZLqiI^GmL7z_xB^^%pDcs3Fp^Y>3-SPTy-N-2#Z-5HC%{yp7fRK$I4RFp2Y-#IA0 z)9%QvnnQfSYS@l2``h&NlO|o3y?q)*q;>D^3WBJ)op*L4wakUp6N6T%QccBbd?rjmd1}V)`++1O8 zfwmn}4ziEapOqXARk?0_Pw}8HSySpelf4`#rg5hlQH5=ItA zd}hEdls{!QfZYfSV0KK*fByc{j*SDKnFUbK1n2|cxxxrAP5D#D1Yp{j0d6bIfam`` zmOtk?0D@eAF|n}WGXu1${`3u?`2H2)|B9vmEk^!DJ_2U{A4oXuIDjV?J-pE6O9W4G zD1M2lAvpyQUP21z`xjwMEdEYJ%jaJ`HHAsY9y9z69!w2$!yjFyxnjN&wIGPmIoWy; z6>2juiKfnOB!|{7UCNVFq?Fme^)(R>a)!TKSA^ZEilh)@oo{Ki{w^}Z+riHvTl2;X zEr+&@a-H}k6n(+VbgsimL zy#2xH1bO8h3#EwJmvmK`ICSCO!sq%v>JV-KK2ny4@3Y--_`kn@|N5x-vo-)Zvwywl z|7`d9Uq4j-*{1aOhYVnu*#N#X|9Sluy-oGB2HPGcIMzLvt5w$WmG8?R4J0k^Ei_Y% zC7S_1`vIP8Ht3la`0y54z(Me01_8^KfyVf~;#mTSNCMyDK*Pif_BaWmX^%Y*CSt4- z?RqYUA9r=~Omj`g(s^#DCb;&op#&fZL>&A^3f-Px;-%+m8_^hKfv{38S5P@!hRfi- z3p`l-1_(-mEQ)TfdCo3Gq9(dcD=lXckX(nxN2_v#(+~_G}IL*?npA8()~6 zS^vn(>~?zUx#$x$lYj|W@cm${zhxBA+-BtAU?&C%JZj z_fNr(L4s@^uZ#dGUsfmmH9UQBvlgNwxPXlEk-5&>mx4pAfMI&TN%)Gjgt~?T&v-q zF7Z^OHua%rB(Dj%T*+x&VyjgH7Xo8G4k#K277lXq0qzq74lr$~RW3Yj{u^PauXi)i zifyoonIn^ChtqMIqb0|hw32Pn8zQ`tHln_*i5tQfq`87UPr%PRWCoY=JAASiB#(L1 zwNw`Z6W$T+nHz!EParqw?n&50u~f}kuod=^-#RLlsJkFoS0Xv_+V^7GSX^b)E%_>Y zPrTXHFSTp8dnKz^;v0z?wg~o&mN>Gkz*WY&jiPD?tV=PL(N0IL22Siwjqj0F-?k0Z zqtmmyzj;E8(`Rl*w@!a*o)vM>F1jYt>4W-UcfC6TgeIO=P-a-X8QNJkSjDN%r z3krQXVa}UqR^O4!=J7oWEU`>@mi=okJ_WRfO&(7|) zE=QB;ljDn%Gc#LDYjYcmEDX!iT!yad=HmA9`ux&bd_FcVDy9U4yY@5IidD0j(?-lD zi4^it+wex%(4EzOdu5lxt}ee|BBC(#Hev&ITmhxiefJ##m(6bpwBs0pQ^~m_7`q&X ziX3G$%-K?OBXCVZ0@sd{@iXY!D_mc^B^{0Ek$Zj|;R;vOC;MUe+o7ulX>?X(3fgmG zTZFe1b8`Y=mjwg3_22J#>{Vclz*dWDSBuXax!^nvgfEU zHWK!dx%@8Kz=w^iv?G?NprSR8yi92vyfk1xy;nSQ{l*k(i`x)y+%G>LF%l6!2x9LJ ziiVS-35(awYZE(kOE`Jmx#@e==T~t3Cgv!~joBORJemChjHzn6N|@LGN!a>468zbx zt&7N%5H)MG`XQ`FSh16ozT+fh7U0>BlkfAJz9Thr$iN5#_!^`Ogd3Z1{0#z;Dgt(> zNI%6vq_Fi>eGDj`(fQd9G{ri+5t_``wen#Ijv5MOufRBYyRwxM>Nu}8i>K4-*`tqH+jpk8C?4u(AS zY9*z$fQLt?8GBQ+!H)rTz*`eLZ0pNQwCB-t+E0!Dl$5g3Q-d?*SfZv!t_> zeh?~^p}_tRl%rfKL68qSZq{$NFd|zeBviV*4Gmko2y1sdTQoQa#x&6EO#}*_W_QkT?|flu+9{bTw5p z0W1Mt1Rhf~ag)J8v8ez%un8rGagGxaVpX6jRCI_Gj+)Dh8yhpdFt(g|PUyU%9Cs+qC#Ke>=FaQU` zX`!{B$M9Jlh*WiIsH62kYJSPgXh7Ks+rFG4BS0j|MMC7i_YITC?YWV5$klmCuh}z4 z$OvQxcMT*q@O|j}IxA*Duli~7P%7OYV5@n#xktXDUH_oCmfU4lklj%z{9sRJE^Z}Y zTtjCQ!BqDGiM0K7jfq+l%{){V+Q)8qB_0||bftLY05Tv8KFeiQ`6#KLS2sH94)WXa z11eA-I(+bFpMNWFg!}jG#c(fc=>9O9NIW&(K7eStVQEABYMmFnAwO~$HI6-x#0;6_ z_ZXFZ%q1NAS%*d#Ou4p?FMzjw;B_zg>zqH!S&RUIW>%x9#q3$9lr!sVetvI%j2Ok~ z$_OT#k@mD$tS6B-2=`Ddem691>Y|usUp8GVzWKA=H<}-WVX2B;qb8!y0xXT#s=Sg>N9`R|hQDR;^=yTui8ZyN8z0xJAye&A$1c`q zWa_zcSZ=NC^~Y1CgTwQIJtMGk)W(RvmCV+S{`xH|GJqxwb>o~H#X>b33U@m3`3!7B zm+c;*PLYQ?!SY1O;u5a8e^^(LPV2CWMeypY}_uE79u3z zgu_yh$TUz%HsVdrScB(K&TA8Hc8!`1NQ7C_Bo1ee>S6t`ntifF!)6giGn=ib>3L{B zx1C z9T_z|Awey^xy7SPGL5w?e2))#Ha_`YzG%EuTEtvapy!cNWh=jQ*XLAKxj15x&Dv7V zP++MoIaJg1;M794nK#cd$8+J-;qu02F&^rxs>y4iQ1yBwqpsM}N}%|W#ZOkooKfeu z%vMFa!LWVOSQaIdxmhsJc~-n}Fu1$iHm`1I-TV(j~i%R-JZ+LJd=NPD*vFU zz@0==ZcBG~?>Y~ZO?7r_((2^l%07tZa;)G?TBT9Na;(&Y3fVGvDcPiJO~y3RMCMSb zqI#2qJj6p0VGs(T-8Aw$06~)b8^~ZvaiDY?xeS$#|Vi_4&rxAN=cg_5JPg$(gdjv7GXgH$|W3ggZr5LVmgWaBPNuRVLIST!ZZtxPC> z=QaqtofS=EEKMhaD7$7=b=k-DaQJg3BRzRSW0B2)37W#a_Zlym4iA?y!`rF(&bmsx zM&Vdm!-OrII;Rt#ZG?~17(L`#ZDbAIirOM6`X$K$30lr3kYX$yWz1Ry>zo#^;Bt_f zm~2?0G<-$PaG8__(&rY`fhr0LJ=bV?Ax6ACZ9M13Tfv4Z^<*kZQ9)*W9LiJ%tKcK; zz70AfK2O58qtmASVve#uQ!&-La9)CJquwT!Nu z1a%fB5l#sy&NR_e+pL~?ue}iWRk*FW&U^-TcGH6)44p*r0)}){)<%=2>a5kSGNy_q zFPUIIo`mX#=gRK81+jLf9^cQ-1`043_bTt`$q4V*pWQu5wnOP?9tVa;S0Q%$D}{{z zA8T&`RmT=|4I)8;2Z9C54Z+=Af;$0%I|PEeyF<|6cJTngg1fsza1ZY84%2xr@V;5| z&&B19`zd}x>^g7=zIEZ_fkR9 z?&OqPkol;WT0PuFe*Btt98I%1`RvGSQkL!2!j{FGBBr(TjKg(@%IZzpdgBiVSqCTA zr61i3NphVn74G?CBbrL@drj5$XDXfX=;akDLsji7QJ|ImBaZnt6h+O-Q97%u@iiFQ z8H!5nR>T&4w)-#1^_@XxSW#&p%(bpn<0Hy1QNP!@%dt*b$#hYo+6Q2xy)dhx9}w|o zCAb;A77el2LdClhYI_7|n%I08d~10UI7G6ehh(mYNyu-%|DM;10)$bz&*|r{5JwRE z;Aq~gWL;B(74jHU=^RQ&y}AYoT;4-dLRb#ckO#i6oMdY>O*dLQ7zs{HjzAJ|O{Qva z30tFAx6QenI%uH8$4k;;Y6h8%zNt8Yc1T;;>z8osxByRk?2py&n&shYg^ca?ybQ2y z&n48fGJ2bY8@2`BHY-GFr`7Jj)n_#jZ7y>72u@(WS0vF3-# zf-_W>eNzj5B7w9d+|*a5gU4TKE6Trk3}>wNSMfMYt4l_Ie(hn=0Mqzo=C{getK3;m z4*Dnji#I-v;Vsp|rFd@4tVKV{GHmp-_dXN%;rgV2hpc#QPp=2Gt_Qwd2geIqUM-bw zZ28JjAlUMBiD=ZCgyNwWo-vYy_P5Lr<|V+iFW(Uneq6|j8v3ziOPMd9joBEru<^1QvqY> z9U>m}3$`ie|ga!2Z*ogWHMzOCb? z$Q3)Nq>Z$Ga2AwVP-MlkWmguSopKa;!z9hAYHpvSGVYS~TYXZ!UdmL~-Y|gop?s)^ zJ6evcUNCX!Q@w*x@A>KJfKv1rp8?$UhiP4uJU(0`5jEsO4_mia9|sf_l*T7^8h-u4 zqNw{gmO8a>svLk+{4NfDvrmi8efeCT8aWyfnpJt`8hrk!HTL=-W#Pm(((6 z#rQBqMVcW-{DOnp_piaS>Q)OMP3(nbf`xO`T*+f`JIPE6ZknjGR+>&~71K<$Xp>W>!s%{29cV(AT24KMN`Qr*)+GO zahe<{-S0qZN&|PDTxGXW-pH!+gkEUUB5G4Rla!G2EJmlmdi(Hi!yyz0vYh28JUd~1 z4zfx~>LF5;jWpks*NoL)Nya1cW$&sCZgCDty3U5^EuX(Tw8aR>$aeA7GC$@VWirER zBrP!ArT)4vLrHq@%`(PQXs1+ARU$Q{mH@_lptyQ_sc=?+m2BUF$`mKrElt`{r!&iU zm~SZRO+`6K->|^fVfdn;u+t_{slNd`2QGAoiGfMzL*nG&R2=4y>7ek~_Q*)c3ruJb z9xYx%943=bd10qoZQbcqP7~Y0!LrG9(f0nBKv;ABfyPT`^n;piqVlK}vD~HLC`ojm#FfN)- zE0!V3{`p)saLTX+v)%FItYVznAGChD8Y;M0^IQ^(lJdnIcDt0sXgHT;fMsk+?@1E4 zYg4%cpe~YMD{3=0G*N$EFx+s1}zX~do)wk{DaDO;LJ5OBXQw1?0T>C>yi zY5td7u_dGKuas`;&{3(JQe#+Gzm_Dc_oXx-6iR*2v5;pQII98S2tJ~OkK9D_st4+& zVbcjktB0(aZ15clq?qM(*Ad@b7jt26-&RPdh$KSH+MDXv%6I9Pe`SK7fO_7 zdJCWlg^&Cyiq6$XpK&H?35<&zMo92kw$N3^+qx-FEw-ImZ_AQoi&kxDts4{wd`Q0# z#fwPhbrT;>a4^Z=zbaN_vK}Ne7uej!Z$c`jYcFC`CreGo8xS#@x2IG!og8bHO?YfH zb-UwU(52rspw>JiEjC~I`jxsqxrmQm%ZSHpgOp*tK{w0hcX}vN4Q=*~nP@tgF6g3b z@AN_3w@A@=?K7fwom7fi{DZ5h49iNV7T1Ks&Sps*SnzlFH32JgaCBI^S@MWby=}vu z?U=@_OYfHAfjDmGQ8hxATuWb$5blJx7hDPt8aYcztGSNvTnhpVxo>h2z0Ba(8RKEF z%br0@zE)Ya^CpHXQRjOO+0n~oHM39ATRR=Bq8LoWdxe%XKMu&ZQf&~nAP4NpkTHs! zy@^_N?4!6tba{PBWUPC?BF)KbZ;(IG_#Ar8TO4q7=n3EBJHC}kp=z!zF*HR?_Ecz- zDI#mmD>0ml;TvHemFM1OHNPw(nD8C!tn&H&vuXf_i_=Ge=AEz!@3QIxk4O`2KcDI( zo;}y?mt3sD0UG1f4ZnU}%Q|v*@g^d36^VmTRcE}i0I53N&h+>Sh0$A^c4FR{R2;nr zugLw%8aBgnQpcfSZILOiSi7D9f^H<3lrgtNg0?HOCh$qm$eOp@=O-E4bfheC~X3U>a_2S?khi_eD#gw`23T&=kg1 zH7tT{TX(u3l$x(L&&N@NZiYd;wgMJ-j;|hM4^gSl)K=5`}%8ZiZ zkM=qtOa1p=!(e{*So(m#HXL-O?k%cP9YbToyxw6_SiaZ#g`X#@|@Pk>Th+&q#*+tDZkB^Ksx0x+2n$2-|e&Ax3n~hbgY%+c1 z%O{7|(jn`$w)(cWw|X4oqh%;GsVlYyuqk=0MSN?HLX_oY{kFciBRAJ$R3e-w(kRt~ zpU>_c}njRYKhh zQ#OY_RHdaZgQ8Qz3N)H((e!Op%g21ry2$3I%QC+0l0k3ugYB2=5gi-H>)!USvNPcl zyY^KdwR9z@SijvCp|G$f+;+I!AXkNTTa@S1kT4BqE9_3>3&&faUT=5g9+LE~y)US~ zQ?`$ck#@rgR6~zB3V2@~c!#jZ5IrFFda&c{?4j4_En4S~+qZ^MRGCb3<|ByqnESL2 zd+`%lo82CpRx*Mi658%5mi^X#A0+AAlU`Mw(oC=8?LX=uT$@6o8a}=zl6gxSOq;iq zt1ig9E_;8KnrFS)WH*doCA*)SLHPl+t=^}R8AVh4U_T*(K5+W~}8 z2yDoFv)Yf=Rf&4%n5aV?K0T3V>ki+$^S@;vn8I)kmX2t!4E6|jgd!y+erT6s^)oh1 z2#A?R8$=qxr&@TGqw65{qq=^s9ppso_d9fZd8>`xUrxY`%5U0Hk2L1h&^|n#0#~Tp z8!z`6K-?-*u+QZ!Cv%4fg*p!TOF6$RIaW5KJmC%0wJ6l!X=3&-60y<1M*;~cdq+Ds zVmVmY(0a~QKVb~#kMDuhC0si4l%;>HMZ5=pyH$X4C~`}au%tKUd#D@9j8^0f`Jkm^ zvt?j*{oZY>TS1z1Th;}iRf6+EfO$`o;X32y&2+tggF{k9tN1Yg`VqI^#hT(6WtXZy zGnZ7kATyU(IW#j@%EtE*4a~u4V{?L{f^2&jI~QK9tF~1I^%L$u214Vv@BGls5=3L& z8CMftjwoT7r_5xm>2H{o3|5&}Xc{QY=%L8g7Znm0WL;FbB@K_B%*^ZBy38uC9}dK; zp(T$NU3qCUs-vWs8?nQw+k{Xl(NT~N3-e6%j$cF_N*iuN%XC9>p{$)H zFWW$ttY8D(YRnsbMQGe(qaN`C1XIjQTgN4({_*0#PWEauO%> zymh~{gx7Wwcs>b)B#e=NKFIv}&1D3aD3JPcH0Ha$&Z^MYlaD;R`D5Rtrdh^b7KQ(k zAZ7{pl^a(0A+#%Mr6D|MB=t9_YJEU)njj|ap*=rF6?|V7K^<`d#u$z==mgZcV-;UV z#71+`aJeRl9Z89dOEt)K*-3Gd6;0vDI1B1e=ez{>>7d?> zmE%WwtoXWxjD7E_QkN7ZYl4WHAkFnp%|ulP8^#tg7?FjK&Ae4Luu~? zp=5)MQ}cs#SJ-STz`%o6YrVtPHc2zJ@I8$!C7d^5yb|SHHU)(=@(jtKR-<&PliHVl zq!)}DE-cw6w{KiU$Z5uYCOQomDkp1Tsb$&VtaVxx3)ActZX6423+KuW%4jmsk_fCR z^l`+zdQ5HckC*#CNXFta;|KS;IK}sHBR5tdm#;z@d?AIekRnNVAcZgLS^MRLr_LMP z-7F=>Ap=P9M`UHlq0hhW`|1%$aHnk(T9NU?!v)lSQH+1h~svg{nek3VJ6JvW#B56=fg=sGF$UW z!KU)^J^C3@!*JJ572f3;>;Z*Tp9}_Enk2m=`7T3OM5(Lo68R<)p0LX4scUH5N%H51 zWM}lrb1DMNb$J=qMf6-J{Ijr%o!=5OYf|>#bCUC1j-yBeeYdoT{hyP-`zt&?s`cgSTFV-c1 z%h=8pT62a!`Hhh?^q^Tfvc9~+fPsW0)BewN+{hyT~5=(tzU>Zr-H>)go>)R z6bOjYNa#&Hh9OoLYV8Ig7W-rl?!CEzC)IsZJQcN$hby?MtfI?%DX8W>JK^i<6_j6B z3I`K3XB4^!k9zW$TsPtiYt89zM`HT?!&Fmfkn@%UNRUfO&bQB~?k_cGBIjxkj(jC= znye3{3vzagP_kxrD%j=CIYSmk-IsPliXe+C4bQrkXS2fqmEiQ%9nq=RuP?*(ydrB$ z_Az$oWnSlt;qf>neJT@vo%&KKb6K`5pjgMJlia5>CIm;gB!RI5+>-NAce={=9CK2L zph6`k3%;tkiFt!tz4~>8cvHe~Y(c2EhQV?CIOzLExcF}sla@Cx)3NqG`nbQ)fE28Z zYEGj0IKQ1x5{noex!1Ns_MOzMRg1m#&9z=u8ppEy8|{W#tAKqA)lDVBRMr&-eORU3 zF1^=%K7C2@uOyhMUS_kE{WN5wCo=hwkU@)ciCh&bYmWt9C5;gJr8|wf7(;$rMLySb zJO=g9>k?s;)6E!MRK_@Z?Irv3H;Fla+_eIvgHx2e>b8&=_m{kww1lSXj7qA5g^$T| zl^F&%D=IaguOnmoEeQI)6th&A@AWxzG}aaCEr@sy`fO+I<``5InpmiC5d3xj%* z?}1-;Y5;dx$6a6ap$F5HL1u0w-Xo}KtwZ6yTE9saU&i2TJB8W$P)C`{A$fW{K3D0f z680Q)jmm0mgA@-%X*IN<8zPQg3Q`!V(vWd$p9sVq>FJhAc|g~9pM>9N?>e0fBn;tr z8F+q@GY+td390tJ^CQ;C7A$Gx@bg|;e7h7`1Jd2^haylORuzroMG}4`*K@qbmPct9lEq1YeZN@5!#Kn%dsOX_Q%k!E!H7?oQ=6P zkHNU9EdwJLI}fEH!>DCuB+9#Gqkqxmq(S7uxWiDuI!(vmvv+Kyo%kJY6$L*| zS2yP6s954my#>EF(WW+mz`AGVq%NqBG~(+hxo?5v&zpBqsBY7eX7JM zklJj@gxRfAEjHHeNcW3F{NWhR!0d6STC`l&NV5I-3COjJ$~4r4Q`*4BiC{X^`1hph z*^Z%uNk(NhCqbS=js>pQ}JrW`9F$DkIu5liYdP$9)LN;(d|lj z)i`2Q{PU&1$uCGmBDzx}gj+Lq-2qHipWGJQkFSEvbF?B-^)=(l{*+VxW+Ek=IakXR(MiKQ<~0)wb(8y4nNdY9D={&f;3j;H^|ZeA7m)_c5Xb8A z!`k!dIP7y2aD!YKg2%GMw53?+!=6m{5nr+^s~6HiDJZMCzO@MOJl`BT(dIdWUnWnm(lU<#H*TPk-RoNc>~ON3n&G%@6e3 zBqgvlAN5ze?FQtQGDsR;xOt2&QlZYh^1URXySe$^-f|2+dCTUkMkY+#M4H#&Kajd| zWXm-GgN-*5rn+=-W4@@uWqZnBq?j8?W9Tlt*tOAxIfy&bMCE#sUR3cWOSrk#T3S@b z#Mx4KU(7Mj+nlHb)^75`GL)u4SMI|P4_(c%E)E#G{-q+Sg8A(aA)T=YLsEza{){`f zk_E7OxHxYua)7#NT)fDW$uG z`OTLKJA5Wr7-yb@Xe7fsIFOMz!%P)scxxvk_D4rE54c-$k&>fY;~P{2KCZ?H|k~ly9nLkd|vMm0TVV!|6y@7?W%kAA>N4*U&Ws*W3_uDAUv~21@y$Z_h_?AO3v)+qO zrPVFAx_25lOz~l%8vT2tVcE*Dec9UsEq}iIzDa%&q`iNcha_3Z7A;xGwCB#v{f_@O zMURRncPu0$nuuwA>Vc`_H;K~br3)P%w;=nBAu3zme&<>O2iF-C5$}A%Kod65bX!>p zIRVLF%CMVWFFdUA0#~L9AGEmOvUF9qy}O~Pb}Y|J7-)n%Hal6tX1+r+u)P4>+U0jh zVoRVM{H2O)60iS`XH>4?I3tYZ>|p}ctg!O70V|qkLicjc-pP@Dydl5b!&vZFOcIG| zJBVjq$MB#-(Q^;({y+w%)?$T8d=7?9pp&xU*QTEDBD>T!AWm+y?!)ldAnoYhfFJ&C)yQ#nhEhDCWfa^Fo7>vocLO4AW>N?H_tfL=7yCf*$~f& zX(!-vl_8H=U*22w+AXT7-fuF-E~bzoGRrANU#hP=c?L@o{*gYl2zFWOs%z=}Zl%51 zMN9UQqaF$?ky&w8tbLI^)$W=U_&7{_Bq5s|QMUep5W$%0k)sHeN7YfIA3Ma1P^Xxr z9j?T&Fte}!2wo?|t(1t0Cy^(-X77Xa1j%7{JnW};Z#u zT-z@LG`O7_BATyp6L;K9&q=I)y^{_|X1Fh1*KyXZ;`H+~fh=uAesX3Pm)Hp2KX|`Pb!?u$?;d-uo z?D3pj#Y;stx_m3Rotx?Dq`f3J;os>$Te!%abH8FFvvv-r->Z^2?z|;z_ZpcQ{|?_x zE;rCc(y5S(5e#h@XpL(ULN&O4jAxMI7B;(bQNQ33T{yOVuBQ5>DXjAWnnzYImjdTL1*V9mi zP{H1EUfFbTDyg-j@nV&BZe@t;RaqjaOU=!{+U1MRe7LEbi*Fh@(>=tPWaoa|d(-CJ zR`Po7Pw!6~hbBr$A0}5Pq9!a>YJ4fGb~ZzuMZOT=rdu$4tZH9z>bvHeS~yTWXm;|5 zKVdmUKa@!8`f_|vJ`u}FWv^1Ihx?%B^~TefAJKHqN-1zJ|IR6^8AZP&%k`52h#miFVARd7| ztQ856!^={IAOZn1Y`tVOb^mGV4pI;+Lg|N~bAdt(y&^Pa_)?Le34ua%y==5BfkHIB zTC{#YoL71(LD>S-uk^%%It8fF^)k?W1(4uN`Gc+n&JY=7gLpw32qRP-_#i_>2FV~o zP@Vr4dZt1U3TW2f2qRN52n&?tZ-kyH7nCT_;b(-FsTG7PAcdVN6Ql+*@%w?5DG?+A zqVyxj&Xfw02TAymV`Yj334jp%da&P7b})lZ{CY6oi3XX0%KUm>zk4SXfTjx)5P0Da z4}q0>&AnmqhFxmeMgAEoqP~*zCYS9;;}6#6=UU#05??!2grl6L)P!A6m1y(m>A?i z-ht|O)r9uN|0)%25p#u00Q_pj7}P}5QSIj>5k%(iBoH(v5c<+uBB0F3qy z)L{);5x~b-kpneRbPx;RW3J!{xM>CzzdSBMLw$Ly2qJvFLM6ccwj)99fTkUMC)v{dcSFk4ir!oVySdc zk$~ANy>hf1*pz%>vg7JkOOGe&j>S9ILHu`BvUfM zs5JPM-yO|#L#PFrvqw;w45|{IU@4=3eP8y4RM334pex7zaz*l3?ANozo-(S)-!Eo+ zjp1_lxy|uV&DSgZMJ;5$104aS!K^m3E#-xq72#vELTZRMTCK*&xf5U|Yqdl%QxV|J z5Vclgj$8w<2s^T^TA%UDW{aReEL*h>V^Hn~8E7z;Rnl-?+8DQtJ9xupXPr54%uJ@7 z{oHD2W4tquY59@Eeq(%MA&svgZm{Hp%LAUKJg<)k9XM{b|J0V3fUVS#_f1>5g(6KMW{g?J8EnI`ew10x zVQ|dI#39UXaFp2&7PzZ>n+uU^Cu0o01IuINmFrLwky*a8XBD6Tb90Xl_I47dfbqe5 z+=E@ceZ(~20k9PJU{7z0`0$t=xB|@lauMIHo^yE@CXc4fG=Zfk>kD%vL#^UL(L-xj@ZEo3Hn%pU;wF0o#@)@2?^Mew&`Pj~rU=vX=T34U&x&CSbPqEqT&tD9F5cc5G% zs~g_ja&S|(tw(%dQ~NejZm#oeHHUkMC~xPsxQwh7=b&-uCU>V`gsn^Hn79lXdMfNE z&d4KbD1yz`n|7gNS>UGL?N>6Q9PY%+-cz~So7rw*W9{7gAQ|oTv$wg$RxVy+@f-`o z+q_!SjSVq$);I5DZ=rIBZ8_VvZSQ} z5;q&Z2BO&3MUEkZe{R}ow(kpbqzEY++VBk9dnSGV>e$Hwp@<4+^C>f)(V$rJ!xY-0`GDZ ztyaX1VS*=*c9m?^IuFfAn%!c?5K?Xb=ejLELu)SY1Y;db(5(rhp3uDkgzpy*+#ZDQ z8)BTnH|&G!X3PT#;BvOQn;3G006=^6I? z-RijGEgE7hW20)nBlxy+WN0vRCuh;#h zS7W*n``2UIDUubG+J*{adMVoa2bK&1oOMB365kZOwBv^;!lKg@D9N3GCG`trRo>`1*OxdpE!jk>_cv!W2?0rHCHh-=BdBL(ge%L&;Db6L5i8PWs!4#8=r zf%Ph?_WjkntN0E3R_uY9R&9u3!N+-gWL~&CBqyxxO|(me)0-vPbWfyvq_c!_h~8n5BILSEW!neqzs4)iL1gXn|m z(+tJ!W!i+)v{=LHM0D2pOB<>Q{vIag+&RYng@HSY^(BNOv?HV=lp{p-YTa;V!yHn% zPxTu^I6i$9%!baRiKW4SK;Nl8)mGEBoh6VO0r#|L`r}R(+)eS$;#BkFR+GmnugU!8 z;#8&Oa8uT;M>*YO7Q^2D;zIN0*1-eSt>eWZXI;5x_sITz{{GMXxvKuhd6@`{+`&2H zV+YE}{i^+p{W4?q$GC?g(dx5k8rv%TY4pX+{18iyX5n}0QD4#_TYK}BFxTrpgom)MQ?qocWhz8zZ zE7R?1+u7+p>YVdGLan7~^ArQP8y=c=em~TTy54?K9^OdQE!h%%H!%#CO2A8c#4eu9F}0<$NS( zhPQ6SG4@a?&FuVPfU2{>`MPK_CN2Apb-kE^@(VRdaY?L`S?V`YB|;ommyOc8lp|(l zTiU#jJF}}_KUb?QjPIb-Wyhr_qu)B;ayiW0SL}ab?KR0(+WoE=tQxss@>1>n1%q*< zeq2<(QUQli+;sPM)r*dSAYHaJ{UoO12@|9@*$=R*W?8S9SeYxkLSZ_KgmORb7i{^kWU>Tdg;_#04Yvn#0a5Qw<*nHwqXSn$Fb!)4 z!wQ}371jc)!&8Eyf~Wym2&n{J;1%0KUINwfXv5$32GdIo*!#j8X63vmF_5W3upFdc6Tiqjh?gQ!C>DN}k1(I0F!?z?!p1<6@H2dT@fr$-pBD`#2hy3J_8atPXjOhvG)P7-dNe2> zeh4wRQ3$?o2v-nv-=Lfz*p{HcUeG1btStyC5KKByp1D)e-g*)RA^ens>E#wHKQ= zn-?FX=Zgo3JHji1BTg&AE1IJ>N0dhhM|ew9EyZ5(-tk`8-r7)f5X}&&a2_b!{}2&7 z+}-P|mq+?bxJ#lfsNO^ni*Q3wi_lGoZgA|-+<$ln>*)2-`=b|DZ*ZVxAS0k7Aj!Nj z`2QuFmaG;wZ&5Gcr&lqwHZ&nDAyg9rH@q8+6T}sx6`vK672OfZQb-H7*D$oG*D&P& zAQtE}7z=0%7+&aksClIM7x=IiFDxK_!u^E)NkU~vm_Ef%0EGgj3=QX1;C0`^t3y`; zH;t_Eau3P@ipy)ig;j^D1ZEn^42l&B&+EK}Q-{V1rUX_6xe!VTDys!Shob}u=l^N8 z>ERNP2cYV_Y11*bAZEQ;(=m-8le|gGRy<2W9u}=keIM~GPCSozT;gd#k8mw))7<}y z2YH{gJOFv&{~qN1+aM5ufra6JJm33|WHj*5?>_>@e;z0QSF!kiHVgc(h2a0WSKwcP z=zmTSH)ngx06e@+|5pAj@W}Z8onkUC@7w36$^WWV{1f=ES_KmeE7SjOAHhmBRm(M2 zbdSs8t!i`VxOZBdCsi|_v0kE4L*dOph!c*Z&lQD+6B4W*Kim}QVNS?bb8}!JLSv~m z1b1@sVyW-FyTahg7^UwMsv8pt5C`vQj?C}#?q$+TYQ)zfmF7xPND)&$)Mk92TQtER|+dKA+V>5G(6yug|(02iuG(q0!Iuqx* z!xLBBeZJq4<-rJH~Ad-5=USt!Pm zH>}Z|`hcjTM;(Rnn~&6dS3#TuDRDWGY~x^mzI)D&iJ(}|Tol6NUfpJYpV&1+_Mv0M zSxT)xEhzGV<(RpBmwq;&Z@8+`omVY&1AM8kC}sb9s#vI0^z|8?-20Hes;soe&v7X) z7J8ao4^9n_xO!`MA+cIUG|cO~CA*tU!7A_KMEBMhno_NI*ym8csDEoawo4(l|t9_Gmu~AW~~B~GB3t-^1QmkU2ddY z3NM_s!*aXAOY{`E(ZbffI(0db^nZu9AP^=cXL=*A;u9UG5d`%m56-m(2ssB163~rB zdV4eAe_gup^=}tWut-%+2*)^Bb9z{tq{@lRjS9%ke>2?q3YmdOq?wC7v{I#qRxE*Z z)>4(eN&|^-jd94~EAnSDde&mq#dNbDVH_X&qA&`%WHfqJ$80jY9r^q}B?)iLeudre zIXFnu6-7LHaxrpn&zq;p7`OvcdiQfK45(0M31o$_K0#9afj7vra z{YK{GuOpwiJr^>#9}W%Oof+?d|IdEZNA$LEY7nE~x~U>yW0w_YMvoSWeqp?^F5h6q z?oklf;B@GW!_|yd-eBjjSDt>o{R!D)XJ$5xjpglSy4n55jEHxdiyyQ7_cU?jO>hIG zj8@o}>0_|{2?CZrRysev@!G9w7uo6)!pV(1)7QDIK1IL?W?rR*F{?S;SyFMNgDk%r zu^6C!2eT)X)Xh`!o@4tYL=aD_4yAhYl~=Poz$wOZxSvaZ-w}NhNN> ziU(jO`&}hXk#c_$B?kJ-$~JbrBVdMy5a7S<`J6!7SBMm7PTc=%tX%BVYmhA+W}U9t z&Ja1r(M&sZB?6Y&D z-fykOKsH734xzx&Mx)tD&2x44oX5FP`yg_ll+VhREE`U`hGra&qkMWthlK}x=7NL# z{F7Zh1lCrNUVAGVm$DS@-WHjjD6+vX!*4=^A?x$!5}KBsY`X`QpkR6?5iRGTFSpzH zG3HGfUq$@H(K`#j_T)#tK`MaErGH1=v9lc8#3MeY>O=ey=Y=RM63!t(ku{kd7-EL! zn^ITM3+XyN6IP35EPI(!NUs?$ezR@C-;{1ajdchFa8(E3{LqY`sufK2VyA_uZ3JPx z8V^qC_IBjdBlxz!Gm~i{lw9z(Jxe%CgirYppKloLfyXO5aIwH|qxa_5NN?g@A61kD z8IXNx+?|e@oM%!`%NKEI8Fd&pLq0t^>Fc<-I;{+MWaHJ zc@?N_jO>hvc9(1{V^^dfO=AKeJo5KCWs#(^Bekb@w6L-{M77@(sft+qdsq5etc$CUXCu&XEv_RO{R#?H)79Cwe_b;N^mr-yJ7@Sm zl-Q27Oj?^D!huUDr#>LfjbN`{5`o;C%Z8ZD8NvS6+*xhtE0#+FLp}N2jw+&It2Opk zjNXFry_>qO_$EawVK97<8$4zdjBgz{v|+cf(!5Vo=I`+(5Uq7E9V4{ADNmfzehyV} zEee-D&{tZ3{OqC9{t$KlFlZl|X;7XQr#1Efmpv|LR}iDxCGoZBdknlkoy1o=!(W)P z?rc11KjzS5=Q(fHgKXSAp(_l(%MxE)Xf!W(Ea{95n4ZJT6BqU(scYnH;^I#b5wN_f z8m7+`-i-U6F)m*ez7J;F5+mpNCKRIjZJNNNyi;ubYrPG=EP4M{8JP-b4Fbk6KjQ_y z!=@FwMbNuxcVi6#Bj&%r}ump9V>bq z)1B*CCHxi`NehFlP48oCi4=$y?>iP|PY~m+A{hGbTB6sGH@JSY=6{alg4W?d`7i++ zI3*n;*uwdMR5G;WpgTYb!fvVT@TjmjDB`eBXi>b680wuo9C=rB4Bs$E2_0X(?`l`+ zd0fSCx%$7k3Gy%O-5+aR; zSiSHMPPzT)rJS<4TyN+)DpN4>W~o0R<1NHu<{5nxgWw^cj*Me{SG>ScQSI<{9JvTZ z7=0%DwI#AwarfwF*Q2>ul7U3|6^tN19;Tqk_Rg<~{rauoL0QXmIM%u~R4khvU*|NM zZpNRqJ@9BcrW56oK2Y!(+@N3NR46c^#cOlvE7hUy6e4C_FOab-K56NO5Ko&o5&T?n z3b?{|hF24U1?iM=Dm#dyAEcd%>%o}!W5PrBb`ZZcTg@S%ZapqOBZ19B3JmAun=%f| zC!~^6T-48MbdmC#v;E?rJAK$nsHumo-R z!|qlIX(7Mpu2((6rC+p0vTtb7lzZA5)f6n1wU+zn-FounC7RL|B=k~RuhDYxeu8r4 zTv-%t+q-^SECtF^OKSLfoGOpXdszZ@$Xc?4jq|8GrYFD+OQL)xs2%1kN zjwCy7?*=Y+D(tP`n(am+HOMs#VHXqJ6v9z#LGlhmTyXI-r&AZVNOD=EXJZW^`r_@2 z#AnJDCuS>1`d?z?wUZKzgdea`iM5~FOTqTzpKvxRhhgS;KxboJb*Xa5qe(2~z~%dN zTlG4xABVN2E7`ekYtg6E(%PG7v3H*LzGcm=R^LIqG@1>gTL1j$R_ws%4{>K{2&4wTHb)4Ea4Or|SA3T;C z@pPJUGH+qvyKIRNzB!$rzDhqLE!k4V{ei&BJ3%6CGtD>+b%zoF!6{V^ajs&!4RS1G z_^>tLL_>eqU+hvg|BC>2Zp)BZA9Zd1=&v!bKFKXU zU8*twLS_H8y#F`e|EK0ifK08emGNf-oB!>$NDTj8Q3Ig=e{YM#Ov}d1#K6k&Pa`CD zT6zXRWE1#$%fbvaLZWB+rxDUyHg=%R5*x#xf&a~}NOa=nK%XapxBvbY{QFz{El}Y9 zRktL@f0Z!*uicUu|Cxn9w-Wxl&42(nWo8Ei;Qlnn0%lU&oPiCn{uQbNtUtFW82@Uy ziJJq`Z;XIU+}|Sse}Ba4p3eJojZ)W z2QvM;JpMpo2CQc&tbiIG0N`(cKc_t-0U|L1;&o540bESaNPxdHGCd<s;4>8FKh`r8p!$r=&rn!_%$c8| z05BMVVn2ZfjQ@}T830J1V*jz8kuU(UfyzI{2EqZ-eSa-rZWvjfp#WJk0`h%-#{d|N zEYDDY*nooH-yxt_j4aPcfbGf1@(cxV$H@8&1y~r2f4A?S`2n(HeTKpcgahs_{q^}r z8<6!G3L6j)n7^lZKpj}0p#W=v5jgkn7_fvGfob_`0Y?F9jZYRE5D)nG6ahd6M0q+A zSUGIZSb%advOQz@GxQ%6z<5Ri)PRxgKO}(h3K0*1T3d#N- z6u>3NGZbLAFaipWe?bEaijm_P3b4xX`p?)i79c++V8cBj12i##>i@L> zC{M3=3PyjKezyHVEW6+fCX$(rhkd}pE1D86ZHZW18Vd{ zy?_^>Do@l4SbxTzkpO#w>4|!QF`z0>)C*XD;{9DafCYel;$EP(K)fgJ1+V~hc;a5b z0*t>)2LKJYe4<{Un18J2q5xa;k8tSUq5zb@^u)bD3V`uk6`um%nNw@GxWS>f${@y_&w(X_zzZ<;#Js?Hf2`*T0&2(f#JqqPAlE1A z1?m7yTovU5~w#PD+_BUanj} zKiAd5Ycr}qWW378MbGO8&-(}Mrp2a*W0%YOx+%N|LfcPzrO#|zjsfBJso|NnPCLTB2G z0Dt?}@Ar3i&-V`I_U`57?%~_Net)`ud3wBa!UwU5wc`SylNOyaC zbN6_A`+1ZL`547{y}o>+%eUJLd2jOa@c4Rv|HtQH-l6wK&rdfGZrkS-zd;}5dwPC& zdAa@L(`?`0q4$v?jD}e z=#SS=M0$tbM{>$q{qX~DT#%9ei9q=fS^xiX=bzs1{Piz){tf$|b?0xNU!I=tZa*{b zK|V3={p0J+%jYw>y^!}KdA+~Im!A*!+dK5$=<(+M&fkSa&1#sXR7aKs=I$^s&v|P?cd+l?PIg- zVxOt5iSECAA~*iwyTeLlZ&TMy4_`ggIVl45kNaQf_xRP5-9P@pthl{@`s4BG=fisX z>dEe&$=_Q7mOB55F`mDAE;pSVzhwlu06!eq%U4hJbZGc``^WPyG<^N)$!?#Yy25w2 zH$RgQ@{io(KXJLJ9R|nU9mDU9hAi7lXnaVGZ+}^8{2-xjnUH3Cc>04m^~N4=BI+L# z9KV-`KgcN8>+XTs{YXN;P4>36FBcxJw4J?7g#0|&m&=cb=UAR4I49<_sABhhF^Akf zko5O=H#tT>Z|uv($6=8BdoIu~^5gbHfP4`BlbLIm3y*7#+vyDt|aN5eea&i?p`NAA8{h}=DNtsm}pcyF^^Lgeo2g~+bj!$Yd( zOm>NoyDt|ZZW^wCc-o9_8+)7WLxy}2^E0dP;ls-`+uLk!Wctu&GR8QzUZiUYT3br{;#@)8hBHiUv#}5Sfvc%*Uui( zb-V8WG0E{KZr3YepC$bKp;|7vasMGVzKD#^^EXAnesPoT|1qiYCwRU%BRlvZzxF4d zC%fKG?29&bc>eDG?!!-dBjT5f4KY^%;YVT4U-tFog5zFD3>BXQDt?{qLvnl(-`~v} zyL%BDf0G;++duqclH*UX{Sk@xH^0dFhp!hNi?rV#+v6uz6pnpk#jhgbOq_dB{a^j0 zhcA~Ne0Bkr`=^@^jd?LX)%LctFS=y>2(In@^VH_gbo`JXUq#1>{QFn8?Su8-*zq3| zAb)}#Srq8_aQpP(D!tM1%LT}xm|rTH|*hs$@ruB@%ZHu1X~pByLtJIG9xPA?%7vy{_$xiwchySjf!6{K<4-z z!{BYQi#;B{UV=O%rkvRGa<4zn_a;L`g8qbs|NC40L(FQnefiP1ncm3w_3~r!s@prE z^^e)!==kLl*!hXnZ|I-cx{g!hMnd1uC_H~B#Z{AKy^ z12bN;NgceYm=6~D$3)1VASBu0yzXyRNBkl}o<2m#7ZLKPw0p^eG}{%Ecw@;A5%N`p zTtrju;Mbk~V-n;~(D7Wgd#Qu>h}Ff8&tEP?kk7TgmpXX&nBM045FvkthJSirs%Sp) zSZ{OvVFC{e*SU+A`HijlQ#HOb3T8_k1rzPn>qaS;V->k>E{pm z@l}^>ftCkpgLi#)T`@NK7b{Mx1pyz*8vJs}o-u2lB9Y4g!H=$gK z44JKu(m3Mn=G9V#hMr#^EcWk}5&T#t_TQ)+8(shDpKrha+dp5$5>MiwkIynsKTiEZ z$i{LHYRY~;H5Kp=O}$(APyc-PF||nV?VXCT-%S1d$Ez~Er@Oy<3IEE}_ut-kUEEh< zK!xLbE#e{g_oqMZo?jn@SH68RWF zTiNOFr~Zo!{_<&RA>{j;U%2e0Dit^W>EUbn`}Kp~j`@$Lr(d{C8RCCq(~QD@=&0WW z%FV~Fi!a~Y-~U2zyCx4G6{0`@JsUEEx8?xfKUJ3lXoz_{&)Q_U;qS6)`J( z`-#t9`4S4)Zl3QSUVp#sze@7^PumuZzEyVoqcj_fQ>w3bBC5Z=U4N0qZ$HU1{7sVn z!f7ugC~{ z!CyZST!{Pr<`-MRu2r49KHoh49Si9%5?l$%yHI%$uYF?C|9ZRf3ps~hE5=p!eoQU= zeRKcxyKUbpw&`~Lp3nXw#Z{Ml%q=(hz$W<3zVp5xpI-mYY5!G{e-da9&o^W#iTNYV z&(*$vx_i3)QXcn!;$zzaubxo+JazX=VEge|M&fHp{>eh?y$x~wySe!gk9XM;Uny3U zro8XF(|#tkf28>AQd4_U@cgwTfBqo3!+yE%dCZST^rX&i7S>+RRt9-}%hroj>jz?T=G$(^Tri{onHh{vyG-J0DX&-FbnL-~Y4!BN+Vh zdh^A`;r(ZaQ?&kubp3Ja{GS(6<@HWw$yc&C8TGMi!FzARewsRh3+~gK#LaJ~{;LH4 zB+pn#q6@#7S>V~Dk*6=_?@tbAas6AO<2Q3xCFP;l?>GHd8T^xdR*?Teg67Aget8jM z;hfyuGEcvh-k+pduRC89Yy32I0>zrhlP@OtXOC0(pB()i!I@95FUgkQZu>7%T&>MJ zhqDU_QqNR>-FNZ6o7>mFbJ~BA#c9cpxz(01OMW{yq2e9l!l7uaR2fvt6_;MJl*@hV=w$wnt!s;IJBhcZ&~gB`HvT|kLRzY`6r=P=Hb?Jq@S+X zq8ma@ujc+*nt$>-A3R@p=)L%_*E^a&J+dZ#%WHp?=AUddCNYWn3$LX;ksK$weZQUi zFY>tpp!e%tmg3I4@t^iRKIbQR?)|kifBfWldi5+`cK`F-?VEda|8VaL{C3}ek>;`t z@B4P#kB<+lZU4belLYAoIF7$#Ed5oQf0ApC`}Owa7n-+knV1(Z#=kb4_4vv2TzdKL zmr&ZWK$z|JRXXfTY5vJl<7~*Q{~BnJ1`=+%@uh~pbKZZI=AY!+t%okY9PksH7bO=# zd{qPWrIN*^dFQm-5^vAHgc+Jz;Kf@vM%$NC{FAMATjq@_`OUTk(7jju;)oX0>|@`h z-fn)4GuU^&_~X;d*GiVBPoC#psW-Wa-|Sn>_>J7#*K#@k`hDMbCEtD@MHD-I5KsF% zbN@vySGDvpH)g)=F8`>-mI7l!%CmlLOzY{B_sLiyQuk>72Z_pR!G%7h@wJ8`q4BZp z(rK(9rs@)`6r=vw^t)e^nc#=j23f0iqn6oXnFeNfZmsZQw#gkaZi!( zR{pNt@E7%`(x-Ql3rUlwzi`^o-8avD(&YD2?XQyjlT^FU$9?{V(`K^>bnr>O)*TW; z_}F&|xQ9If`Fz~%+wH!4edVrvr8HM4^)YuDxSL;Ct+~mZ`#$aS`?>!j&4nf3=YA*! z_ssbJNwUa1+P4#V{o0Js^CuVdp%mQx!_RXs{U-u*|N6zEMH=Q~-*RwV`(LhDqQ!r? zefoR$(qEy-x&rZ}_Er{>fH* zkcPW^{e{<>yU(=TDXIAV+<%qkpXAzOdAP@4cx|$!7hqy7UrX~(J}Aed0%&g=e*d+z z-+uMWm%tugZ|+o7T>tU~pf~J)))#=#`N6&R1)#pGB^37d37((7rSzv4{B55pdt2Pc zGC%(Hk1x2|5Xn)Y19xHz_Km2wkCI)$zr3}$K5F#Q;thCf@$KykM(<<10dFn7zkk2z zy~#WB-sbJ|MHlUgro4UQ=)KJwHQ$GM1OD6OePh5s#}6Nz@fW@V7kPi8=Ev90-U$BR zUa{-?t$LXMU#<9k3k-kJ58w8Ce0*g%zwN-c|K5PN7SHNUUifF1`d2i#JYcJvxACs}IF66z9kK^6QbiB9u=6h!s^4{k4 z@$pV%;k}J$#vAh1#?uE=y|2e@xDZ=?Z}T9nqN3+xoV$1Ay$w0}N)3E!^Ny^IPjmTj zprG34^?V?2D(tak2WoDbw`^X>lLza*SKwRuP0$9a5t&a3{^<{f!&^Wu9z&##{j z)wjn&^m=Q<)bUx2&+GX>-rIPZ``Bl3-i0Ka@Iv0(Ao4R!^06Lo|1RXcO|e#f>U*1S zN|Z0;z0K>(b7e;FZTgzzg}k-#<;@!V#s~5?PVSzntxt1(AXl4jZy!zkSkDLYHqMVQAoVO&z>_ zX!SQMC=u__o_%72+m>(k+ZB9!qrtU;|Mg!c!nYRj!!f)sK^c`;J`?V@OL#wqw1Q%_Jlm+s@W zRgyerunP*X&uKaD1fOr@O};(SWHKCgeY{b0>V$|Cm20 z&~QuLSVoV)%*|MM!e8>w!)~9%CQ6d45>||%GUD|?oekvfNd@n>kmnl(eSZs6vn!1c z@)AL86reSG7(zJrw4T>Lx8JT`(@v+GZ+zNelu(bk!AW9~UWkz%Lwrha3n+ao=D&V4 zcd4e{>zCAOGxzrojpWlNuTpFf`eXfWP%ps|_Tbx7ZKgcCVhe~cDzXEpObZb9RAABq zgq)SReA7)N=$U$8X0Y*}C=Q6}deQ^2-XW%KNg--^o6ey=`LgaXpW?my26^yFP4j8> zB;#EhsggD|1JxU7eoc3a zJ`qK zUNgTS?83ai&dw}nzDLhwj1~5Bci*bSIjafo%4*4hbx2U7 z5-qwtqtf$u?ymZrv%S~Xip8|LdpHMt<2%S_Abzn8JI$&fw7{{i^{U=U4faNoKeoAU z{C&xDtsb6v@{p&y6nBW{IFvw`8x?_JPs(~jveM5zct)=HS@z_xyim&)iRm%lxn#Iv zT(ABoes=AAEYNOU6~=ZOaS^-jrgNpZYSBsRuWGyydprGBzaAob+IER5U!iT8RK|@M z6Rf)bm&b4Gw`UI!-x;=W{qD$>wYjfudi@?8=fO}4k9jRo{=9)63t|9tngmH0jWN5y zk0eKpUMka!D6hNHL>O@s@WMMj<4lKu^!C#c7X?0T(=;rro<=lgu@F8Ll>xX+iLpYeo-0lw{KSoKkBd&<#@~if7|I&ef z6ShUHJW|wseGpvg6T9R%+v{MennE0XH=|Zc$A&PTu2Xq^omA7x!Je~wd2vPRcS}C5 zpK2uBLshvmXCzm1+*5_zP4x|(@aywSt9tSh>x}*?PguW4=X9;<{@f@S-adZg#xA?`tpa+n8p!{O2o_Tq@Ox_@?GhD-v4cr|hW4pZj>x_f=vNVi3!0&btK zGk06jH$-XYy4|sOuWr1wGnDM!wjv#*P_OwtDn7{Et0Bt#-==%K`r*E_N-6M2ryq^5 z`JQ+X8wn-G21x#xV6GK0cpWG)v8$KLMSYy0La9dn(U^d~A>Q^dNjJleVK}kvNL1B4 z22w}a63D!CZ^-?t)rF|Wza*Wy5Ct(|FR$sq`f&!e!pqgSHult22>avWU`IXvNryRX ztt_*_NiWllT`^5(?s_@JL#daWo3T_^js|iL{x^~nXV2LjU2f`ih@zFl_)^b~s75c( zhow97nAP>pv)0XauaU9+BrEZP03D{v{s~pndB{llRz2KY=cbdo= z3PB$@dwLZ*$NM2S)X5NE%-`1fRFN+l4`T{qImp=v2FSk+;L3HMit?Xhlf9+d+ghxX zoPj*QTmuO>V4O0%j}s{l{@5}g4^YogzR-Uf@mtTD*sf=w-P(q}CFi50Dt)^7tTM}L zNWp;9=nj`?LcSf~+$M+u`-6BJTOS)N6W+-Dk0B3MbdXm{Vsjw~zT4LBI@_tragxmv zxI?({=LYnB^V5&TJ!yqZsH_`Nd|eZF_o+29MUE)8;)$U$=s}$Gmh82>-2i#vD)S$ohGSMWv9`@gZrRWTpJrB?Ed1&Oo;gV z@r;A@Z}I>f86NI1C{oorAw2-PE>%|S=E8YrsOj^V`X(E;&kl%??ZTWJOt0(R0^Ktw z7d5g6;;Fvl!VDOK+Z>@A?1R1W5bGmpx_+K{PNP5iuMf8gD3<5A0aDQ(M6L=s>(~G4 zmf}kH1!0ECb_VJ+heiZrZ9K|INtlf#RX3cSj-?8}}l>C5`||Lj$cFja_;Xw%enX98hnub^^C+Y_6IMRC@4$4D95&^C_ated@O0qzyU z;7mvSP1?c)c7&u1|H7j_?bfk*_nvCZ%~xbp-8u0yU4~ji;WS46#oV|rlZ}l$?uon8 zx#%Obc7}$G=jaQ+h;l9y%+h16W5(+D_<&N51IM3x@kALl9}^WvUTa`@gh-}c*VNel z{>i2On_rpX!BXdOi^>`0JpIIlN)Kl1OzGInlKr9#?7>w=F4!~MBZMYw6%hWww~(hj zRSvlyNr&|VBWsnpH{|rt%%*1Mq)daJ~NW2 ze^d{nW>ODq{j3=XRj~7e6r&9hA3QfSCt};XqixRiXwGd<_4#C>Zs{xCZeNxqZD=;o znT~UI-C9BA=N3h&y!Au<^|PXD>|VlP4!$d||16U^Q(z{{GwZV(Pm8|+2#ej@KB|&; z2%+iPamLS4M-_i?tA;(io>rm<6I1R1-=dKid%J#_XcJRXzGU#xqf8vqMX>{8qrvHj z=Uh*yb)=`uAaM>8ru{I}W0mC%-iH{p zx+_#Ogu8EdeI111ImD4q-l%C4SvpdQRCJ5f?y^6Q0Y(7Pwn9v#_-R8xUbl~vkNTsO z60vTZTQa$vgNHl2kGD(zcA&1(aazUI&SgMWA^~d&d7qOa9MCD*+izH5Mlm0b@h-cc z4%w*-ToE%9350ixQhho{UO(dSASwZO3a$V#9Hvw)5!<3LQsTz@RJKPWaX%-|J?~;w zHD8f8Hpg1wng9&En3~GY42I}rdu_!Di79k?YP0$>!l3CdBv+LiqL?Nj>{PBh1t4g) zHzXNfh_957$E(&&8lrK7K*Zd1Itg77)3%ncs$qcZuM0C3`9 zW#Cwok<<_WIClosw78p^#p{s!AgvT9qQhpg;|>?)uc-S2^-(k!6^_JW_$U1p4uuF}R^XWGkt9l%T;TQEm z1s}LM_w!CdtI7I>uejB}`Y_@8@l30?ars|o#+&|GsCtM%`!>f!zZ9yUyqY;+D|E-q zEtbL>Jqfa`m#ae{+Ww1?hVXgEQ8pyP9VrPPskn%HD_~eFMu#_C6NuHK55a#kOsmu6loENj_zjP`Y{rNbw;@>KRcn(9f4JOZt?hLrtv!`@5z^m3~jJ` zROxF*t0`?PR!9P0f?@lEWV=!m;+b7V_LDqGAJ%I7*;*?e+SM&%W=xP$`srp^q~HB3q{;5qitr)vv&gs*S2`r2$fy83MZ_8rF!$d= zUVIm5NLD}V1cbV$(Gy>5h?S&X=DV{M-e?MukAv&mw1e#9H{hej;UEPc_8(Ifj--C^`k`dXG@(TpWPByGbP4 zu&4&Z>c~L9vo}%+*L0w@dPEj&Y#~24MELBC73W`Ll?1C5H}}#VdF~LZ)*jAC*IAK9 ziu(t#H`j4mqVUaCq?pjPx|E?OtT@`wDyQR6e5+QSH= z6;QGodDBKKG4j{U`$W+H!}eybZyHbH%i|$6%%t8MvH5 zn0xsR!sMTLNQ~t6ES+&A4RJIsS#W;p#VU&iYjo-5I6Bv{nplyzT>}B_E;aUL>=tp; zh%p~P)a@jTA+}q*A?$t_fDtj8IORSaw8NAvS}Q()VetEWysqKCWmf6JNpBjd6n4jL zZ4RuljWRAN^!te2@D$zBNToc^5)pTYE6nVFHIX|mL)VX=<^MuR-tiH~B{jdDvGt8u zD;_MKun`RvEtw>%)wyuAs~1N{>!hxN3lq z$+X(g)1#(;v9UXHmzluW=dFLv+Ld~D(Hpk9@phv`E&R2lC8jth0*g+CF zhv~HN@x(e2)NH%6qHc8vO+D#mMZJT9h}@6Ct$GQDhGG?u3&pY(j?{`Rn}uXat|>%h zrzlD^k_W!Dsmg<0IihbTN5L@Bj>`87x;Pa=%wKA`HKv0Wb}|r--N?O#ikGqqlAGE{ zcpaHc5WF0PPjOEKCDhvq{YGG)V`Fe^GTD)9B-Z1#NWtPWxKORIo^Fi44heTuy#YbL z5*0%-KZl8vo+a@1-4w0-?Do|PrHtccU^;r0YYEmJh3evItW14d^UOrMLA zPryQ)b|VSFPU1muq`%qNXRd-+fS)X`*Ag#yWku zm8x1dF&6aiJ4e?N<@|DTK~X#I?poyn$~pnsMm zIIwOM^j+dxzXENWPTXLp*;t|r{eT$(cl9fl6v8yU7SML}<7LPRB)^wxnr{K)oE)-< z@*)d_x!BQ>Bh|Y>_}jbU=?jM2#wszAlR)xvzH8+^&p07vQ{@mf$J5{?=rM|Ze0FJ# zPLq`FPC_W00t=7{5D29(*#xQ3YW1$;g{TrcZ3=jAEN^=!*R`rv|=@FB!$ea ziWKU{jZQxnK<5W5m)okut`E`!x*?BqhP82e-A;|96xt3*T&70k+SQE$9l%&UvprO7 zyxFXA=R(HJH_f7>%$+BstPJ5#I!)3MJI4c>O||0#m1xyy>|HOJMw|~IMB@|)1=o4P z1S8K1lzg66raOBh42Q^rOpWTN&aG9R+kDQ2d+j_SB*)b+mnp=y6Bzo5Y}K!b8siy; z7y_!DXVJ21Zo&jUxIuV|x@}eLqT<^Symi@lKC&<;Ky-|WcUo1LQ>(su(GK0A!a5Ln zq^$u@RWff4#mfrd*2>KK6^vY!MM!QNge@?RGLruot=u9J*lTn#mk_q$G!=s?{S3jc z*TPHwtedYn7f~`eQrVu6n*ALl^$?)kqHfNkD3osQx@&#ph--~oLr`I@WL0+4D_=@x zr2LO3(7iH_R`%I(qcA@gcXu1?RGfAQ2e&0aN`};iy_sAruzEBF?0KQwFox=Bl@D60 zf;VUE3ay4Hl56e9L(j_4s*=GFN_~x3o=69vFe4_iM(NXyW!?rObwam*>Z+n3RNKUc z7=U|O8y4XDVJh+ZGrCOXL=e?5(McF~vKWE>m%FB#dV=3$` zMhNK`vp{m%tTTqaXu!M}zp_s*`j+;s37X6xFQ!WGtefEQuBf3F$A8-agk!x|I8_*}Zu`*ox^)8@%H8GVGYh_Zlqz=bb9|F>_^Xx2nnLGv2f zTlb(OLbt8ZLiTJ3S(iM5F}lytGTs)+!QkbkJT;m=EX2p9I^E21y7B0*MLtcIWQB|B zoL2mvzNkhi`H0F!D%QK{`t;QqD<$c2nvrmyGlj2iiY`J}6=$qlQHg`}9izq~OLmyG z+V`Zx7Q_h2>RYRos6m(@XMcj=sk6 zKk6Do_y-zujAF7>8rI%Aon!|Ha;IyfraPJkY%($KH%*ngSf^66aZ3ZGjB*)|8wQac z`xfHs`yGn~^}(r$EV-Eaxty%y*(Zo0-m6_0Cw^kgn{R6gQPq+4qy8fS719kpV{uIE z3Z~|Y#IIE%b;$G!gjs(2;r!{P=970?D^Y~g&)q*O5Pm;`l*Yf>$mcYl4K z`XCPN^kXX#(`C6sB^&R_N40JpQJ;9{E0w>(7>enp*=90S> zI^kE-L4+8P4w9)dq)Hd;N|K8moqi?f&tZ|%YlS^CSuAsvl19P?iB8CyVI!YrQ=aX_ zQ;1o9Ee|(9lm;7+@|8mcEJb9I+$g@MMZ$D9NC!pVuan`Br}1 zX3HY-4S=e%+5jq3M*-zP+nhsLO`|samka@o_}@6iIV-?Dhai;coJ#XmZM!!3Wz=QE zT_@#k@o~7{D}SvK+3ptLM6zW2AfqRa9Hw(dy11!|Lyef=a}VRVcre|+w@=y#Dqa0J z6ipXRWwG{1)}KlvPM+BTs%fel>{oLhX%wSX%+r46Hs^ zP^d!#%+{5_(&EhBENW$u>#mC(PCoNe7JSHp#cdQP9u^R7vn<`!1Yo75F%I&?Wx{0K z_zqjYg#O{B%(a6p0bZa>K4FM^Zb*SHq0u%{>4L(B^?xk97-Ox@a|MXN z$r;IWht9HA%8VLIT2!d3RUzfPE^=iVfJPeoYQtNY!o|=WxAuoJc>?7&@|gnc%0Dbq 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

!H1ZAV|(6is8=)Ne!ez0@sCsIv8hxM`v%I^cdj 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 z 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%0D8bGnWEX=&1U%Q%cSAF* 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

tnorth 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

%hSe#a|9It3t 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 Iuh0Fz09WF-JOBUy literal 0 HcmV?d00001 From b0cde50e217e7b65eb5af8ac3c8055c30be81d60 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 04:35:25 +0200 Subject: [PATCH 089/439] Re-enable TrueType and add a TODO about translating the ToUnicode entry (note TrueType still fails on cmap) --- fonts.js | 18 +++--------------- pdf.js | 12 ++++++++++-- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/fonts.js b/fonts.js index aa0ad2933..8bc169aa6 100644 --- a/fonts.js +++ b/fonts.js @@ -100,18 +100,6 @@ var Font = function(aName, aFile, aProperties) { break; case "TrueType": - // TrueType is disabled for the moment since the sanitizer prevent it - // from loading because of an overdated cmap table - return Fonts[aName] = { - data: null, - properties: { - encoding: {}, - charset: null - }, - loading: false, - cache: Object.create(null) - }; - this.mimetype = "font/opentype"; var ttf = new TrueType(aFile); this.font = ttf.data; @@ -184,7 +172,7 @@ Font.prototype = { document.body.appendChild(canvas); // Retrieve font charset - var charset = Fonts[fontName].charset || []; + var charset = Fonts[fontName].properties.charset || []; // if the charset is too small make it repeat a few times var count = 30; while (count-- && charset.length <= 30) @@ -205,7 +193,7 @@ Font.prototype = { } } ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var textWidth = ctx.measureText(testString); + var textWidth = ctx.measureText(testString).width; if (debug) ctx.fillText(testString, 20, 20); @@ -220,7 +208,7 @@ Font.prototype = { window.clearInterval(interval); Fonts[fontName].loading = false; warn("Is " + fontName + " for charset: " + charset + " loaded?"); - } else if (textWidth != ctx.measureText(testString)) { + } else if (textWidth != ctx.measureText(testString).width) { window.clearInterval(interval); Fonts[fontName].loading = false; } diff --git a/pdf.js b/pdf.js index 399708b84..2288654f3 100644 --- a/pdf.js +++ b/pdf.js @@ -1902,6 +1902,7 @@ var CanvasGraphics = (function() { // Generate the custom cmap of the font if needed var encodingMap = {}; + var charset = []; if (fontDict.has("Encoding")) { var encoding = xref.fetchIfRef(fontDict.get("Encoding")); if (IsDict(encoding)) { @@ -1923,16 +1924,23 @@ var CanvasGraphics = (function() { if (!encoding) error("Unknown font encoding"); - var widths = xref.fetchIfRef(fontDict.get("Widths")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); + + var index = 0; + for (var j = 0; j < encoding.length; j++) { + encodingMap[firstChar + index++] = GlyphsUnicode[encoding[j]]; + } + + var widths = xref.fetchIfRef(fontDict.get("Widths")); assertWellFormed(IsArray(widths) && IsInt(firstChar), "invalid font Widths or FirstChar"); - var charset = []; for (var j = 0; j < widths.length; j++) { if (widths[j]) charset.push(encoding[j + firstChar]); } } + } else if (fontDict.has("ToUnicode")) { + TODO("ToUnicode stream translation not implemented"); } var subType = fontDict.get("Subtype"); From 17cbc72e19cb58815cf5a8ed7c25ab0acdd4dbf3 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 21:12:21 -0700 Subject: [PATCH 090/439] add Vivien to contributors list (list is in order of chronogically first push/pull, nothing else) --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index 7c27034ba..3d42ba007 100644 --- a/LICENSE +++ b/LICENSE @@ -4,6 +4,7 @@ Contributors: Andreas Gal Chris G Jones Shaon Barman + Vivien Nicolas <21@vingtetun.org> Justin D'Arcangelo Permission is hereby granted, free of charge, to any person obtaining a From 1be8c5e7ed4d61f52c18580c7e8e0939bf5658ac Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 21:18:56 -0700 Subject: [PATCH 091/439] CharSet is optional --- pdf.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 9c4344fab..c0e4791d4 100644 --- a/pdf.js +++ b/pdf.js @@ -1912,9 +1912,11 @@ var CanvasGraphics = (function() { // Get the font charset if any var charset = descriptor.get("CharSet"); - assertWellFormed(IsString(charset), "invalid charset"); + if (charset) { + assertWellFormed(IsString(charset), "invalid charset"); - charset = charset.split("/"); + charset = charset.split("/"); + } } else if (IsName(encoding)) { var encoding = Encodings[encoding.name]; if (!encoding) From c3a7bc7d796eaae9aaf8261e18a7e8801eeb71cb Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sat, 18 Jun 2011 23:49:31 -0500 Subject: [PATCH 092/439] Add Yury to the contributors list --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index 3d42ba007..81658476c 100644 --- a/LICENSE +++ b/LICENSE @@ -6,6 +6,7 @@ Shaon Barman Vivien Nicolas <21@vingtetun.org> Justin D'Arcangelo + Yury Delendik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From 4c018956f2c00fc184c45643dea90adcc8db304d Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 22:04:36 -0700 Subject: [PATCH 093/439] mozMeasureText() is non-standard and deprecated --- fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 7978cd60d..6c643ae40 100644 --- a/fonts.js +++ b/fonts.js @@ -203,7 +203,7 @@ Font.prototype = { } } ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var textWidth = ctx.mozMeasureText(testString); + var textWidth = ctx.measureText(testString).width; if (debug) ctx.fillText(testString, 20, 20); @@ -218,7 +218,7 @@ Font.prototype = { window.clearInterval(interval); Fonts[fontName].loading = false; warn("Is " + fontName + " for charset: " + charset + " loaded?"); - } else if (textWidth != ctx.mozMeasureText(testString)) { + } else if (textWidth != ctx.measureText(testString).width) { window.clearInterval(interval); Fonts[fontName].loading = false; } From 23e19c08b10732d5736340760b2cf906dc5cd914 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 23:18:46 -0700 Subject: [PATCH 094/439] use strict mode and fix violators --- fonts.js | 5 ++++- glyphlist.js | 5 +++++ multi-page-viewer.js | 2 ++ pdf.js | 18 +++++++++++------- viewer.js | 8 +++++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 6c643ae40..0c8725fb4 100644 --- a/fonts.js +++ b/fonts.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +"use strict"; + /** * Maximum file size of the font. */ @@ -1042,7 +1044,8 @@ var Type1Parser = function() { this.extractFontProgram = function t1_extractFontProgram(aStream) { var eexecString = decrypt(aStream, kEexecEncryptionKey, 4); var subrs = [], glyphs = []; - var inSubrs = inGlyphs = false; + var inGlyphs = false; + var inSubrs = false; var glyph = ""; var token = ""; diff --git a/glyphlist.js b/glyphlist.js index 1a0190133..72a90431f 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1,3 +1,8 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + var GlyphsUnicode = { A: 0x0041, AE: 0x00C6, diff --git a/multi-page-viewer.js b/multi-page-viewer.js index cc4a286ff..2410eb7bf 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +"use strict"; + var PDFViewer = { queryParams: {}, diff --git a/pdf.js b/pdf.js index 993b5063d..a051e57f3 100644 --- a/pdf.js +++ b/pdf.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +"use strict"; + var ERRORS = 0, WARNINGS = 1, TODOS = 5; var verbosity = WARNINGS; @@ -389,6 +391,12 @@ var FlateStream = (function() { return [codes, maxLen]; }, readBlock: function() { + function repeat(stream, array, len, offset, what) { + var repeat = stream.getBits(len) + offset; + while (repeat-- > 0) + array[i++] = what; + } + var stream = this.stream; // read block header @@ -449,11 +457,6 @@ var FlateStream = (function() { var codes = numLitCodes + numDistCodes; var codeLengths = new Array(codes); while (i < codes) { - function repeat(stream, array, len, offset, what) { - var repeat = stream.getBits(len) + offset; - while (repeat-- > 0) - array[i++] = what; - } var code = this.getCode(codeLenCodeTab); if (code == 16) { repeat(this, codeLengths, 2, 3, len); @@ -813,6 +816,7 @@ var Lexer = (function() { var done = false; var str = ""; var stream = this.stream; + var ch; do { switch (ch = stream.getChar()) { case undefined: @@ -1573,7 +1577,7 @@ var Catalog = (function() { return shadow(this, "toplevelPagesDict", obj); }, get numPages() { - obj = this.toplevelPagesDict.get("Count"); + var obj = this.toplevelPagesDict.get("Count"); assertWellFormed(IsInt(obj), "page count in top level pages object is not an integer"); // shadow the prototype getter @@ -2527,7 +2531,7 @@ var CanvasGraphics = (function() { error("No support for array of functions"); else if (!IsPDFFunction(fnObj)) error("Invalid function"); - fn = new PDFFunction(this.xref, fnObj); + var fn = new PDFFunction(this.xref, fnObj); var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); var step = (t1 - t0) / 10; diff --git a/viewer.js b/viewer.js index 59d8167a2..675f2fb87 100644 --- a/viewer.js +++ b/viewer.js @@ -1,12 +1,14 @@ /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ -var pdfDocument, canvas, pageDisplay, pageNum, pageInterval; +"use strict"; + +var pdfDocument, canvas, numPages, pageDisplay, pageNum, pageInterval; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; pageNum = parseInt(queryParams().page) || 1; - fileName = userInput; + var fileName = userInput; if (!userInput) { fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; } @@ -26,7 +28,7 @@ function queryParams() { function open(url) { document.title = url; - req = new XMLHttpRequest(); + var req = new XMLHttpRequest(); req.open("GET", url); req.mozResponseType = req.responseType = "arraybuffer"; req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; From 9477df21ce3a6c8278ab9d376d3f1a848299fcc0 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Sat, 18 Jun 2011 23:21:30 -0700 Subject: [PATCH 095/439] use strict in the utils/ too --- utils/cffStandardStrings.js | 11 ++++++++--- utils/fonts_utils.js | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js index 8977cd8f2..1b328a2da 100644 --- a/utils/cffStandardStrings.js +++ b/utils/cffStandardStrings.js @@ -1,5 +1,10 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + var CFFStrings = [ - ".notdef", + ".notdef", "space", "exclam", "quotedbl", @@ -490,7 +495,7 @@ var CFFDictDataMap = { }, "10": { name: "StdHW" - }, + }, "11": { name: "StdVW" }, @@ -597,7 +602,7 @@ var CFFDictDataMap = { }, "18": { name: "Private", - operand: "number number" + operand: "number number" }, "19": { name: "Subrs" diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index 086648fe2..79ecf257f 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -1,3 +1,8 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + /** * 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. From c1fc38725abe270b78a4266c5de34d4da591f00f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 09:29:28 +0200 Subject: [PATCH 096/439] Make Helvetica and Helvetica bold from page 2 to pass the sanitizer --- fonts.js | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index 8bc169aa6..3e3af250b 100644 --- a/fonts.js +++ b/fonts.js @@ -101,7 +101,7 @@ var Font = function(aName, aFile, aProperties) { case "TrueType": this.mimetype = "font/opentype"; - var ttf = new TrueType(aFile); + var ttf = new TrueType(aName, aFile, aProperties); this.font = ttf.data; break; @@ -656,7 +656,7 @@ var FontsUtils = { * is deprecated and not supported by the sanitizer... * */ -var TrueType = function(aFile) { +var TrueType = function(aName, aFile, aProperties) { var header = this._readOpenTypeHeader(aFile); var numTables = header.numTables; @@ -682,11 +682,6 @@ var TrueType = function(aFile) { tables.push(table); } - // Tables needs to be written by ascendant alphabetic order - tables.sort(function(a, b) { - return a.tag > b.tag; - }); - // If any tables are still in the array this means some required tables are // missing, which means that we need to rebuild the font in order to pass // the sanitizer. @@ -758,6 +753,31 @@ var TrueType = function(aFile) { data: OS2 }); + // If the font is missing a OS/2 table it's could be an old mac font + // without a 3-1-4 Unicode BMP table, so let's rewrite it. + var charset = aProperties.charset; + var glyphs = []; + for (var i = 0; i < charset.length; i++) { + glyphs.push({ + unicode: GlyphsUnicode[aProperties.encoding[charset[i]]] + }); + } + + // Replace the old CMAP table + var cmap = this._createCMAPTable(glyphs); + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + if (table.tag == "cmap") { + table.data = cmap; + break; + } + } + + // Tables needs to be written by ascendant alphabetic order + tables.sort(function(a, b) { + return a.tag > b.tag; + }); + // rewrite the tables but tweak offsets for (var i = 0; i < tables.length; i++) { var table = tables[i]; @@ -893,6 +913,88 @@ TrueType.prototype = { offset: length, data: data } + }, + + _createCMAPTable: function font_createCMAPTable(aGlyphs) { + var characters = new Uint16Array(kMaxGlyphsCount); + for (var i = 0; i < aGlyphs.length; i++) + characters[aGlyphs[i].unicode] = i + 1; + + // Separate the glyphs into continuous range of codes, aka segment. + var ranges = []; + var range = []; + var count = characters.length; + for (var i = 0; i < count; i++) { + if (characters[i]) { + range.push(i); + } else if (range.length) { + ranges.push(range.slice()); + range = []; + } + } + + // The size in bytes of the header is equal to the size of the + // different fields * length of a short + (size of the 4 parallels arrays + // describing segments * length of a short). + var headerSize = (12 * 2 + (ranges.length * 4 * 2)); + + var segCount = ranges.length + 1; + var segCount2 = segCount * 2; + var searchRange = FontsUtils.getMaxPower2(segCount) * 2; + var searchEntry = Math.log(segCount) / Math.log(2); + var rangeShift = 2 * segCount - searchRange; + var cmap = [].concat( + [ + 0x00, 0x00, // version + 0x00, 0x01, // numTables + 0x00, 0x03, // platformID + 0x00, 0x01, // encodingID + 0x00, 0x00, 0x00, 0x0C, // start of the table record + 0x00, 0x04 // format + ], + FontsUtils.integerToBytes(headerSize, 2), // length + [0x00, 0x00], // language + FontsUtils.integerToBytes(segCount2, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(searchEntry, 2), + FontsUtils.integerToBytes(rangeShift, 2) + ); + + // Fill up the 4 parallel arrays describing the segments. + var startCount = []; + var endCount = []; + var idDeltas = []; + var idRangeOffsets = []; + var glyphsIdsArray = []; + var bias = 0; + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = FontsUtils.integerToBytes(range[0], 2); + var end = FontsUtils.integerToBytes(range[range.length - 1], 2); + + var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); + bias += range.length; + + // deltas are signed shorts + delta[0] ^= 0xFF; + delta[1] ^= 0xFF; + delta[1] += 1; + + startCount.push(start[0], start[1]); + endCount.push(end[0], end[1]); + idDeltas.push(delta[0], delta[1]); + idRangeOffsets.push(0x00, 0x00); + + for (var j = 0; j < range.length; j++) + glyphsIdsArray.push(range[j]); + } + startCount.push(0xFF, 0xFF); + endCount.push(0xFF, 0xFF); + idDeltas.push(0x00, 0x01); + idRangeOffsets.push(0x00, 0x00); + + return cmap.concat(endCount, [0x00, 0x00], startCount, + idDeltas, idRangeOffsets, glyphsIdsArray); } }; From ca61249db168d09b6f042b03b36c59407f808ee0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sun, 19 Jun 2011 11:07:03 +0200 Subject: [PATCH 097/439] Really pass the sanitizer (encoding is broken) --- fonts.js | 49 +++++++++++++++++++++++++++---------------------- pdf.js | 2 +- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/fonts.js b/fonts.js index 3e3af250b..281eb94a8 100644 --- a/fonts.js +++ b/fonts.js @@ -82,6 +82,7 @@ var Fonts = { */ var Font = function(aName, aFile, aProperties) { this.name = aName; + this.encoding = aProperties.encoding; // If the font has already been decoded simply return if (Fonts[aName]) { @@ -134,6 +135,7 @@ Font.prototype = { name: null, font: null, mimetype: null, + encoding: null, bind: function font_bind() { var data = this.font; @@ -185,10 +187,11 @@ Font.prototype = { // When debugging use the characters provided by the charsets to visually // see what's happening if (debug) { + var encoding = this.encoding; for (var i = 0; i < charset.length; i++) { var unicode = GlyphsUnicode[charset[i]]; if (!unicode) - error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); + continue; testString += String.fromCharCode(unicode); } } @@ -672,12 +675,18 @@ var TrueType = function(aName, aFile, aProperties) { "post" ]; + var originalCMAP = null; + var tables = []; for (var i = 0; i < numTables; i++) { var table = this._readTableEntry(aFile); var index = requiredTables.indexOf(table.tag); - if (index != -1) + if (index != -1) { + if (table.tag == "cmap") + originalCMAP = table; + requiredTables.splice(index, 1); + } tables.push(table); } @@ -726,10 +735,25 @@ var TrueType = function(aName, aFile, aProperties) { 0x00, 0x02 // usMaxContext ]; + // If the font is missing a OS/2 table it's could be an old mac font + // without a 3-1-4 Unicode BMP table, so let's rewrite it. + var charset = aProperties.charset; + var glyphs = []; + for (var i = 0; i < charset.length; i++) { + glyphs.push({ + unicode: GlyphsUnicode[charset[i]] + }); + } + + // Replace the old CMAP table + var rewrittedCMAP = this._createCMAPTable(glyphs); + var cmapDelta = rewrittedCMAP.length - originalCMAP.data.length; + originalCMAP.data = rewrittedCMAP; + // Create a new file to hold the new version of our truetype with a new // header and new offsets var stream = aFile.stream || aFile; - var ttf = new Uint8Array(stream.length + 16 + OS2.length); + var ttf = new Uint8Array(stream.length + 16 + OS2.length + cmapDelta); // The new numbers of tables will be the last one plus the num of missing // tables @@ -753,25 +777,6 @@ var TrueType = function(aName, aFile, aProperties) { data: OS2 }); - // If the font is missing a OS/2 table it's could be an old mac font - // without a 3-1-4 Unicode BMP table, so let's rewrite it. - var charset = aProperties.charset; - var glyphs = []; - for (var i = 0; i < charset.length; i++) { - glyphs.push({ - unicode: GlyphsUnicode[aProperties.encoding[charset[i]]] - }); - } - - // Replace the old CMAP table - var cmap = this._createCMAPTable(glyphs); - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - if (table.tag == "cmap") { - table.data = cmap; - break; - } - } // Tables needs to be written by ascendant alphabetic order tables.sort(function(a, b) { diff --git a/pdf.js b/pdf.js index 2288654f3..fc2dcf7ea 100644 --- a/pdf.js +++ b/pdf.js @@ -1928,7 +1928,7 @@ var CanvasGraphics = (function() { var index = 0; for (var j = 0; j < encoding.length; j++) { - encodingMap[firstChar + index++] = GlyphsUnicode[encoding[j]]; + encodingMap[index++] = GlyphsUnicode[encoding[j]]; } var widths = xref.fetchIfRef(fontDict.get("Widths")); From 89a1f3ea179a85684daa2d7f2618817d2e6d4f7f Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 11:29:18 -0700 Subject: [PATCH 098/439] no need for new for typed array constructors --- pdf.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pdf.js b/pdf.js index c0e4791d4..8f61646d1 100644 --- a/pdf.js +++ b/pdf.js @@ -48,7 +48,7 @@ function shadow(obj, prop, value) { var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { - this.bytes = new Uint8Array(arrayBuffer); + this.bytes = Uint8Array(arrayBuffer); this.start = start || 0; this.pos = this.start; this.end = (start + length) || this.bytes.byteLength; @@ -113,7 +113,7 @@ var Stream = (function() { var StringStream = (function() { function constructor(str) { var length = str.length; - var bytes = new Uint8Array(length); + var bytes = Uint8Array(length); for (var n = 0; n < length; ++n) bytes[n] = str.charCodeAt(n); Stream.call(this, bytes); @@ -125,11 +125,11 @@ var StringStream = (function() { })(); var FlateStream = (function() { - const codeLenCodeMap = new Uint32Array([ + const codeLenCodeMap = Uint32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); - const lengthDecode = new Uint32Array([ + const lengthDecode = Uint32Array([ 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, @@ -137,7 +137,7 @@ var FlateStream = (function() { 0x00102, 0x00102, 0x00102 ]); - const distDecode = new Uint32Array([ + const distDecode = Uint32Array([ 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, @@ -145,7 +145,7 @@ var FlateStream = (function() { 0xd4001, 0xd6001 ]); - const fixedLitCodeTab = [new Uint32Array([ + const fixedLitCodeTab = [Uint32Array([ 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, @@ -222,7 +222,7 @@ var FlateStream = (function() { 0x900ff ]), 9]; - const fixedDistCodeTab = [new Uint32Array([ + const fixedDistCodeTab = [Uint32Array([ 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, @@ -298,7 +298,7 @@ var FlateStream = (function() { var size = 512; while (size < requested) size <<= 1; - var buffer2 = new Uint8Array(size); + var buffer2 = Uint8Array(size); for (var i = 0; i < current; ++i) buffer2[i] = buffer[i]; return this.buffer = buffer2; @@ -363,7 +363,7 @@ var FlateStream = (function() { // build the table var size = 1 << maxLen; - var codes = new Uint32Array(size); + var codes = Uint32Array(size); for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { From cf0e22ffafe30c21fd2df04c76eb2f38cc061fbb Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 19 Jun 2011 14:54:13 -0400 Subject: [PATCH 099/439] Changed the zoom input to utilize a pre-populated combo box. --- images/combobox.png | Bin 0 -> 1964 bytes images/source/ComboBox.psd.zip | Bin 0 -> 17724 bytes multi-page-viewer.css | 60 +++++++++++++++++++++++++++++++++ multi-page-viewer.html | 13 +++++-- multi-page-viewer.js | 40 +++++++++++++++++++--- 5 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 images/combobox.png create mode 100644 images/source/ComboBox.psd.zip diff --git a/images/combobox.png b/images/combobox.png new file mode 100644 index 0000000000000000000000000000000000000000..f1527d6a2e4cdcf3f72df511bdbde4e9f843a0f9 GIT binary patch literal 1964 zcmaJ?eNYp38r}fLFKoE>;0P*ggJ^6?vI$8@);sq@tFtSFs37Ov}b`3}&&cRx8sQ#Y9azSZtwC=+)qG7zBc0-ebfyHipq0 zKC2)_%vzHk!}X{U^eSq$qZV9DBQpJ^1OxV3)@Xj!CZb_1n+9XCnUJ@nS)fAk|DguM zYqS|pMSjiqe+rvbdoYBRikMN0NlOeaE8H6jgC!s{oJ`k&8hc_tD8F) z?wni}kqpZ_*#8>ztc%zl@AdWC62|MrM~uX_n~1f(R$!?F06$PJjaAwDM~|&v|6c5G zZ)_OiwS_HAIus{~!G5zVe9=(c`ar*w^oL1>LG3qg6+Wv>YfrMqrB5x~lHRb`y4mk{ zO()|vof=xx2G6utWYm7~@Koyqj&ISWDC*r8BC}`s$)k~xaNgr1iq+FoC^SO zL7vcgQ(ex#RZAq2=9U&2f*^n23moIMzT)ym#;3VMpF#kg`50TSe*sO33*0 zz}B|57Zsh>-Sp7%iW|e7qyHQnRB}V=E?>T3DN)}HL>3puZFtJNb>~9$TZ@k+pFVr` ztURx*wTL&lm9*fqD_8zHIl23};qNUik1Uf^wKPQ)saC70=w+JwUrzMq0r|82z>k~! z8m@2c@_4M@1h!thc(u8l`+eZ@@v*V7(y-AP^4_wVn;+mLO4lcijem^qixLPD_qhgB zGFPoy_32KV$K%nP%@u!8tDC9{R~7`#JimVZ`jMwY^DVc1{}j0DD`#p;OUqzoWu+^U z#hMuxtw>DoJ?K2i3F{2iBd#M6cWvifuCU6tk!rWwF|#kY56TJd>t+-WxE=L(`1$us z+Ah^@SXsekvuj!(|6sQq*mSAt{{8#(H;Y9-uleYdQn0N4_;Knxbh<7S3yIn%cW|`J?Z}r`(Ra-^!E732UAy28!W{M(=6d@#Pe|NXamnVR#FO&2aCOiWB1 z-+PcM#B@4oo@cG}%uXP)gXd2!;KK0FiTq`up|_^1_*2z)j}8eP!wdSlyJH#~8~Y0w z3{QJ21d^*1W6h b81(T623#fQfN0SX@BdRSOO}2Tm%0Bx3gr>A literal 0 HcmV?d00001 diff --git a/images/source/ComboBox.psd.zip b/images/source/ComboBox.psd.zip new file mode 100644 index 0000000000000000000000000000000000000000..232604c7514e825ae93b017a0fe186447399f32f GIT binary patch literal 17724 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 F@c^Z#N{Ijf literal 0 HcmV?d00001 diff --git a/multi-page-viewer.css b/multi-page-viewer.css index 53a28f129..293b32241 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -113,6 +113,66 @@ span { background: url('images/buttons.png') no-repeat -28px 0px; } +#scaleComboBoxInput { + background: url('images/combobox.png') no-repeat 0px -23px; + display: inline-block; + float: left; + margin: 0px; + width: 35px; + height: 23px; +} + +#scaleComboBoxInput input { + background: none; + border: 0px; + margin: 3px 2px 0px; + width: 31px; +} + +#scaleComboBoxButton { + background: url('images/combobox.png') no-repeat -41px -23px; + cursor: pointer; + display: inline-block; + float: left; + margin: 0px; + width: 21px; + height: 23px; +} + +#scaleComboBoxButton.down { + background: url('images/combobox.png') no-repeat -41px -46px; +} + +#scaleComboBoxButton.disabled { + background: url('images/combobox.png') no-repeat -41px 0px; +} + +#scaleComboBoxList { + background-color: #fff; + border: 1px solid #666; + clear: both; + position: relative; + display: none; + top: -20px; + width: 48px; +} + +#scaleComboBoxList > ul { + list-style: none; + padding: 0px; + margin: 0px; +} + +#scaleComboBoxList > ul > li { + display: inline-block; + cursor: pointer; + width: 100%; +} + +#scaleComboBoxList > ul > li:hover { + background-color: #09f; +} + #pageNumber, #scale { text-align: right; } diff --git a/multi-page-viewer.html b/multi-page-viewer.html index aec84a42f..692cfb1c4 100644 --- a/multi-page-viewer.html +++ b/multi-page-viewer.html @@ -21,9 +21,18 @@ Page Number - - % + Zoom +

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

diff --git a/multi-page-viewer.js b/multi-page-viewer.js index 2410eb7bf..6cb46a08a 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -8,9 +8,10 @@ var PDFViewer = { element: null, - pageNumberInput: null, previousPageButton: null, nextPageButton: null, + pageNumberInput: null, + scaleInput: null, willJumpToPage: false, @@ -158,6 +159,8 @@ var PDFViewer = { PDFViewer.drawPage(1); } } + + PDFViewer.scaleInput.value = Math.floor(PDFViewer.scale * 100) + '%'; }, goToPage: function(num) { @@ -317,13 +320,40 @@ window.onload = function() { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; - var scaleInput = document.getElementById('scale'); - scaleInput.onchange = function(evt) { - PDFViewer.changeScale(this.value); + PDFViewer.scaleInput = document.getElementById('scale'); + PDFViewer.scaleInput.buttonElement = document.getElementById('scaleComboBoxButton'); + PDFViewer.scaleInput.buttonElement.listElement = document.getElementById('scaleComboBoxList'); + PDFViewer.scaleInput.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); }; + PDFViewer.scaleInput.buttonElement.onclick = function(evt) { + this.listElement.style.display = (this.listElement.style.display === 'block') ? 'none' : 'block'; + }; + PDFViewer.scaleInput.buttonElement.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.scaleInput.buttonElement.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.scaleInput.buttonElement.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + var listItems = PDFViewer.scaleInput.buttonElement.listElement.getElementsByTagName('LI'); + + for (var i = 0; i < listItems.length; i++) { + var listItem = listItems[i]; + listItem.onclick = function(evt) { + PDFViewer.changeScale(parseInt(this.innerHTML)); + PDFViewer.scaleInput.buttonElement.listElement.style.display = 'none'; + }; + } + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(scaleInput.value) / 100 || 1.0; + PDFViewer.scale = parseInt(PDFViewer.scaleInput.value) / 100 || 1.0; PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); window.onscroll = function(evt) { From a3781157cf7f2f70b06742c02d0e534d3039365c Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 19 Jun 2011 14:57:45 -0400 Subject: [PATCH 100/439] Minor CSS fix for zoom drop down. --- multi-page-viewer.css | 1 + 1 file changed, 1 insertion(+) diff --git a/multi-page-viewer.css b/multi-page-viewer.css index 293b32241..c96567465 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -171,6 +171,7 @@ span { #scaleComboBoxList > ul > li:hover { background-color: #09f; + color: #fff; } #pageNumber, #scale { From e9a9de8a1b4ca6eb68faf79aee0aaabc2a026726 Mon Sep 17 00:00:00 2001 From: sbarman Date: Sun, 19 Jun 2011 15:01:52 -0500 Subject: [PATCH 101/439] cleanup --- pdf.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pdf.js b/pdf.js index 233773cb4..bf8ff1d97 100644 --- a/pdf.js +++ b/pdf.js @@ -1738,6 +1738,7 @@ var CanvasExtraState = (function() { this.fontSize = 0.0; this.textMatrix = IDENTITY_MATRIX; this.leading = 0.0; + this.colorSpace = "DeviceRGB"; // Current point (in user coordinates) this.x = 0.0; this.y = 0.0; @@ -2424,9 +2425,9 @@ var CanvasGraphics = (function() { setFillColorSpace: function(space) { // TODO real impl if (space.name === "Pattern") - this.colorspace = "Pattern"; + this.current.colorSpace = "Pattern"; else - this.colorspace = null; + this.current.colorSpace = "DeviceRGB"; }, setStrokeColor: function(/*...*/) { // TODO real impl @@ -2451,7 +2452,7 @@ var CanvasGraphics = (function() { setFillColorN: function(/*...*/) { // TODO real impl var args = arguments; - if (this.colorspace == "Pattern") { + if (this.current.colorSpace == "Pattern") { var patternName = args[0]; if (IsName(patternName)) { var xref = this.xref; @@ -2502,12 +2503,9 @@ var CanvasGraphics = (function() { ctx.strokeStyle = this.makeCssRgb(0, 0, 0); } - // not sure what to do with this - var tilingType = dict.get("TilingType"); + TODO("TilingType"); - var matrix = dict.get("Matrix"); - if (!matrix) - matrix = [1, 0, 0, 1, 0, 0]; + var matrix = dict.get("Matrix") || IDENTITY_MATRIX; var bbox = dict.get("BBox"); var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; @@ -2526,7 +2524,7 @@ var CanvasGraphics = (function() { // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext("2d"); - var oldCtx = this.ctx; + var savedCtx = this.ctx; this.ctx = tmpCtx; // normalize transform matrix so each step @@ -2554,11 +2552,10 @@ var CanvasGraphics = (function() { pattern.code = this.compile(pattern, xref, res, []); this.execute(pattern.code, xref, res); - // set the old context - this.ctx = oldCtx; + this.ctx = savedCtx; this.restore(); - warn("Inverse pattern is painted"); + TODO("Inverse pattern is painted"); var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); this.ctx.fillStyle = pattern; }, @@ -2650,8 +2647,8 @@ var CanvasGraphics = (function() { var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); // 10 samples seems good enough for now, but probably won't work - // if there are sharp color changes. Ideally, we could see the - // current image size and base the # samples on that. + // if there are sharp color changes. Ideally, we would implement + // the spec faithfully and add lossless optimizations. var step = (t1 - t0) / 10; for (var i = t0; i <= t1; i += step) { @@ -2664,7 +2661,10 @@ var CanvasGraphics = (function() { // HACK to draw the gradient onto an infinite rectangle. // PDF gradients are drawn across the entire image while // Canvas only allows gradients to be drawn in a rectangle - // Also, larger numbers seem to cause overflow which causes + // The following bug should allow us to remove this. + // https://bugzilla.mozilla.org/show_bug.cgi?id=664884 + // + // Also, larg numbers seem to cause overflow which causes // nothing to be drawn. this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); }, From 30460ce4b2bcc28090f9bb4d47f63841a6392a00 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 20 Jun 2011 00:09:50 +0200 Subject: [PATCH 102/439] Fix the encoding problem for TrueType --- pdf.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pdf.js b/pdf.js index fc2dcf7ea..631c1a74a 100644 --- a/pdf.js +++ b/pdf.js @@ -1608,6 +1608,9 @@ var CanvasExtraState = (function() { const Encodings = { get ExpertEncoding() { return shadow(this, "ExpertEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", "ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior", "twodotenleader","onedotenleader","comma","hyphen","period","fraction", @@ -1643,6 +1646,9 @@ const Encodings = { }, get MacExpertEncoding() { return shadow(this, "MacExpertEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle", "dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior", "parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period", @@ -1677,6 +1683,9 @@ const Encodings = { }, get MacRomanEncoding() { return shadow(this, "MacRomanEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "period","slash","zero","one","two","three","four","five","six","seven","eight", @@ -1707,6 +1716,9 @@ const Encodings = { }, get StandardEncoding() { return shadow(this, "StandardEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "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", @@ -1727,6 +1739,9 @@ const Encodings = { }, get WinAnsiEncoding() { return shadow(this, "WinAnsiEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "period","slash","zero","one","two","three","four","five","six","seven","eight", @@ -1758,6 +1773,9 @@ const Encodings = { }, get zapfDingbatsEncoding() { return shadow(this, "zapfDingbatsEncoding", [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13", "a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25", "a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34", @@ -1934,6 +1952,7 @@ var CanvasGraphics = (function() { var widths = xref.fetchIfRef(fontDict.get("Widths")); assertWellFormed(IsArray(widths) && IsInt(firstChar), "invalid font Widths or FirstChar"); + for (var j = 0; j < widths.length; j++) { if (widths[j]) charset.push(encoding[j + firstChar]); From 5afd963c8a62102591d6b60f31e354f51670a3af Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:14:07 -0700 Subject: [PATCH 103/439] handle surrogate pairs in glyph to unicode translation --- fonts.js | 6 +- glyphlist.js | 152 +++++++++++++++++++++++++-------------------------- 2 files changed, 81 insertions(+), 77 deletions(-) diff --git a/fonts.js b/fonts.js index 0c8725fb4..6cf9d6c1d 100644 --- a/fonts.js +++ b/fonts.js @@ -62,6 +62,10 @@ var Fonts = { var uc = encoding[ch]; if (uc instanceof Name) // we didn't convert the glyph yet uc = encoding[ch] = GlyphsUnicode[uc.name]; + if (uc > 0xffff) { // handle surrogate pairs + ret += String.fromCharCode(uc & 0xffff); + uc >>= 16; + } ret += String.fromCharCode(uc); } @@ -83,7 +87,7 @@ var Fonts = { var Font = function(aName, aFile, aProperties) { this.name = aName; - // If the font has already been decoded simply return + // If the font has already been decoded simply return it if (Fonts[aName]) { this.font = Fonts[aName].data; return; diff --git a/glyphlist.js b/glyphlist.js index 72a90431f..85ab876f9 100644 --- a/glyphlist.js +++ b/glyphlist.js @@ -1505,27 +1505,27 @@ var GlyphsUnicode = { dalet: 0x05D3, daletdagesh: 0xFB33, daletdageshhebrew: 0xFB33, - dalethatafpatah: "05D3 05B2", - dalethatafpatahhebrew: "05D3 05B2", - dalethatafsegol: "05D3 05B1", - dalethatafsegolhebrew: "05D3 05B1", + dalethatafpatah: 0x05D305B2, + dalethatafpatahhebrew: 0x05D305B2, + dalethatafsegol: 0x05D305B1, + dalethatafsegolhebrew: 0x05D305B1, dalethebrew: 0x05D3, - dalethiriq: "05D3 05B4", - dalethiriqhebrew: "05D3 05B4", - daletholam: "05D3 05B9", - daletholamhebrew: "05D3 05B9", - daletpatah: "05D3 05B7", - daletpatahhebrew: "05D3 05B7", - daletqamats: "05D3 05B8", - daletqamatshebrew: "05D3 05B8", - daletqubuts: "05D3 05BB", - daletqubutshebrew: "05D3 05BB", - daletsegol: "05D3 05B6", - daletsegolhebrew: "05D3 05B6", - daletsheva: "05D3 05B0", - daletshevahebrew: "05D3 05B0", - dalettsere: "05D3 05B5", - dalettserehebrew: "05D3 05B5", + dalethiriq: 0x05D305B4, + dalethiriqhebrew: 0x05D305B4, + daletholam: 0x05D305B9, + daletholamhebrew: 0x05D305B9, + daletpatah: 0x05D305B7, + daletpatahhebrew: 0x05D305B7, + daletqamats: 0x05D305B8, + daletqamatshebrew: 0x05D305B8, + daletqubuts: 0x05D305BB, + daletqubutshebrew: 0x05D305BB, + daletsegol: 0x05D305B6, + daletsegolhebrew: 0x05D305B6, + daletsheva: 0x05D305B0, + daletshevahebrew: 0x05D305B0, + dalettsere: 0x05D305B5, + dalettserehebrew: 0x05D305B5, dalfinalarabic: 0xFEAA, dammaarabic: 0x064F, dammalowarabic: 0x064F, @@ -1842,10 +1842,10 @@ var GlyphsUnicode = { finalkafdagesh: 0xFB3A, finalkafdageshhebrew: 0xFB3A, finalkafhebrew: 0x05DA, - finalkafqamats: "05DA 05B8", - finalkafqamatshebrew: "05DA 05B8", - finalkafsheva: "05DA 05B0", - finalkafshevahebrew: "05DA 05B0", + finalkafqamats: 0x05DA05B8, + finalkafqamatshebrew: 0x05DA05B8, + finalkafsheva: 0x05DA05B0, + finalkafshevahebrew: 0x05DA05B0, finalmem: 0x05DD, finalmemhebrew: 0x05DD, finalnun: 0x05DF, @@ -2034,14 +2034,14 @@ var GlyphsUnicode = { hakatakanahalfwidth: 0xFF8A, halantgurmukhi: 0x0A4D, hamzaarabic: 0x0621, - hamzadammaarabic: "0621 064F", - hamzadammatanarabic: "0621 064C", - hamzafathaarabic: "0621 064E", - hamzafathatanarabic: "0621 064B", + hamzadammaarabic: 0x0621064F, + hamzadammatanarabic: 0x0621064C, + hamzafathaarabic: 0x0621064E, + hamzafathatanarabic: 0x0621064B, hamzalowarabic: 0x0621, - hamzalowkasraarabic: "0621 0650", - hamzalowkasratanarabic: "0621 064D", - hamzasukunarabic: "0621 0652", + hamzalowkasraarabic: 0x06210650, + hamzalowkasratanarabic: 0x0621064D, + hamzasukunarabic: 0x06210652, hangulfiller: 0x3164, hardsigncyrillic: 0x044A, harpoonleftbarbup: 0x21BC, @@ -2473,10 +2473,10 @@ var GlyphsUnicode = { lameddagesh: 0xFB3C, lameddageshhebrew: 0xFB3C, lamedhebrew: 0x05DC, - lamedholam: "05DC 05B9", + lamedholam: 0x05DC05B9, lamedholamdagesh: "05DC 05B9 05BC", lamedholamdageshhebrew: "05DC 05B9 05BC", - lamedholamhebrew: "05DC 05B9", + lamedholamhebrew: 0x05DC05B9, lamfinalarabic: 0xFEDE, lamhahinitialarabic: 0xFCCA, laminitialarabic: 0xFEDF, @@ -2784,7 +2784,7 @@ var GlyphsUnicode = { noonfinalarabic: 0xFEE6, noonghunnaarabic: 0x06BA, noonghunnafinalarabic: 0xFB9F, - noonhehinitialarabic: "FEE7 FEEC", + noonhehinitialarabic: 0xFEE7FEEC, nooninitialarabic: 0xFEE7, noonjeeminitialarabic: 0xFCD2, noonjeemisolatedarabic: 0xFC4B, @@ -3156,27 +3156,27 @@ var GlyphsUnicode = { qof: 0x05E7, qofdagesh: 0xFB47, qofdageshhebrew: 0xFB47, - qofhatafpatah: "05E7 05B2", - qofhatafpatahhebrew: "05E7 05B2", - qofhatafsegol: "05E7 05B1", - qofhatafsegolhebrew: "05E7 05B1", + qofhatafpatah: 0x05E705B2, + qofhatafpatahhebrew: 0x05E705B2, + qofhatafsegol: 0x05E705B1, + qofhatafsegolhebrew: 0x05E705B1, qofhebrew: 0x05E7, - qofhiriq: "05E7 05B4", - qofhiriqhebrew: "05E7 05B4", - qofholam: "05E7 05B9", - qofholamhebrew: "05E7 05B9", - qofpatah: "05E7 05B7", - qofpatahhebrew: "05E7 05B7", - qofqamats: "05E7 05B8", - qofqamatshebrew: "05E7 05B8", - qofqubuts: "05E7 05BB", - qofqubutshebrew: "05E7 05BB", - qofsegol: "05E7 05B6", - qofsegolhebrew: "05E7 05B6", - qofsheva: "05E7 05B0", - qofshevahebrew: "05E7 05B0", - qoftsere: "05E7 05B5", - qoftserehebrew: "05E7 05B5", + qofhiriq: 0x05E705B4, + qofhiriqhebrew: 0x05E705B4, + qofholam: 0x05E705B9, + qofholamhebrew: 0x05E705B9, + qofpatah: 0x05E705B7, + qofpatahhebrew: 0x05E705B7, + qofqamats: 0x05E705B8, + qofqamatshebrew: 0x05E705B8, + qofqubuts: 0x05E705BB, + qofqubutshebrew: 0x05E705BB, + qofsegol: 0x05E705B6, + qofsegolhebrew: 0x05E705B6, + qofsheva: 0x05E705B0, + qofshevahebrew: 0x05E705B0, + qoftsere: 0x05E705B5, + qoftserehebrew: 0x05E705B5, qparen: 0x24AC, quarternote: 0x2669, qubuts: 0x05BB, @@ -3255,27 +3255,27 @@ var GlyphsUnicode = { rekatakanahalfwidth: 0xFF9A, resh: 0x05E8, reshdageshhebrew: 0xFB48, - reshhatafpatah: "05E8 05B2", - reshhatafpatahhebrew: "05E8 05B2", - reshhatafsegol: "05E8 05B1", - reshhatafsegolhebrew: "05E8 05B1", + reshhatafpatah: 0x05E805B2, + reshhatafpatahhebrew: 0x05E805B2, + reshhatafsegol: 0x05E805B1, + reshhatafsegolhebrew: 0x05E805B1, reshhebrew: 0x05E8, - reshhiriq: "05E8 05B4", - reshhiriqhebrew: "05E8 05B4", - reshholam: "05E8 05B9", - reshholamhebrew: "05E8 05B9", - reshpatah: "05E8 05B7", - reshpatahhebrew: "05E8 05B7", - reshqamats: "05E8 05B8", - reshqamatshebrew: "05E8 05B8", - reshqubuts: "05E8 05BB", - reshqubutshebrew: "05E8 05BB", - reshsegol: "05E8 05B6", - reshsegolhebrew: "05E8 05B6", - reshsheva: "05E8 05B0", - reshshevahebrew: "05E8 05B0", - reshtsere: "05E8 05B5", - reshtserehebrew: "05E8 05B5", + reshhiriq: 0x05E805B4, + reshhiriqhebrew: 0x05E805B4, + reshholam: 0x05E805B9, + reshholamhebrew: 0x05E805B9, + reshpatah: 0x05E805B7, + reshpatahhebrew: 0x05E805B7, + reshqamats: 0x05E805B8, + reshqamatshebrew: 0x05E805B8, + reshqubuts: 0x05E805BB, + reshqubutshebrew: 0x05E805BB, + reshsegol: 0x05E805B6, + reshsegolhebrew: 0x05E805B6, + reshsheva: 0x05E805B0, + reshshevahebrew: 0x05E805B0, + reshtsere: 0x05E805B5, + reshtserehebrew: 0x05E805B5, reversedtilde: 0x223D, reviahebrew: 0x0597, reviamugrashhebrew: 0x0597, @@ -3474,7 +3474,7 @@ var GlyphsUnicode = { shaddadammaarabic: 0xFC61, shaddadammatanarabic: 0xFC5E, shaddafathaarabic: 0xFC60, - shaddafathatanarabic: "0651 064B", + shaddafathatanarabic: 0x0651064B, shaddakasraarabic: 0xFC62, shaddakasratanarabic: 0xFC5F, shade: 0x2592, @@ -3671,7 +3671,7 @@ var GlyphsUnicode = { tchehfinalarabic: 0xFB7B, tchehinitialarabic: 0xFB7C, tchehmedialarabic: 0xFB7D, - tchehmeeminitialarabic: "FB7C FEE4", + tchehmeeminitialarabic: 0xFB7CFEE4, tcircle: 0x24E3, tcircumflexbelow: 0x1E71, tcommaaccent: 0x0163, From 7bb098dfc7b91151cb20d786c7a4bc190b0c85bc Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:30:55 -0700 Subject: [PATCH 104/439] don't use an array to translate from a typed array to a string, and always store font data as typed array, never as a stream --- fonts.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fonts.js b/fonts.js index 6cf9d6c1d..e018061e9 100644 --- a/fonts.js +++ b/fonts.js @@ -154,14 +154,13 @@ Font.prototype = { bind: function font_bind() { var data = this.font; - // Compute the binary data to base 64 - var str = []; - var count = data.length; - for (var i = 0; i < count; i++) - str.push(data.getChar ? data.getChar() - : String.fromCharCode(data[i])); + // Get the base64 encoding of the binary font data + var str = ""; + var length = data.length; + for (var i = 0; i < length; ++i) + str += String.fromCharCode(data[i]); - var dataBase64 = window.btoa(str.join("")); + var dataBase64 = window.btoa(str); var fontName = this.name; /** Hack begin */ @@ -752,7 +751,7 @@ var TrueType = function(aFile) { } else if (requiredTables.lenght) { error("Table " + requiredTables[0] + " is missing from the TruType font"); } else { - this.data = aFile; + this.data = aFile.getBytes(); } }; From f6e85f00cbb155f0c4bba2555d6df8468ea32e41 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:46:58 -0700 Subject: [PATCH 105/439] add a closure around Font so we can hide helper functions in it --- fonts.js | 829 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 416 insertions(+), 413 deletions(-) diff --git a/fonts.js b/fonts.js index e018061e9..85a5c199d 100644 --- a/fonts.js +++ b/fonts.js @@ -84,17 +84,18 @@ var Fonts = { * var type1Font = new Font("MyFontName", binaryFile, propertiesObject); * type1Font.bind(); */ -var Font = function(aName, aFile, aProperties) { - this.name = aName; +var Font = (function () { + var constructor = function(aName, aFile, aProperties) { + this.name = aName; - // If the font has already been decoded simply return it - if (Fonts[aName]) { - this.font = Fonts[aName].data; - return; - } - fontCount++; + // If the font has already been decoded simply return it + if (Fonts[aName]) { + this.font = Fonts[aName].data; + return; + } + fontCount++; - switch (aProperties.type) { + switch (aProperties.type) { case "Type1": var cff = new CFF(aName, aFile, aProperties); this.mimetype = "font/otf"; @@ -124,448 +125,450 @@ var Font = function(aName, aFile, aProperties) { default: warn("Font " + aProperties.type + " is not supported"); break; - } - - Fonts[aName] = { - data: this.font, - properties: aProperties, - loading: true, - cache: Object.create(null) - } - - // Attach the font to the document - this.bind(); -}; - - -/** - * A bunch of the OpenType code is duplicate between this class and the - * TrueType code, this is intentional and will merge in a future version - * where all the code relative to OpenType will probably have its own - * class and will take decision without the Fonts consent. - * But at the moment it allows to develop around the TrueType rewriting - * on the fly without messing up with the 'regular' Type1 to OTF conversion. - */ -Font.prototype = { - name: null, - font: null, - mimetype: null, - - bind: function font_bind() { - var data = this.font; - - // Get the base64 encoding of the binary font data - var str = ""; - var length = data.length; - for (var i = 0; i < length; ++i) - str += String.fromCharCode(data[i]); - - var dataBase64 = window.btoa(str); - var fontName = this.name; - - /** Hack begin */ - - // Actually there is not event when a font has finished downloading so - // the following tons of code are a dirty hack to 'guess' when a font is - // ready - var debug = false; - - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); } - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); + Fonts[aName] = { + data: this.font, + properties: aProperties, + loading: true, + cache: Object.create(null) + } - // Retrieve font charset - var charset = Fonts[fontName].charset || []; - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); + // Attach the font to the document + this.bind(); + }; - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening - if (debug) { - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); - testString += String.fromCharCode(unicode); + /** + * A bunch of the OpenType code is duplicate between this class and the + * TrueType code, this is intentional and will merge in a future version + * where all the code relative to OpenType will probably have its own + * class and will take decision without the Fonts consent. + * But at the moment it allows to develop around the TrueType rewriting + * on the fly without messing up with the 'regular' Type1 to OTF conversion. + */ + constructor.prototype = { + name: null, + font: null, + mimetype: null, + + bind: function font_bind() { + var data = this.font; + + // Get the base64 encoding of the binary font data + var str = ""; + var length = data.length; + for (var i = 0; i < length; ++i) + str += String.fromCharCode(data[i]); + + var dataBase64 = window.btoa(str); + var fontName = this.name; + + /** Hack begin */ + + // Actually there is not event when a font has finished downloading so + // the following tons of code are a dirty hack to 'guess' when a font is + // ready + var debug = false; + + if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); } - } - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var textWidth = ctx.measureText(testString).width; - if (debug) - ctx.fillText(testString, 20, 20); + var canvas = document.createElement("canvas"); + var style = "border: 1px solid black; position:absolute; top: " + + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; + canvas.setAttribute("style", style); + canvas.setAttribute("width", 340); + canvas.setAttribute("heigth", 100); + document.body.appendChild(canvas); - var start = Date.now(); - var interval = window.setInterval(function canvasInterval(self) { + // Retrieve font charset + var charset = Fonts[fontName].charset || []; + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); + + // Get the font size canvas think it will be for 'spaces' + var ctx = canvas.getContext("2d"); + var testString = " "; + + // When debugging use the characters provided by the charsets to visually + // see what's happening + if (debug) { + for (var i = 0; i < charset.length; i++) { + var unicode = GlyphsUnicode[charset[i]]; + if (!unicode) + error("Unicode for " + charset[i] + " is has not been found in the glyphs list"); + testString += String.fromCharCode(unicode); + } + } ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - - // For some reasons the font has not loaded, so mark it loaded for the - // page to proceed but cry - if ((Date.now() - start) >= kMaxWaitForFontFace) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - } + var textWidth = ctx.measureText(testString).width; if (debug) - ctx.fillText(testString, 20, 50); - }, 50, this); + ctx.fillText(testString, 20, 20); - /** Hack end */ + var start = Date.now(); + var interval = window.setInterval(function canvasInterval(self) { + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");"; - var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); - }, + // For some reasons the font has not loaded, so mark it loaded for the + // page to proceed but cry + if ((Date.now() - start) >= kMaxWaitForFontFace) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + warn("Is " + fontName + " for charset: " + charset + " loaded?"); + } else if (textWidth != ctx.measureText(testString).width) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + } - _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) { - // sfnt version (4 bytes) - var version = [0x4F, 0x54, 0x54, 0X4F]; + if (debug) + ctx.fillText(testString, 20, 50); + }, 50, this); - // numTables (2 bytes) - var numTables = aNumTables; + /** Hack end */ - // searchRange (2 bytes) - var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); - var searchRange = tablesMaxPower2 * 16; + // Add the @font-face rule to the document + var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");"; + var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + }, - // entrySelector (2 bytes) - var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); + _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) { + // sfnt version (4 bytes) + var version = [0x4F, 0x54, 0x54, 0X4F]; - // rangeShift (2 bytes) - var rangeShift = numTables * 16 - searchRange; + // numTables (2 bytes) + var numTables = aNumTables; - var header = [].concat(version, - FontsUtils.integerToBytes(numTables, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(entrySelector, 2), - FontsUtils.integerToBytes(rangeShift, 2)); - aFile.set(header, aOffsets.currentOffset); - aOffsets.currentOffset += header.length; - aOffsets.virtualOffset += header.length; - }, + // searchRange (2 bytes) + var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); + var searchRange = tablesMaxPower2 * 16; - _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) { - // tag - var tag = [ - aTag.charCodeAt(0), - aTag.charCodeAt(1), - aTag.charCodeAt(2), - aTag.charCodeAt(3) - ]; + // entrySelector (2 bytes) + var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); - // offset - var offset = aOffsets.virtualOffset; + // rangeShift (2 bytes) + var rangeShift = numTables * 16 - searchRange; - // Per spec tables must be 4-bytes align so add some 0x00 if needed - while (aData.length & 3) - aData.push(0x00); + var header = [].concat(version, + FontsUtils.integerToBytes(numTables, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(entrySelector, 2), + FontsUtils.integerToBytes(rangeShift, 2)); + aFile.set(header, aOffsets.currentOffset); + aOffsets.currentOffset += header.length; + aOffsets.virtualOffset += header.length; + }, - // length - var length = aData.length; + _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) { + // tag + var tag = [ + aTag.charCodeAt(0), + aTag.charCodeAt(1), + aTag.charCodeAt(2), + aTag.charCodeAt(3) + ]; - // checksum - var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + // offset + var offset = aOffsets.virtualOffset; - var tableEntry = [].concat(tag, - FontsUtils.integerToBytes(checksum, 4), - FontsUtils.integerToBytes(offset, 4), - FontsUtils.integerToBytes(length, 4)); - aFile.set(tableEntry, aOffsets.currentOffset); - aOffsets.currentOffset += tableEntry.length; - aOffsets.virtualOffset += aData.length; - }, + // Per spec tables must be 4-bytes align so add some 0x00 if needed + while (aData.length & 3) + aData.push(0x00); - _createCMAPTable: function font_createCMAPTable(aGlyphs) { - var characters = new Uint16Array(kMaxGlyphsCount); - for (var i = 0; i < aGlyphs.length; i++) - characters[aGlyphs[i].unicode] = i + 1; + // length + var length = aData.length; - // Separate the glyphs into continuous range of codes, aka segment. - var ranges = []; - var range = []; - var count = characters.length; - for (var i = 0; i < count; i++) { - if (characters[i]) { - range.push(i); - } else if (range.length) { - ranges.push(range.slice()); - range = []; + // checksum + var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + + var tableEntry = [].concat(tag, + FontsUtils.integerToBytes(checksum, 4), + FontsUtils.integerToBytes(offset, 4), + FontsUtils.integerToBytes(length, 4)); + aFile.set(tableEntry, aOffsets.currentOffset); + aOffsets.currentOffset += tableEntry.length; + aOffsets.virtualOffset += aData.length; + }, + + _createCMAPTable: function font_createCMAPTable(aGlyphs) { + var characters = new Uint16Array(kMaxGlyphsCount); + for (var i = 0; i < aGlyphs.length; i++) + characters[aGlyphs[i].unicode] = i + 1; + + // Separate the glyphs into continuous range of codes, aka segment. + var ranges = []; + var range = []; + var count = characters.length; + for (var i = 0; i < count; i++) { + if (characters[i]) { + range.push(i); + } else if (range.length) { + ranges.push(range.slice()); + range = []; + } } - } - // The size in bytes of the header is equal to the size of the - // different fields * length of a short + (size of the 4 parallels arrays - // describing segments * length of a short). - var headerSize = (12 * 2 + (ranges.length * 4 * 2)); + // The size in bytes of the header is equal to the size of the + // different fields * length of a short + (size of the 4 parallels arrays + // describing segments * length of a short). + var headerSize = (12 * 2 + (ranges.length * 4 * 2)); - var segCount = ranges.length + 1; - var segCount2 = segCount * 2; - var searchRange = FontsUtils.getMaxPower2(segCount) * 2; - var searchEntry = Math.log(segCount) / Math.log(2); - var rangeShift = 2 * segCount - searchRange; - var cmap = [].concat( - [ - 0x00, 0x00, // version - 0x00, 0x01, // numTables - 0x00, 0x03, // platformID - 0x00, 0x01, // encodingID - 0x00, 0x00, 0x00, 0x0C, // start of the table record - 0x00, 0x04 // format - ], - FontsUtils.integerToBytes(headerSize, 2), // length - [0x00, 0x00], // language - FontsUtils.integerToBytes(segCount2, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(searchEntry, 2), - FontsUtils.integerToBytes(rangeShift, 2) - ); + var segCount = ranges.length + 1; + var segCount2 = segCount * 2; + var searchRange = FontsUtils.getMaxPower2(segCount) * 2; + var searchEntry = Math.log(segCount) / Math.log(2); + var rangeShift = 2 * segCount - searchRange; + var cmap = [].concat( + [ + 0x00, 0x00, // version + 0x00, 0x01, // numTables + 0x00, 0x03, // platformID + 0x00, 0x01, // encodingID + 0x00, 0x00, 0x00, 0x0C, // start of the table record + 0x00, 0x04 // format + ], + FontsUtils.integerToBytes(headerSize, 2), // length + [0x00, 0x00], // language + FontsUtils.integerToBytes(segCount2, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(searchEntry, 2), + FontsUtils.integerToBytes(rangeShift, 2) + ); - // Fill up the 4 parallel arrays describing the segments. - var startCount = []; - var endCount = []; - var idDeltas = []; - var idRangeOffsets = []; - var glyphsIdsArray = []; - var bias = 0; - for (var i = 0; i < segCount - 1; i++) { - var range = ranges[i]; - var start = FontsUtils.integerToBytes(range[0], 2); - var end = FontsUtils.integerToBytes(range[range.length - 1], 2); + // Fill up the 4 parallel arrays describing the segments. + var startCount = []; + var endCount = []; + var idDeltas = []; + var idRangeOffsets = []; + var glyphsIdsArray = []; + var bias = 0; + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = FontsUtils.integerToBytes(range[0], 2); + var end = FontsUtils.integerToBytes(range[range.length - 1], 2); - var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); - bias += range.length; + var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); + bias += range.length; - // deltas are signed shorts - delta[0] ^= 0xFF; - delta[1] ^= 0xFF; - delta[1] += 1; + // deltas are signed shorts + delta[0] ^= 0xFF; + delta[1] ^= 0xFF; + delta[1] += 1; - startCount.push(start[0], start[1]); - endCount.push(end[0], end[1]); - idDeltas.push(delta[0], delta[1]); + startCount.push(start[0], start[1]); + endCount.push(end[0], end[1]); + idDeltas.push(delta[0], delta[1]); + idRangeOffsets.push(0x00, 0x00); + + for (var j = 0; j < range.length; j++) + glyphsIdsArray.push(range[j]); + } + startCount.push(0xFF, 0xFF); + endCount.push(0xFF, 0xFF); + idDeltas.push(0x00, 0x01); idRangeOffsets.push(0x00, 0x00); - for (var j = 0; j < range.length; j++) - glyphsIdsArray.push(range[j]); + return cmap.concat(endCount, [0x00, 0x00], startCount, + idDeltas, idRangeOffsets, glyphsIdsArray); + }, + + cover: function font_cover(aFont, aProperties) { + var otf = new Uint8Array(kMaxFontFileSize); + + // Required Tables + var CFF = aFont.data, // PostScript Font Program + OS2 = [], // OS/2 and Windows Specific metrics + cmap = [], // Character to glyphs mapping + head = [], // Font eader + hhea = [], // Horizontal header + hmtx = [], // Horizontal metrics + maxp = [], // Maximum profile + name = [], // Naming tables + post = []; // PostScript informations + var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; + + // The offsets object holds at the same time a representation of where + // to write the table entry information about a table and another offset + // representing the offset where to draw the actual data of a particular + // table + var offsets = { + currentOffset: 0, + virtualOffset: tables.length * (4 * 4) + }; + + // For files with only one font the offset table is the first thing of the + // file + this._createOpenTypeHeader(otf, offsets, tables.length); + + // XXX It is probable that in a future we want to get rid of this glue + // between the CFF and the OTF format in order to be able to embed TrueType + // data. + this._createTableEntry(otf, offsets, "CFF ", CFF); + + /** OS/2 */ + OS2 = [ + 0x00, 0x03, // version + 0x02, 0x24, // xAvgCharWidth + 0x01, 0xF4, // usWeightClass + 0x00, 0x05, // usWidthClass + 0x00, 0x00, // fstype + 0x02, 0x8A, // ySubscriptXSize + 0x02, 0xBB, // ySubscriptYSize + 0x00, 0x00, // ySubscriptXOffset + 0x00, 0x8C, // ySubscriptYOffset + 0x02, 0x8A, // ySuperScriptXSize + 0x02, 0xBB, // ySuperScriptYSize + 0x00, 0x00, // ySuperScriptXOffset + 0x01, 0xDF, // ySuperScriptYOffset + 0x00, 0x31, // yStrikeOutSize + 0x01, 0x02, // yStrikeOutPosition + 0x00, 0x00, // sFamilyClass + 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) + 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) + 0x2A, 0x32, 0x31, 0x2A, // achVendID + 0x00, 0x20, // fsSelection + 0x00, 0x2D, // usFirstCharIndex + 0x00, 0x7A, // usLastCharIndex + 0x00, 0x03, // sTypoAscender + 0x00, 0x20, // sTypeDescender + 0x00, 0x38, // sTypoLineGap + 0x00, 0x5A, // usWinAscent + 0x02, 0xB4, // usWinDescent + 0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31) + 0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63) + 0x00, 0x00, // sxHeight + 0x00, 0x00, // sCapHeight + 0x00, 0x01, // usDefaultChar + 0x00, 0xCD, // usBreakChar + 0x00, 0x02 // usMaxContext + ]; + this._createTableEntry(otf, offsets, "OS/2", OS2); + + //XXX Getting charstrings here seems wrong since this is another CFF glue + var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); + + /** CMAP */ + cmap = this._createCMAPTable(charstrings); + this._createTableEntry(otf, offsets, "cmap", cmap); + + /** HEAD */ + head = [ + 0x00, 0x01, 0x00, 0x00, // Version number + 0x00, 0x00, 0x50, 0x00, // fontRevision + 0x00, 0x00, 0x00, 0x00, // checksumAdjustement + 0x5F, 0x0F, 0x3C, 0xF5, // magicNumber + 0x00, 0x00, // Flags + 0x03, 0xE8, // unitsPerEM (defaulting to 1000) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // creation date + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // modifification date + 0x00, 0x00, // xMin + 0x00, 0x00, // yMin + 0x00, 0x00, // xMax + 0x00, 0x00, // yMax + 0x00, 0x00, // macStyle + 0x00, 0x00, // lowestRecPPEM + 0x00, 0x00, // fontDirectionHint + 0x00, 0x00, // indexToLocFormat + 0x00, 0x00 // glyphDataFormat + ]; + this._createTableEntry(otf, offsets, "head", head); + + /** HHEA */ + hhea = [].concat( + [ + 0x00, 0x01, 0x00, 0x00, // Version number + 0x00, 0x00, // Typographic Ascent + 0x00, 0x00, // Typographic Descent + 0x00, 0x00, // Line Gap + 0xFF, 0xFF, // advanceWidthMax + 0x00, 0x00, // minLeftSidebearing + 0x00, 0x00, // minRightSidebearing + 0x00, 0x00, // xMaxExtent + 0x00, 0x00, // caretSlopeRise + 0x00, 0x00, // caretSlopeRun + 0x00, 0x00, // caretOffset + 0x00, 0x00, // -reserved- + 0x00, 0x00, // -reserved- + 0x00, 0x00, // -reserved- + 0x00, 0x00, // -reserved- + 0x00, 0x00 // metricDataFormat + ], + FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics + ); + this._createTableEntry(otf, offsets, "hhea", hhea); + + /** HMTX */ + hmtx = [0x01, 0xF4, 0x00, 0x00]; + for (var i = 0; i < charstrings.length; i++) { + var charstring = charstrings[i].charstring; + var width = FontsUtils.integerToBytes(charstring[1], 2); + var lsb = FontsUtils.integerToBytes(charstring[0], 2); + hmtx = hmtx.concat(width, lsb); + } + this._createTableEntry(otf, offsets, "hmtx", hmtx); + + /** MAXP */ + maxp = [].concat( + [ + 0x00, 0x00, 0x50, 0x00, // Version number + ], + FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...) + ); + this._createTableEntry(otf, offsets, "maxp", maxp); + + /** NAME */ + name = [ + 0x00, 0x00, // format + 0x00, 0x00, // Number of names Record + 0x00, 0x00 // Storage + ]; + this._createTableEntry(otf, offsets, "name", name); + + /** POST */ + // FIXME Get those informations from the FontInfo structure + post = [ + 0x00, 0x03, 0x00, 0x00, // Version number + 0x00, 0x00, 0x01, 0x00, // italicAngle + 0x00, 0x00, // underlinePosition + 0x00, 0x00, // underlineThickness + 0x00, 0x00, 0x00, 0x00, // isFixedPitch + 0x00, 0x00, 0x00, 0x00, // minMemType42 + 0x00, 0x00, 0x00, 0x00, // maxMemType42 + 0x00, 0x00, 0x00, 0x00, // minMemType1 + 0x00, 0x00, 0x00, 0x00 // maxMemType1 + ]; + this._createTableEntry(otf, offsets, "post", post); + + // Once all the table entries header are written, dump the data! + var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + otf.set(table, offsets.currentOffset); + offsets.currentOffset += table.length; + } + + var fontData = []; + for (var i = 0; i < offsets.currentOffset; i++) + fontData.push(otf[i]); + return fontData; } - startCount.push(0xFF, 0xFF); - endCount.push(0xFF, 0xFF); - idDeltas.push(0x00, 0x01); - idRangeOffsets.push(0x00, 0x00); - - return cmap.concat(endCount, [0x00, 0x00], startCount, - idDeltas, idRangeOffsets, glyphsIdsArray); - }, - - cover: function font_cover(aFont, aProperties) { - var otf = new Uint8Array(kMaxFontFileSize); - - // Required Tables - var CFF = aFont.data, // PostScript Font Program - OS2 = [], // OS/2 and Windows Specific metrics - cmap = [], // Character to glyphs mapping - head = [], // Font eader - hhea = [], // Horizontal header - hmtx = [], // Horizontal metrics - maxp = [], // Maximum profile - name = [], // Naming tables - post = []; // PostScript informations - var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; - - // The offsets object holds at the same time a representation of where - // to write the table entry information about a table and another offset - // representing the offset where to draw the actual data of a particular - // table - var offsets = { - currentOffset: 0, - virtualOffset: tables.length * (4 * 4) - }; - - // For files with only one font the offset table is the first thing of the - // file - this._createOpenTypeHeader(otf, offsets, tables.length); - - // XXX It is probable that in a future we want to get rid of this glue - // between the CFF and the OTF format in order to be able to embed TrueType - // data. - this._createTableEntry(otf, offsets, "CFF ", CFF); - - /** OS/2 */ - OS2 = [ - 0x00, 0x03, // version - 0x02, 0x24, // xAvgCharWidth - 0x01, 0xF4, // usWeightClass - 0x00, 0x05, // usWidthClass - 0x00, 0x00, // fstype - 0x02, 0x8A, // ySubscriptXSize - 0x02, 0xBB, // ySubscriptYSize - 0x00, 0x00, // ySubscriptXOffset - 0x00, 0x8C, // ySubscriptYOffset - 0x02, 0x8A, // ySuperScriptXSize - 0x02, 0xBB, // ySuperScriptYSize - 0x00, 0x00, // ySuperScriptXOffset - 0x01, 0xDF, // ySuperScriptYOffset - 0x00, 0x31, // yStrikeOutSize - 0x01, 0x02, // yStrikeOutPosition - 0x00, 0x00, // sFamilyClass - 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) - 0x2A, 0x32, 0x31, 0x2A, // achVendID - 0x00, 0x20, // fsSelection - 0x00, 0x2D, // usFirstCharIndex - 0x00, 0x7A, // usLastCharIndex - 0x00, 0x03, // sTypoAscender - 0x00, 0x20, // sTypeDescender - 0x00, 0x38, // sTypoLineGap - 0x00, 0x5A, // usWinAscent - 0x02, 0xB4, // usWinDescent - 0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31) - 0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63) - 0x00, 0x00, // sxHeight - 0x00, 0x00, // sCapHeight - 0x00, 0x01, // usDefaultChar - 0x00, 0xCD, // usBreakChar - 0x00, 0x02 // usMaxContext - ]; - this._createTableEntry(otf, offsets, "OS/2", OS2); - - //XXX Getting charstrings here seems wrong since this is another CFF glue - var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); - - /** CMAP */ - cmap = this._createCMAPTable(charstrings); - this._createTableEntry(otf, offsets, "cmap", cmap); - - /** HEAD */ - head = [ - 0x00, 0x01, 0x00, 0x00, // Version number - 0x00, 0x00, 0x50, 0x00, // fontRevision - 0x00, 0x00, 0x00, 0x00, // checksumAdjustement - 0x5F, 0x0F, 0x3C, 0xF5, // magicNumber - 0x00, 0x00, // Flags - 0x03, 0xE8, // unitsPerEM (defaulting to 1000) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // creation date - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // modifification date - 0x00, 0x00, // xMin - 0x00, 0x00, // yMin - 0x00, 0x00, // xMax - 0x00, 0x00, // yMax - 0x00, 0x00, // macStyle - 0x00, 0x00, // lowestRecPPEM - 0x00, 0x00, // fontDirectionHint - 0x00, 0x00, // indexToLocFormat - 0x00, 0x00 // glyphDataFormat - ]; - this._createTableEntry(otf, offsets, "head", head); - - /** HHEA */ - hhea = [].concat( - [ - 0x00, 0x01, 0x00, 0x00, // Version number - 0x00, 0x00, // Typographic Ascent - 0x00, 0x00, // Typographic Descent - 0x00, 0x00, // Line Gap - 0xFF, 0xFF, // advanceWidthMax - 0x00, 0x00, // minLeftSidebearing - 0x00, 0x00, // minRightSidebearing - 0x00, 0x00, // xMaxExtent - 0x00, 0x00, // caretSlopeRise - 0x00, 0x00, // caretSlopeRun - 0x00, 0x00, // caretOffset - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00 // metricDataFormat - ], - FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics - ); - this._createTableEntry(otf, offsets, "hhea", hhea); - - /** HMTX */ - hmtx = [0x01, 0xF4, 0x00, 0x00]; - for (var i = 0; i < charstrings.length; i++) { - var charstring = charstrings[i].charstring; - var width = FontsUtils.integerToBytes(charstring[1], 2); - var lsb = FontsUtils.integerToBytes(charstring[0], 2); - hmtx = hmtx.concat(width, lsb); - } - this._createTableEntry(otf, offsets, "hmtx", hmtx); - - /** MAXP */ - maxp = [].concat( - [ - 0x00, 0x00, 0x50, 0x00, // Version number - ], - FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...) - ); - this._createTableEntry(otf, offsets, "maxp", maxp); - - /** NAME */ - name = [ - 0x00, 0x00, // format - 0x00, 0x00, // Number of names Record - 0x00, 0x00 // Storage - ]; - this._createTableEntry(otf, offsets, "name", name); - - /** POST */ - // FIXME Get those informations from the FontInfo structure - post = [ - 0x00, 0x03, 0x00, 0x00, // Version number - 0x00, 0x00, 0x01, 0x00, // italicAngle - 0x00, 0x00, // underlinePosition - 0x00, 0x00, // underlineThickness - 0x00, 0x00, 0x00, 0x00, // isFixedPitch - 0x00, 0x00, 0x00, 0x00, // minMemType42 - 0x00, 0x00, 0x00, 0x00, // maxMemType42 - 0x00, 0x00, 0x00, 0x00, // minMemType1 - 0x00, 0x00, 0x00, 0x00 // maxMemType1 - ]; - this._createTableEntry(otf, offsets, "post", post); - - // Once all the table entries header are written, dump the data! - var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - otf.set(table, offsets.currentOffset); - offsets.currentOffset += table.length; - } - - var fontData = []; - for (var i = 0; i < offsets.currentOffset; i++) - fontData.push(otf[i]); - return fontData; - } -}; + }; + return constructor; +})(); /** * FontsUtils is a static class dedicated to hold codes that are not related From 886054080e38ad325e4fe3400bce82c738790295 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:54:27 -0700 Subject: [PATCH 106/439] make createOpenTypeHeader and createTableEntry inner functions --- fonts.js | 135 +++++++++++++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/fonts.js b/fonts.js index 85a5c199d..fcd55d20e 100644 --- a/fonts.js +++ b/fonts.js @@ -138,6 +138,63 @@ var Font = (function () { this.bind(); }; + function createOpenTypeHeader(aFile, aOffsets, aNumTables) { + // sfnt version (4 bytes) + var version = [0x4F, 0x54, 0x54, 0X4F]; + + // numTables (2 bytes) + var numTables = aNumTables; + + // searchRange (2 bytes) + var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); + var searchRange = tablesMaxPower2 * 16; + + // entrySelector (2 bytes) + var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); + + // rangeShift (2 bytes) + var rangeShift = numTables * 16 - searchRange; + + var header = [].concat(version, + FontsUtils.integerToBytes(numTables, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(entrySelector, 2), + FontsUtils.integerToBytes(rangeShift, 2)); + aFile.set(header, aOffsets.currentOffset); + aOffsets.currentOffset += header.length; + aOffsets.virtualOffset += header.length; + } + + function createTableEntry(aFile, aOffsets, aTag, aData) { + // tag + var tag = [ + aTag.charCodeAt(0), + aTag.charCodeAt(1), + aTag.charCodeAt(2), + aTag.charCodeAt(3) + ]; + + // offset + var offset = aOffsets.virtualOffset; + + // Per spec tables must be 4-bytes align so add some 0x00 if needed + while (aData.length & 3) + aData.push(0x00); + + // length + var length = aData.length; + + // checksum + var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + + var tableEntry = [].concat(tag, + FontsUtils.integerToBytes(checksum, 4), + FontsUtils.integerToBytes(offset, 4), + FontsUtils.integerToBytes(length, 4)); + aFile.set(tableEntry, aOffsets.currentOffset); + aOffsets.currentOffset += tableEntry.length; + aOffsets.virtualOffset += aData.length; + } /** * A bunch of the OpenType code is duplicate between this class and the @@ -242,64 +299,6 @@ var Font = (function () { styleSheet.insertRule(rule, styleSheet.length); }, - _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) { - // sfnt version (4 bytes) - var version = [0x4F, 0x54, 0x54, 0X4F]; - - // numTables (2 bytes) - var numTables = aNumTables; - - // searchRange (2 bytes) - var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); - var searchRange = tablesMaxPower2 * 16; - - // entrySelector (2 bytes) - var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); - - // rangeShift (2 bytes) - var rangeShift = numTables * 16 - searchRange; - - var header = [].concat(version, - FontsUtils.integerToBytes(numTables, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(entrySelector, 2), - FontsUtils.integerToBytes(rangeShift, 2)); - aFile.set(header, aOffsets.currentOffset); - aOffsets.currentOffset += header.length; - aOffsets.virtualOffset += header.length; - }, - - _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) { - // tag - var tag = [ - aTag.charCodeAt(0), - aTag.charCodeAt(1), - aTag.charCodeAt(2), - aTag.charCodeAt(3) - ]; - - // offset - var offset = aOffsets.virtualOffset; - - // Per spec tables must be 4-bytes align so add some 0x00 if needed - while (aData.length & 3) - aData.push(0x00); - - // length - var length = aData.length; - - // checksum - var checksum = FontsUtils.bytesToInteger(tag) + offset + length; - - var tableEntry = [].concat(tag, - FontsUtils.integerToBytes(checksum, 4), - FontsUtils.integerToBytes(offset, 4), - FontsUtils.integerToBytes(length, 4)); - aFile.set(tableEntry, aOffsets.currentOffset); - aOffsets.currentOffset += tableEntry.length; - aOffsets.virtualOffset += aData.length; - }, - _createCMAPTable: function font_createCMAPTable(aGlyphs) { var characters = new Uint16Array(kMaxGlyphsCount); for (var i = 0; i < aGlyphs.length; i++) @@ -408,12 +407,12 @@ var Font = (function () { // For files with only one font the offset table is the first thing of the // file - this._createOpenTypeHeader(otf, offsets, tables.length); + createOpenTypeHeader(otf, offsets, tables.length); // XXX It is probable that in a future we want to get rid of this glue // between the CFF and the OTF format in order to be able to embed TrueType // data. - this._createTableEntry(otf, offsets, "CFF ", CFF); + createTableEntry(otf, offsets, "CFF ", CFF); /** OS/2 */ OS2 = [ @@ -455,14 +454,14 @@ var Font = (function () { 0x00, 0xCD, // usBreakChar 0x00, 0x02 // usMaxContext ]; - this._createTableEntry(otf, offsets, "OS/2", OS2); + createTableEntry(otf, offsets, "OS/2", OS2); //XXX Getting charstrings here seems wrong since this is another CFF glue var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); /** CMAP */ cmap = this._createCMAPTable(charstrings); - this._createTableEntry(otf, offsets, "cmap", cmap); + createTableEntry(otf, offsets, "cmap", cmap); /** HEAD */ head = [ @@ -484,7 +483,7 @@ var Font = (function () { 0x00, 0x00, // indexToLocFormat 0x00, 0x00 // glyphDataFormat ]; - this._createTableEntry(otf, offsets, "head", head); + createTableEntry(otf, offsets, "head", head); /** HHEA */ hhea = [].concat( @@ -508,7 +507,7 @@ var Font = (function () { ], FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics ); - this._createTableEntry(otf, offsets, "hhea", hhea); + createTableEntry(otf, offsets, "hhea", hhea); /** HMTX */ hmtx = [0x01, 0xF4, 0x00, 0x00]; @@ -518,7 +517,7 @@ var Font = (function () { var lsb = FontsUtils.integerToBytes(charstring[0], 2); hmtx = hmtx.concat(width, lsb); } - this._createTableEntry(otf, offsets, "hmtx", hmtx); + createTableEntry(otf, offsets, "hmtx", hmtx); /** MAXP */ maxp = [].concat( @@ -527,7 +526,7 @@ var Font = (function () { ], FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...) ); - this._createTableEntry(otf, offsets, "maxp", maxp); + createTableEntry(otf, offsets, "maxp", maxp); /** NAME */ name = [ @@ -535,7 +534,7 @@ var Font = (function () { 0x00, 0x00, // Number of names Record 0x00, 0x00 // Storage ]; - this._createTableEntry(otf, offsets, "name", name); + createTableEntry(otf, offsets, "name", name); /** POST */ // FIXME Get those informations from the FontInfo structure @@ -550,7 +549,7 @@ var Font = (function () { 0x00, 0x00, 0x00, 0x00, // minMemType1 0x00, 0x00, 0x00, 0x00 // maxMemType1 ]; - this._createTableEntry(otf, offsets, "post", post); + createTableEntry(otf, offsets, "post", post); // Once all the table entries header are written, dump the data! var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; From 1a5105741734578c3215af114b8c885a16b83498 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:58:02 -0700 Subject: [PATCH 107/439] make createOpenTypeHeader and createTableEntry inner functions of co(n)ver(t) so we can use an upvar to collect the output --- fonts.js | 116 +++++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/fonts.js b/fonts.js index fcd55d20e..1250bf558 100644 --- a/fonts.js +++ b/fonts.js @@ -138,64 +138,6 @@ var Font = (function () { this.bind(); }; - function createOpenTypeHeader(aFile, aOffsets, aNumTables) { - // sfnt version (4 bytes) - var version = [0x4F, 0x54, 0x54, 0X4F]; - - // numTables (2 bytes) - var numTables = aNumTables; - - // searchRange (2 bytes) - var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); - var searchRange = tablesMaxPower2 * 16; - - // entrySelector (2 bytes) - var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); - - // rangeShift (2 bytes) - var rangeShift = numTables * 16 - searchRange; - - var header = [].concat(version, - FontsUtils.integerToBytes(numTables, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(entrySelector, 2), - FontsUtils.integerToBytes(rangeShift, 2)); - aFile.set(header, aOffsets.currentOffset); - aOffsets.currentOffset += header.length; - aOffsets.virtualOffset += header.length; - } - - function createTableEntry(aFile, aOffsets, aTag, aData) { - // tag - var tag = [ - aTag.charCodeAt(0), - aTag.charCodeAt(1), - aTag.charCodeAt(2), - aTag.charCodeAt(3) - ]; - - // offset - var offset = aOffsets.virtualOffset; - - // Per spec tables must be 4-bytes align so add some 0x00 if needed - while (aData.length & 3) - aData.push(0x00); - - // length - var length = aData.length; - - // checksum - var checksum = FontsUtils.bytesToInteger(tag) + offset + length; - - var tableEntry = [].concat(tag, - FontsUtils.integerToBytes(checksum, 4), - FontsUtils.integerToBytes(offset, 4), - FontsUtils.integerToBytes(length, 4)); - aFile.set(tableEntry, aOffsets.currentOffset); - aOffsets.currentOffset += tableEntry.length; - aOffsets.virtualOffset += aData.length; - } - /** * A bunch of the OpenType code is duplicate between this class and the * TrueType code, this is intentional and will merge in a future version @@ -384,6 +326,64 @@ var Font = (function () { cover: function font_cover(aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); + function createOpenTypeHeader(aFile, aOffsets, aNumTables) { + // sfnt version (4 bytes) + var version = [0x4F, 0x54, 0x54, 0X4F]; + + // numTables (2 bytes) + var numTables = aNumTables; + + // searchRange (2 bytes) + var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); + var searchRange = tablesMaxPower2 * 16; + + // entrySelector (2 bytes) + var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); + + // rangeShift (2 bytes) + var rangeShift = numTables * 16 - searchRange; + + var header = [].concat(version, + FontsUtils.integerToBytes(numTables, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(entrySelector, 2), + FontsUtils.integerToBytes(rangeShift, 2)); + aFile.set(header, aOffsets.currentOffset); + aOffsets.currentOffset += header.length; + aOffsets.virtualOffset += header.length; + } + + function createTableEntry(aFile, aOffsets, aTag, aData) { + // tag + var tag = [ + aTag.charCodeAt(0), + aTag.charCodeAt(1), + aTag.charCodeAt(2), + aTag.charCodeAt(3) + ]; + + // offset + var offset = aOffsets.virtualOffset; + + // Per spec tables must be 4-bytes align so add some 0x00 if needed + while (aData.length & 3) + aData.push(0x00); + + // length + var length = aData.length; + + // checksum + var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + + var tableEntry = [].concat(tag, + FontsUtils.integerToBytes(checksum, 4), + FontsUtils.integerToBytes(offset, 4), + FontsUtils.integerToBytes(length, 4)); + aFile.set(tableEntry, aOffsets.currentOffset); + aOffsets.currentOffset += tableEntry.length; + aOffsets.virtualOffset += aData.length; + } + // Required Tables var CFF = aFont.data, // PostScript Font Program OS2 = [], // OS/2 and Windows Specific metrics From bb40d20eae6ddf0e92dfe5b074545630547ecb61 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 15:58:30 -0700 Subject: [PATCH 108/439] rename conver to convert --- fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 1250bf558..5ee3cc8f7 100644 --- a/fonts.js +++ b/fonts.js @@ -101,7 +101,7 @@ var Font = (function () { this.mimetype = "font/otf"; // Wrap the CFF data inside an OTF font file - this.font = this.cover(cff, aProperties); + this.font = this.convert(cff, aProperties); break; case "TrueType": @@ -323,7 +323,7 @@ var Font = (function () { idDeltas, idRangeOffsets, glyphsIdsArray); }, - cover: function font_cover(aFont, aProperties) { + convert: function font_convert(aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); function createOpenTypeHeader(aFile, aOffsets, aNumTables) { From c09ee48094b504028cf2f55976842bb3149bad1e Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 16:13:59 -0700 Subject: [PATCH 109/439] write OTF header using a string, not an array --- fonts.js | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 5ee3cc8f7..c599af2a4 100644 --- a/fonts.js +++ b/fonts.js @@ -326,29 +326,39 @@ var Font = (function () { convert: function font_convert(aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); - function createOpenTypeHeader(aFile, aOffsets, aNumTables) { + function s2a(s) { + var a = []; + for (var i = 0; i < s.length; ++i) + a[i] = s.charCodeAt(i); + return a; + } + + function createOpenTypeHeader(aFile, aOffsets, numTables) { + var header = ""; + + function WriteHeader16(value) { + header += String.fromCharCode(value >> 8); + header += String.fromCharCode(value & 0xff); + } + // sfnt version (4 bytes) - var version = [0x4F, 0x54, 0x54, 0X4F]; + header += "\x4F\x54\x54\x4F"; // numTables (2 bytes) - var numTables = aNumTables; + WriteHeader16(numTables); // searchRange (2 bytes) var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); var searchRange = tablesMaxPower2 * 16; + WriteHeader16(searchRange); // entrySelector (2 bytes) - var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); + WriteHeader16(Math.log(tablesMaxPower2) / Math.log(2)); // rangeShift (2 bytes) - var rangeShift = numTables * 16 - searchRange; + WriteHeader16(numTables * 16 - searchRange); - var header = [].concat(version, - FontsUtils.integerToBytes(numTables, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(entrySelector, 2), - FontsUtils.integerToBytes(rangeShift, 2)); - aFile.set(header, aOffsets.currentOffset); + aFile.set(s2a(header), aOffsets.currentOffset); aOffsets.currentOffset += header.length; aOffsets.virtualOffset += header.length; } From a118f9035a82b2a576d849533a1c6495c5319f9d Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 16:32:26 -0700 Subject: [PATCH 110/439] in preparation for using strings to write out font data, store constant blobs as strings --- fonts.js | 195 +++++++++++++++++++++++++++---------------------------- 1 file changed, 96 insertions(+), 99 deletions(-) diff --git a/fonts.js b/fonts.js index c599af2a4..3bc71e683 100644 --- a/fonts.js +++ b/fonts.js @@ -333,30 +333,29 @@ var Font = (function () { return a; } + function s16(value) { + return String.fromCharCode(value >> 8) + String.fromCharCode(value & 0xff); + } + function createOpenTypeHeader(aFile, aOffsets, numTables) { var header = ""; - function WriteHeader16(value) { - header += String.fromCharCode(value >> 8); - header += String.fromCharCode(value & 0xff); - } - // sfnt version (4 bytes) header += "\x4F\x54\x54\x4F"; // numTables (2 bytes) - WriteHeader16(numTables); + header += s16(numTables); // searchRange (2 bytes) var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); var searchRange = tablesMaxPower2 * 16; - WriteHeader16(searchRange); + header += s16(searchRange); // entrySelector (2 bytes) - WriteHeader16(Math.log(tablesMaxPower2) / Math.log(2)); + header += s16(Math.log(tablesMaxPower2) / Math.log(2)); // rangeShift (2 bytes) - WriteHeader16(numTables * 16 - searchRange); + header += s16(numTables * 16 - searchRange); aFile.set(s2a(header), aOffsets.currentOffset); aOffsets.currentOffset += header.length; @@ -425,45 +424,45 @@ var Font = (function () { createTableEntry(otf, offsets, "CFF ", CFF); /** OS/2 */ - OS2 = [ - 0x00, 0x03, // version - 0x02, 0x24, // xAvgCharWidth - 0x01, 0xF4, // usWeightClass - 0x00, 0x05, // usWidthClass - 0x00, 0x00, // fstype - 0x02, 0x8A, // ySubscriptXSize - 0x02, 0xBB, // ySubscriptYSize - 0x00, 0x00, // ySubscriptXOffset - 0x00, 0x8C, // ySubscriptYOffset - 0x02, 0x8A, // ySuperScriptXSize - 0x02, 0xBB, // ySuperScriptYSize - 0x00, 0x00, // ySuperScriptXOffset - 0x01, 0xDF, // ySuperScriptYOffset - 0x00, 0x31, // yStrikeOutSize - 0x01, 0x02, // yStrikeOutPosition - 0x00, 0x00, // sFamilyClass - 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) - 0x2A, 0x32, 0x31, 0x2A, // achVendID - 0x00, 0x20, // fsSelection - 0x00, 0x2D, // usFirstCharIndex - 0x00, 0x7A, // usLastCharIndex - 0x00, 0x03, // sTypoAscender - 0x00, 0x20, // sTypeDescender - 0x00, 0x38, // sTypoLineGap - 0x00, 0x5A, // usWinAscent - 0x02, 0xB4, // usWinDescent - 0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31) - 0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63) - 0x00, 0x00, // sxHeight - 0x00, 0x00, // sCapHeight - 0x00, 0x01, // usDefaultChar - 0x00, 0xCD, // usBreakChar - 0x00, 0x02 // usMaxContext - ]; + OS2 = s2a( + "\x00\x03" + // version + "\x02\x24" + // xAvgCharWidth + "\x01\xF4" + // usWeightClass + "\x00\x05" + // usWidthClass + "\x00\x00" + // fstype + "\x02\x8A" + // ySubscriptXSize + "\x02\xBB" + // ySubscriptYSize + "\x00\x00" + // ySubscriptXOffset + "\x00\x8C" + // ySubscriptYOffset + "\x02\x8A" + // ySuperScriptXSize + "\x02\xBB" + // ySuperScriptYSize + "\x00\x00" + // ySuperScriptXOffset + "\x01\xDF" + // ySuperScriptYOffset + "\x00\x31" + // yStrikeOutSize + "\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) + "\x2A\x32\x31\x2A" + // achVendID + "\x00\x20" + // fsSelection + "\x00\x2D" + // usFirstCharIndex + "\x00\x7A" + // usLastCharIndex + "\x00\x03" + // sTypoAscender + "\x00\x20" + // sTypeDescender + "\x00\x38" + // sTypoLineGap + "\x00\x5A" + // usWinAscent + "\x02\xB4" + // usWinDescent + "\x00\xCE\x00\x00" + // ulCodePageRange1 (Bits 0-31) + "\x00\x01\x00\x00" + // ulCodePageRange2 (Bits 32-63) + "\x00\x00" + // sxHeight + "\x00\x00" + // sCapHeight + "\x00\x01" + // usDefaultChar + "\x00\xCD" + // usBreakChar + "\x00\x02" // usMaxContext + ); createTableEntry(otf, offsets, "OS/2", OS2); //XXX Getting charstrings here seems wrong since this is another CFF glue @@ -474,49 +473,47 @@ var Font = (function () { createTableEntry(otf, offsets, "cmap", cmap); /** HEAD */ - head = [ - 0x00, 0x01, 0x00, 0x00, // Version number - 0x00, 0x00, 0x50, 0x00, // fontRevision - 0x00, 0x00, 0x00, 0x00, // checksumAdjustement - 0x5F, 0x0F, 0x3C, 0xF5, // magicNumber - 0x00, 0x00, // Flags - 0x03, 0xE8, // unitsPerEM (defaulting to 1000) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // creation date - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // modifification date - 0x00, 0x00, // xMin - 0x00, 0x00, // yMin - 0x00, 0x00, // xMax - 0x00, 0x00, // yMax - 0x00, 0x00, // macStyle - 0x00, 0x00, // lowestRecPPEM - 0x00, 0x00, // fontDirectionHint - 0x00, 0x00, // indexToLocFormat - 0x00, 0x00 // glyphDataFormat - ]; + head = s2a( + "\x00\x01\x00\x00" + // Version number + "\x00\x00\x50\x00" + // fontRevision + "\x00\x00\x00\x00" + // checksumAdjustement + "\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" + // xMin + "\x00\x00" + // yMin + "\x00\x00" + // xMax + "\x00\x00" + // yMax + "\x00\x00" + // macStyle + "\x00\x00" + // lowestRecPPEM + "\x00\x00" + // fontDirectionHint + "\x00\x00" + // indexToLocFormat + "\x00\x00" // glyphDataFormat + ); createTableEntry(otf, offsets, "head", head); /** HHEA */ - hhea = [].concat( - [ - 0x00, 0x01, 0x00, 0x00, // Version number - 0x00, 0x00, // Typographic Ascent - 0x00, 0x00, // Typographic Descent - 0x00, 0x00, // Line Gap - 0xFF, 0xFF, // advanceWidthMax - 0x00, 0x00, // minLeftSidebearing - 0x00, 0x00, // minRightSidebearing - 0x00, 0x00, // xMaxExtent - 0x00, 0x00, // caretSlopeRise - 0x00, 0x00, // caretSlopeRun - 0x00, 0x00, // caretOffset - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00, // -reserved- - 0x00, 0x00 // metricDataFormat - ], - FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics - ); + hhea = s2a( + "\x00\x01\x00\x00" + // Version number + "\x00\x00" + // Typographic Ascent + "\x00\x00" + // Typographic Descent + "\x00\x00" + // Line Gap + "\xFF\xFF" + // advanceWidthMax + "\x00\x00" + // minLeftSidebearing + "\x00\x00" + // minRightSidebearing + "\x00\x00" + // xMaxExtent + "\x00\x00" + // caretSlopeRise + "\x00\x00" + // caretSlopeRun + "\x00\x00" + // caretOffset + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // metricDataFormat + s16(charstrings.length) + ); createTableEntry(otf, offsets, "hhea", hhea); /** HMTX */ @@ -548,17 +545,17 @@ var Font = (function () { /** POST */ // FIXME Get those informations from the FontInfo structure - post = [ - 0x00, 0x03, 0x00, 0x00, // Version number - 0x00, 0x00, 0x01, 0x00, // italicAngle - 0x00, 0x00, // underlinePosition - 0x00, 0x00, // underlineThickness - 0x00, 0x00, 0x00, 0x00, // isFixedPitch - 0x00, 0x00, 0x00, 0x00, // minMemType42 - 0x00, 0x00, 0x00, 0x00, // maxMemType42 - 0x00, 0x00, 0x00, 0x00, // minMemType1 - 0x00, 0x00, 0x00, 0x00 // maxMemType1 - ]; + post = s2a( + "\x00\x03\x00\x00" + // Version number + "\x00\x00\x01\x00" + // 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 + ); createTableEntry(otf, offsets, "post", post); // Once all the table entries header are written, dump the data! From 4fc8a1fa755480a26eb0f427260549259dcfd3e2 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Sun, 19 Jun 2011 16:35:32 -0700 Subject: [PATCH 111/439] make createCMAPTable a nested function function --- fonts.js | 166 +++++++++++++++++++++++++++---------------------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/fonts.js b/fonts.js index 3bc71e683..2ee8a0d3c 100644 --- a/fonts.js +++ b/fonts.js @@ -241,88 +241,6 @@ var Font = (function () { styleSheet.insertRule(rule, styleSheet.length); }, - _createCMAPTable: function font_createCMAPTable(aGlyphs) { - var characters = new Uint16Array(kMaxGlyphsCount); - for (var i = 0; i < aGlyphs.length; i++) - characters[aGlyphs[i].unicode] = i + 1; - - // Separate the glyphs into continuous range of codes, aka segment. - var ranges = []; - var range = []; - var count = characters.length; - for (var i = 0; i < count; i++) { - if (characters[i]) { - range.push(i); - } else if (range.length) { - ranges.push(range.slice()); - range = []; - } - } - - // The size in bytes of the header is equal to the size of the - // different fields * length of a short + (size of the 4 parallels arrays - // describing segments * length of a short). - var headerSize = (12 * 2 + (ranges.length * 4 * 2)); - - var segCount = ranges.length + 1; - var segCount2 = segCount * 2; - var searchRange = FontsUtils.getMaxPower2(segCount) * 2; - var searchEntry = Math.log(segCount) / Math.log(2); - var rangeShift = 2 * segCount - searchRange; - var cmap = [].concat( - [ - 0x00, 0x00, // version - 0x00, 0x01, // numTables - 0x00, 0x03, // platformID - 0x00, 0x01, // encodingID - 0x00, 0x00, 0x00, 0x0C, // start of the table record - 0x00, 0x04 // format - ], - FontsUtils.integerToBytes(headerSize, 2), // length - [0x00, 0x00], // language - FontsUtils.integerToBytes(segCount2, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(searchEntry, 2), - FontsUtils.integerToBytes(rangeShift, 2) - ); - - // Fill up the 4 parallel arrays describing the segments. - var startCount = []; - var endCount = []; - var idDeltas = []; - var idRangeOffsets = []; - var glyphsIdsArray = []; - var bias = 0; - for (var i = 0; i < segCount - 1; i++) { - var range = ranges[i]; - var start = FontsUtils.integerToBytes(range[0], 2); - var end = FontsUtils.integerToBytes(range[range.length - 1], 2); - - var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); - bias += range.length; - - // deltas are signed shorts - delta[0] ^= 0xFF; - delta[1] ^= 0xFF; - delta[1] += 1; - - startCount.push(start[0], start[1]); - endCount.push(end[0], end[1]); - idDeltas.push(delta[0], delta[1]); - idRangeOffsets.push(0x00, 0x00); - - for (var j = 0; j < range.length; j++) - glyphsIdsArray.push(range[j]); - } - startCount.push(0xFF, 0xFF); - endCount.push(0xFF, 0xFF); - idDeltas.push(0x00, 0x01); - idRangeOffsets.push(0x00, 0x00); - - return cmap.concat(endCount, [0x00, 0x00], startCount, - idDeltas, idRangeOffsets, glyphsIdsArray); - }, - convert: function font_convert(aFont, aProperties) { var otf = new Uint8Array(kMaxFontFileSize); @@ -392,6 +310,88 @@ var Font = (function () { aOffsets.currentOffset += tableEntry.length; aOffsets.virtualOffset += aData.length; } + + function createCMAPTable(aGlyphs) { + var characters = new Uint16Array(kMaxGlyphsCount); + for (var i = 0; i < aGlyphs.length; i++) + characters[aGlyphs[i].unicode] = i + 1; + + // Separate the glyphs into continuous range of codes, aka segment. + var ranges = []; + var range = []; + var count = characters.length; + for (var i = 0; i < count; i++) { + if (characters[i]) { + range.push(i); + } else if (range.length) { + ranges.push(range.slice()); + range = []; + } + } + + // The size in bytes of the header is equal to the size of the + // different fields * length of a short + (size of the 4 parallels arrays + // describing segments * length of a short). + var headerSize = (12 * 2 + (ranges.length * 4 * 2)); + + var segCount = ranges.length + 1; + var segCount2 = segCount * 2; + var searchRange = FontsUtils.getMaxPower2(segCount) * 2; + var searchEntry = Math.log(segCount) / Math.log(2); + var rangeShift = 2 * segCount - searchRange; + var cmap = [].concat( + [ + 0x00, 0x00, // version + 0x00, 0x01, // numTables + 0x00, 0x03, // platformID + 0x00, 0x01, // encodingID + 0x00, 0x00, 0x00, 0x0C, // start of the table record + 0x00, 0x04 // format + ], + FontsUtils.integerToBytes(headerSize, 2), // length + [0x00, 0x00], // language + FontsUtils.integerToBytes(segCount2, 2), + FontsUtils.integerToBytes(searchRange, 2), + FontsUtils.integerToBytes(searchEntry, 2), + FontsUtils.integerToBytes(rangeShift, 2) + ); + + // Fill up the 4 parallel arrays describing the segments. + var startCount = []; + var endCount = []; + var idDeltas = []; + var idRangeOffsets = []; + var glyphsIdsArray = []; + var bias = 0; + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = FontsUtils.integerToBytes(range[0], 2); + var end = FontsUtils.integerToBytes(range[range.length - 1], 2); + + var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); + bias += range.length; + + // deltas are signed shorts + delta[0] ^= 0xFF; + delta[1] ^= 0xFF; + delta[1] += 1; + + startCount.push(start[0], start[1]); + endCount.push(end[0], end[1]); + idDeltas.push(delta[0], delta[1]); + idRangeOffsets.push(0x00, 0x00); + + for (var j = 0; j < range.length; j++) + glyphsIdsArray.push(range[j]); + } + startCount.push(0xFF, 0xFF); + endCount.push(0xFF, 0xFF); + idDeltas.push(0x00, 0x01); + idRangeOffsets.push(0x00, 0x00); + + return cmap.concat(endCount, [0x00, 0x00], startCount, + idDeltas, idRangeOffsets, glyphsIdsArray); + } // Required Tables var CFF = aFont.data, // PostScript Font Program @@ -469,7 +469,7 @@ var Font = (function () { var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); /** CMAP */ - cmap = this._createCMAPTable(charstrings); + cmap = createCMAPTable(charstrings); createTableEntry(otf, offsets, "cmap", cmap); /** HEAD */ From c2ce7fa7b2015f5dadaeec7eee63e08f532d22ea Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 19 Jun 2011 18:55:02 -0500 Subject: [PATCH 112/439] Ability to fetch ObjStm objects; fix DEFLATE stream double-eof-call issue; multi-item page content --- pdf.js | 80 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/pdf.js b/pdf.js index a051e57f3..f03615a64 100644 --- a/pdf.js +++ b/pdf.js @@ -308,7 +308,7 @@ var FlateStream = (function() { getByte: function() { var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength == pos) { + if (bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -333,7 +333,7 @@ var FlateStream = (function() { lookChar: function() { var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength == pos) { + if (bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -599,7 +599,7 @@ var PredictorStream = (function() { var DecryptStream = (function() { function constructor(str, fileKey, encAlgorithm, keyLength) { - // TODO + TODO("decrypt stream is not implemented"); } constructor.prototype = Stream.prototype; @@ -1475,11 +1475,12 @@ var XRef = (function() { e = this.getEntry(num); var gen = ref.gen; + var stream, parser; if (e.uncompressed) { if (e.gen != gen) throw("inconsistent generation in XRef"); - var stream = this.stream.makeSubStream(e.offset); - var parser = new Parser(new Lexer(stream), true, this); + stream = this.stream.makeSubStream(e.offset); + parser = new Parser(new Lexer(stream), true, this); var obj1 = parser.getObj(); var obj2 = parser.getObj(); var obj3 = parser.getObj(); @@ -1503,7 +1504,39 @@ var XRef = (function() { this.cache[num] = e; return e; } - error("compressed entry"); + // compressed entry + stream = this.fetch({num:e.offset, gen:0}); + if (!IsStream(stream)) + error("bad ObjStm stream"); + var first = stream.parameters.get("First"); + var n = stream.parameters.get("N"); + if (!IsInt(first) || !IsInt(n)) { + error("invalid first and n parameters for ObjStm stream"); + } + parser = new Parser(new Lexer(stream), false); + var i, entries = [], nums = []; + // read the object numbers to populate cache + for (i = 0; i < n; ++i) { + var num = parser.getObj(); + if (!IsInt(num)) { + error("invalid object number in the ObjStm stream"); + } + nums.push(num); + var offset = parser.getObj(); + if (!IsInt(offset)) { + error("invalid object offset in the ObjStm stream"); + } + } + // read stream objects for cache + for (i = 0; i < n; ++i) { + entries.push(parser.getObj()); + this.cache[nums[i]] = entries[i]; + } + e = entries[e.gen]; + if (!e) { + error("bad XRef entry for compressed object"); + } + return e; }, getCatalogObj: function() { return this.fetch(this.root); @@ -1534,20 +1567,39 @@ var Page = (function() { : null)); }, compile: function(gfx, fonts) { - if (!this.code) { - var xref = this.xref; - var content = xref.fetchIfRef(this.content); - var resources = xref.fetchIfRef(this.resources); - this.code = gfx.compile(content, xref, resources, fonts); + if (this.code) { + // content was compiled + return; } + var xref = this.xref; + var content; + var resources = xref.fetchIfRef(this.resources); + if (!IsArray(this.content)) { + // content is not an array, shortcut + content = xref.fetchIfRef(this.content); + this.code = gfx.compile(content, xref, resources, fonts); + return; + } + // the content is an array, compiling all items + var i, n = this.content.length, compiledItems = []; + for (i = 0; i < n; ++i) { + content = xref.fetchIfRef(this.content[i]); + compiledItems.push(gfx.compile(content, xref, resources, fonts)); + } + // creating the function that executes all compiled items + this.code = function(gfx) { + var i, n = compiledItems.length; + for (i = 0; i < n; ++i) { + compiledItems[i](gfx); + } + }; }, display: function(gfx) { + assert(this.code instanceof Function, "page content must be compiled first"); var xref = this.xref; - var content = xref.fetchIfRef(this.content); var resources = xref.fetchIfRef(this.resources); var mediaBox = xref.fetchIfRef(this.mediaBox); - assertWellFormed(IsStream(content) && IsDict(resources), - "invalid page content or resources"); + assertWellFormed(IsDict(resources), "invalid page resources"); gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], width: mediaBox[2] - mediaBox[0], height: mediaBox[3] - mediaBox[1] }); From 6d3d9e3b2491fb3ad21bd65f7665a36807ae74c6 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 20 Jun 2011 02:52:30 +0200 Subject: [PATCH 113/439] Add a basic embedded CMap reader --- pdf.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index 631c1a74a..7414ac7ea 100644 --- a/pdf.js +++ b/pdf.js @@ -1942,13 +1942,12 @@ var CanvasGraphics = (function() { if (!encoding) error("Unknown font encoding"); - var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); - var index = 0; for (var j = 0; j < encoding.length; j++) { encodingMap[index++] = GlyphsUnicode[encoding[j]]; } + var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); var widths = xref.fetchIfRef(fontDict.get("Widths")); assertWellFormed(IsArray(widths) && IsInt(firstChar), "invalid font Widths or FirstChar"); @@ -1959,8 +1958,66 @@ var CanvasGraphics = (function() { } } } else if (fontDict.has("ToUnicode")) { - TODO("ToUnicode stream translation not implemented"); - } + var cmapObj = xref.fetchIfRef(fontDict.get("ToUnicode")); + if (IsName(cmapObj)) { + error("ToUnicode basic cmap translation not implemented"); + encodingMap = {}; + } else if (IsStream(cmapObj)) { + var tokens = []; + var token = ""; + + var cmap = cmapObj.getBytes(cmapObj.length); + for (var i =0; i < cmap.length; i++) { + var byte = cmap[i]; + if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { + switch (token) { + case "useCMap": + error("useCMap is not implemented"); + break; + + case "begincodespacerange": + case "beginbfrange": + token = ""; + tokens = []; + break; + + case "endcodespacerange": + TODO("Support CMap ranges"); + break; + + case "endbfrange": + for (var j = 0; j < tokens.length; j+=3) { + var startRange = parseInt("0x" + tokens[j]); + var endRange = parseInt("0x" + tokens[j+1]); + var code = parseInt("0x" + tokens[j+2]); + + for (var k = startRange; k <= endRange; k++) { + encodingMap[k] = code; + charset.push(code++); + } + } + break; + + case "beginfbchar": + case "endfbchar": + error("fbchar parsing is not implemented"); + break; + + default: + if (token.length) { + tokens.push(token); + token = ""; + } + break; + } + } else if (byte == 0x5B || byte == 0x5D) { + error("CMAP list parsing is not implemented"); + } else { + token += String.fromCharCode(byte); + } + } + } + } var subType = fontDict.get("Subtype"); var bbox = descriptor.get("FontBBox"); From 5c4f26019e662e553cd402cba4ccd71a4ff450be Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 20 Jun 2011 03:01:09 +0200 Subject: [PATCH 114/439] Check for more missing tables in TrueType (sigh) --- fonts.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fonts.js b/fonts.js index 281eb94a8..72fabd2e3 100644 --- a/fonts.js +++ b/fonts.js @@ -694,7 +694,7 @@ var TrueType = function(aName, aFile, aProperties) { // If any tables are still in the array this means some required tables are // missing, which means that we need to rebuild the font in order to pass // the sanitizer. - if (requiredTables.length && requiredTables[0] == "OS/2") { + if (requiredTables.length == 1 && requiredTables[0] == "OS/2") { var OS2 = [ 0x00, 0x03, // version 0x02, 0x24, // xAvgCharWidth @@ -812,11 +812,10 @@ var TrueType = function(aName, aFile, aProperties) { this.data = fontData; return; - } else if (requiredTables.lenght) { - error("Table " + requiredTables[0] + " is missing from the TrueType font"); - } else { - this.data = aFile; + } else if (requiredTables.length) { + warn("Missing " + requiredTables + " in the TrueType font"); } + this.data = aFile; }; TrueType.prototype = { From a66e085734a2db8c4336cde9cb286cf663044791 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 19 Jun 2011 22:04:45 -0500 Subject: [PATCH 115/439] DCTDecode; text and images vertical inversion fix --- pdf.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/pdf.js b/pdf.js index f03615a64..ab9998264 100644 --- a/pdf.js +++ b/pdf.js @@ -509,9 +509,38 @@ var FlateStream = (function() { return constructor; })(); +var JpegStream = (function() { + function constructor(bytes, dict) { + // TODO per poppler, some images may have "junk" before that need to be removed + this.bytes = bytes; + this.dict = dict; + + // create DOM image + var buffer = "", i, n = bytes.length; + for (i = 0; i < n; ++i) { + buffer += String.fromCharCode(bytes[i]); + } + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(buffer); + this.domImage = img; + } + + constructor.prototype = { + getChar: function() { + TODO("read direct pixels data"); + }, + getImage: function() { + return this.domImage; + } + }; + + return constructor; +})(); + var PredictorStream = (function() { function constructor(stream, params) { this.stream = stream; + this.dict = stream.dict; this.predictor = params.get("Predictor") || 1; if (this.predictor <= 1) { return stream; // no prediction @@ -1177,15 +1206,15 @@ var Parser = (function() { this.encAlgorithm, this.keyLength); } - stream = this.filter(stream, dict); + stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; }, - filter: function(stream, dict) { + filter: function(stream, dict, length) { var filter = dict.get2("Filter", "F"); var params = dict.get2("DecodeParms", "DP"); if (IsName(filter)) - return this.makeFilter(stream, filter.name, params); + return this.makeFilter(stream, filter.name, length, params); if (IsArray(filter)) { var filterArray = filter; var paramsArray = params; @@ -1196,18 +1225,21 @@ var Parser = (function() { params = null; if (IsArray(paramsArray) && (i in paramsArray)) params = paramsArray[i]; - stream = this.makeFilter(stream, filter.name, params); + stream = this.makeFilter(stream, filter.name, length, params); } } } return stream; }, - makeFilter: function(stream, name, params) { + makeFilter: function(stream, name, length, params) { if (name == "FlateDecode" || name == "Fl") { if (params) { return new PredictorStream(new FlateStream(stream), params); } return new FlateStream(stream); + } else if (name == "DCTDecode") { + var bytes = stream.getBytes(length); + return new JpegStream(bytes, stream.dict); } else { error("filter '" + name + "' not supported yet"); } @@ -2398,11 +2430,17 @@ var CanvasGraphics = (function() { var fontName = ""; var fontDescriptor = font.get("FontDescriptor"); - if (fontDescriptor.num) { + if (fontDescriptor && fontDescriptor.num) { var fontDescriptor = this.xref.fetchIfRef(fontDescriptor); fontName = fontDescriptor.get("FontName").name.replace("+", "_"); Fonts.active = fontName; } + if (!fontName) { + // fontDescriptor is not available, fallback to default font (TODO ?) + this.current.fontSize = size; + this.ctx.font = this.current.fontSize + 'px sans-serif'; + return; + } this.current.fontSize = size; this.ctx.font = this.current.fontSize +'px "' + fontName + '"'; @@ -2431,9 +2469,9 @@ var CanvasGraphics = (function() { }, showText: function(text) { this.ctx.save(); - this.ctx.translate(0, 2 * this.current.y); - this.ctx.scale(1, -1); this.ctx.transform.apply(this.ctx, this.current.textMatrix); + this.ctx.scale(1, -1); + this.ctx.translate(0, -2 * this.current.y); this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; @@ -2679,8 +2717,17 @@ var CanvasGraphics = (function() { error("Invalid image width or height"); var ctx = this.ctx; + // scale the image to the unit square - ctx.scale(1/w, 1/h); + ctx.scale(1/w, -1/h); + + if (image instanceof JpegStream) { + var domImage = image.getImage(); + ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, + 0, -h, w, h); + this.restore(); + return; + } var interpolate = dict.get2("Interpolate", "I"); if (!IsBool(interpolate)) @@ -2786,7 +2833,7 @@ var CanvasGraphics = (function() { switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = imgArray[imageIdx++]; + var p = imgArray[imgIdx++]; pixels[i] = p; pixels[i+1] = p; pixels[i+2] = p; @@ -2813,7 +2860,7 @@ var CanvasGraphics = (function() { switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = imgArray[imageIdx++]; + var p = imgArray[imgIdx++]; pixels[i] = p; pixels[i+1] = p; pixels[i+2] = p; @@ -2833,7 +2880,7 @@ var CanvasGraphics = (function() { } } tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, 0); + ctx.drawImage(tmpCanvas, 0, -h); this.restore(); }, From 8d4d0a6752c2da67b3565ae8b750c22e4a61a7d1 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 19 Jun 2011 23:23:21 -0500 Subject: [PATCH 116/439] Multi-color predictor; row predictor for sub and average --- pdf.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index a051e57f3..f22d7c70d 100644 --- a/pdf.js +++ b/pdf.js @@ -522,13 +522,13 @@ var PredictorStream = (function() { this.colors = params.get("Colors") || 1; this.bitsPerComponent = params.get("BitsPerComponent") || 8; this.columns = params.get("Columns") || 1; - if (this.colors !== 1 || this.bitsPerComponent !== 8) { - error("Multi-color and multi-byte predictors are not supported"); + if (this.bitsPerComponent !== 8) { + error("Multi-byte predictors are not supported"); } if (this.predictor < 10 || this.predictor > 15) { error("Unsupported predictor"); } - this.currentRow = new Uint8Array(this.columns); + this.currentRow = new Uint8Array(this.columns * this.colors); this.pos = 0; this.bufferLength = 0; } @@ -536,19 +536,33 @@ var PredictorStream = (function() { constructor.prototype = { readRow : function() { var lastRow = this.currentRow; + var colors = this.colors; var predictor = this.stream.getByte(); - var currentRow = this.stream.getBytes(this.columns), i; + var currentRow = this.stream.getBytes(this.columns * colors), i; switch (predictor) { default: error("Unsupported predictor"); break; case 0: break; + case 1: + for (i = colors; i < currentRow.length; ++i) { + currentRow[i] = (currentRow[i - colors] + currentRow[i]) & 0xFF; + } + break; case 2: for (i = 0; i < currentRow.length; ++i) { currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF; } break; + case 3: + for (i = 0; i < color; ++i) { + currentRow[i] = ((lastRow[i] >> 1) + currentRow[i]) & 0xFF; + } + for (; i < currentRow.length; ++i) { + currentRow[i] = (((lastRow[i] + currentRow[i]) >> 1) + currentRow[i]) & 0xFF; + } + break; } this.pos = 0; this.bufferLength = currentRow.length; From fc4ca2a9dde75d7a536cf81debae674e106a4aaf Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 01:20:05 -0400 Subject: [PATCH 117/439] style fixes, we should post some sensible style guide --- pdf.js | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/pdf.js b/pdf.js index e507d406f..eb40df573 100644 --- a/pdf.js +++ b/pdf.js @@ -1385,31 +1385,25 @@ var XRef = (function() { var length = streamParameters.get("Length"); var byteWidths = streamParameters.get("W"); var range = streamParameters.get("Index"); - if (!range) { + if (!range) range = [0, streamParameters.get("Size")]; - } var i, j; while (range.length > 0) { var first = range[0], n = range[1]; - if (!IsInt(first) || !IsInt(n)) { + if (!IsInt(first) || !IsInt(n)) error("Invalid XRef range fields"); - } var typeFieldWidth = byteWidths[0], offsetFieldWidth = byteWidths[1], generationFieldWidth = byteWidths[2]; - if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) { + if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) error("Invalid XRef entry fields length"); - } for (i = 0; i < n; ++i) { var type = 0, offset = 0, generation = 0; - for (j = 0; j < typeFieldWidth; ++j) { + for (j = 0; j < typeFieldWidth; ++j) type = (type << 8) | stream.getByte(); - } - for (j = 0; j < offsetFieldWidth; ++j) { + for (j = 0; j < offsetFieldWidth; ++j) offset = (offset << 8) | stream.getByte(); - } - for (j = 0; j < generationFieldWidth; ++j) { + for (j = 0; j < generationFieldWidth; ++j) generation = (generation << 8) | stream.getByte(); - } - var entry = { offset: offset, gen: generation }; + var entry = new Ref(offset, generation); if (typeFieldWidth > 0) { switch (type) { case 0: @@ -1425,16 +1419,14 @@ var XRef = (function() { break; } } - if (!this.entries[first + i]) { + if (!this.entries[first + i]) this.entries[first + i] = entry; - } } range.splice(0, 2); } var prev = streamParameters.get("Prev"); - if (IsInt(prev)) { + if (IsInt(prev)) this.readXRef(prev); - } return streamParameters; }, readXRef: function(startXRef) { @@ -1505,7 +1497,7 @@ var XRef = (function() { return e; } // compressed entry - stream = this.fetch({num:e.offset, gen:0}); + stream = this.fetch(new Ref(e.offset, 0)); if (!IsStream(stream)) error("bad ObjStm stream"); var first = stream.parameters.get("First"); From c345a4c75e8383247c85bc5d75bba45a8c775a27 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 20 Jun 2011 08:20:31 +0200 Subject: [PATCH 118/439] Add more TrueType rewriting magic ('post' table) --- fonts.js | 38 +++++++++++++++++++++++++++++++++++--- pdf.js | 45 +++++++++++++++------------------------------ 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/fonts.js b/fonts.js index 72fabd2e3..172d6fa3c 100644 --- a/fonts.js +++ b/fonts.js @@ -23,6 +23,7 @@ var kMaxWaitForFontFace = 1000; * many fonts are loaded. */ var fontCount = 0; +var fontName = ""; /** * Hold a map of decoded fonts and of the standard fourteen Type1 fonts and @@ -38,6 +39,7 @@ var Fonts = { }, set active(aName) { + fontName = aName; this._active = this[aName]; }, @@ -694,7 +696,7 @@ var TrueType = function(aName, aFile, aProperties) { // If any tables are still in the array this means some required tables are // missing, which means that we need to rebuild the font in order to pass // the sanitizer. - if (requiredTables.length == 1 && requiredTables[0] == "OS/2") { + if (requiredTables.length && requiredTables[0] == "OS/2") { var OS2 = [ 0x00, 0x03, // version 0x02, 0x24, // xAvgCharWidth @@ -747,13 +749,43 @@ var TrueType = function(aName, aFile, aProperties) { // Replace the old CMAP table var rewrittedCMAP = this._createCMAPTable(glyphs); - var cmapDelta = rewrittedCMAP.length - originalCMAP.data.length; + var offsetDelta = rewrittedCMAP.length - originalCMAP.data.length; originalCMAP.data = rewrittedCMAP; + // Rewrite the 'post' table if needed + var postTable = null; + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + if (table.tag == "post") { + postTable = table; + break; + } + } + + if (!postTable) { + var post = [ + 0x00, 0x03, 0x00, 0x00, // Version number + 0x00, 0x00, 0x01, 0x00, // italicAngle + 0x00, 0x00, // underlinePosition + 0x00, 0x00, // underlineThickness + 0x00, 0x00, 0x00, 0x00, // isFixedPitch + 0x00, 0x00, 0x00, 0x00, // minMemType42 + 0x00, 0x00, 0x00, 0x00, // maxMemType42 + 0x00, 0x00, 0x00, 0x00, // minMemType1 + 0x00, 0x00, 0x00, 0x00 // maxMemType1 + ]; + + offsetDelta += post.length; + tables.unshift({ + tag: "post", + data: post + }); + } + // Create a new file to hold the new version of our truetype with a new // header and new offsets var stream = aFile.stream || aFile; - var ttf = new Uint8Array(stream.length + 16 + OS2.length + cmapDelta); + var ttf = new Uint8Array(stream.length + 1024); // The new numbers of tables will be the last one plus the num of missing // tables diff --git a/pdf.js b/pdf.js index 7414ac7ea..cc84115cf 100644 --- a/pdf.js +++ b/pdf.js @@ -1607,10 +1607,7 @@ var CanvasExtraState = (function() { const Encodings = { get ExpertEncoding() { - return shadow(this, "ExpertEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "ExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", "ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior", "twodotenleader","onedotenleader","comma","hyphen","period","fraction", @@ -1645,10 +1642,7 @@ const Encodings = { ]); }, get MacExpertEncoding() { - return shadow(this, "MacExpertEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "MacExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle", "dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior", "parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period", @@ -1682,10 +1676,7 @@ const Encodings = { ]); }, get MacRomanEncoding() { - return shadow(this, "MacRomanEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "MacRomanEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "period","slash","zero","one","two","three","four","five","six","seven","eight", @@ -1715,10 +1706,7 @@ const Encodings = { ]); }, get StandardEncoding() { - return shadow(this, "StandardEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "StandardEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "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", @@ -1738,10 +1726,7 @@ const Encodings = { ]); }, get WinAnsiEncoding() { - return shadow(this, "WinAnsiEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "WinAnsiEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "period","slash","zero","one","two","three","four","five","six","seven","eight", @@ -1772,10 +1757,7 @@ const Encodings = { ]); }, get zapfDingbatsEncoding() { - return shadow(this, "zapfDingbatsEncoding", [ - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, + return shadow(this, "zapfDingbatsEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13", "a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25", "a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34", @@ -1918,13 +1900,12 @@ var CanvasGraphics = (function() { error("FontFile not found for font: " + fontName); fontFile = xref.fetchIfRef(fontFile); - // Generate the custom cmap of the font if needed var encodingMap = {}; var charset = []; if (fontDict.has("Encoding")) { var encoding = xref.fetchIfRef(fontDict.get("Encoding")); if (IsDict(encoding)) { - // Build an map between codes and glyphs + // Build a map between codes and glyphs var differences = encoding.get("Differences"); var index = 0; for (var j = 0; j < differences.length; j++) { @@ -1960,9 +1941,13 @@ var CanvasGraphics = (function() { } else if (fontDict.has("ToUnicode")) { var cmapObj = xref.fetchIfRef(fontDict.get("ToUnicode")); if (IsName(cmapObj)) { - error("ToUnicode basic cmap translation not implemented"); - encodingMap = {}; + error("ToUnicode file cmap translation not implemented"); } else if (IsStream(cmapObj)) { + var encoding = Encodings["WinAnsiEncoding"]; + var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); + for (var i = firstChar; i < encoding.length; i++) + encodingMap[i] = new Name(encoding[i]); + var tokens = []; var token = ""; @@ -1992,8 +1977,8 @@ var CanvasGraphics = (function() { var code = parseInt("0x" + tokens[j+2]); for (var k = startRange; k <= endRange; k++) { - encodingMap[k] = code; - charset.push(code++); + encodingMap[k] = GlyphsUnicode[encoding[code]]; + charset.push(encoding[code++]); } } break; From 52e1631030ce6494fca5f3818bc4030172e4acdf Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 03:33:52 -0400 Subject: [PATCH 119/439] use Array.sort to calculate glyph ranges instead of large typed arrays --- fonts.js | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/fonts.js b/fonts.js index 2ee8a0d3c..49a78cb53 100644 --- a/fonts.js +++ b/fonts.js @@ -8,11 +8,6 @@ */ var kMaxFontFileSize = 40000; -/** - * Maximum number of glyphs per font. -*/ -var kMaxGlyphsCount = 65526; - /** * Maximum time to wait for a font to be loaded by @font-face */ @@ -310,24 +305,30 @@ var Font = (function () { aOffsets.currentOffset += tableEntry.length; aOffsets.virtualOffset += aData.length; } - - function createCMAPTable(aGlyphs) { - var characters = new Uint16Array(kMaxGlyphsCount); - for (var i = 0; i < aGlyphs.length; i++) - characters[aGlyphs[i].unicode] = i + 1; - // Separate the glyphs into continuous range of codes, aka segment. + function getRanges(glyphs) { + // Array.sort() sorts by characters, not numerically, so convert to an + // array of characters. + var codes = []; + var length = glyphs.length; + for (var n = 0; n < length; ++n) + codes.push(String.fromCharCode(glyphs[n].unicode)) + codes.sort(); + var ranges = []; - var range = []; - var count = characters.length; - for (var i = 0; i < count; i++) { - if (characters[i]) { - range.push(i); - } else if (range.length) { - ranges.push(range.slice()); - range = []; - } + for (var n = 0; n < length; ) { + var range = []; + do { + var current = codes[n++].charCodeAt(0); + range.push(current); + } while (n < length && current + 1 == codes[n].charCodeAt(0)); + ranges.push(range); } + return ranges; + } + + function createCMAPTable(aGlyphs) { + var ranges = getRanges(aGlyphs); // The size in bytes of the header is equal to the size of the // different fields * length of a short + (size of the 4 parallels arrays From 5f75130fbff18bc422112466cd5e9f7820ac94a1 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 03:49:40 -0400 Subject: [PATCH 120/439] store ranges as [start, end], instead of storing all codes --- fonts.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fonts.js b/fonts.js index 49a78cb53..73d42d8be 100644 --- a/fonts.js +++ b/fonts.js @@ -315,14 +315,16 @@ var Font = (function () { codes.push(String.fromCharCode(glyphs[n].unicode)) codes.sort(); + // Split the sorted codes into ranges. var ranges = []; for (var n = 0; n < length; ) { - var range = []; - do { - var current = codes[n++].charCodeAt(0); - range.push(current); - } while (n < length && current + 1 == codes[n].charCodeAt(0)); - ranges.push(range); + var start = codes[n++].charCodeAt(0); + var end = start; + while (n < length && end + 1 == codes[n].charCodeAt(0)) { + ++end; + ++n; + } + ranges.push([start, end]); } return ranges; } @@ -367,10 +369,10 @@ var Font = (function () { for (var i = 0; i < segCount - 1; i++) { var range = ranges[i]; var start = FontsUtils.integerToBytes(range[0], 2); - var end = FontsUtils.integerToBytes(range[range.length - 1], 2); + var end = FontsUtils.integerToBytes(range[1], 2); var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); - bias += range.length; + bias += (range[1] - range[0] + 1); // deltas are signed shorts delta[0] ^= 0xFF; @@ -382,8 +384,8 @@ var Font = (function () { idDeltas.push(delta[0], delta[1]); idRangeOffsets.push(0x00, 0x00); - for (var j = 0; j < range.length; j++) - glyphsIdsArray.push(range[j]); + for (var j = range[0]; j <= range[1]; j++) + glyphsIdsArray.push(j); } startCount.push(0xFF, 0xFF); endCount.push(0xFF, 0xFF); From e97f74f6e3a1462c2314b4442189d7feddbce66b Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 04:16:41 -0400 Subject: [PATCH 121/439] simplify glyph segment writing code --- fonts.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fonts.js b/fonts.js index 73d42d8be..abdd71db9 100644 --- a/fonts.js +++ b/fonts.js @@ -368,23 +368,21 @@ var Font = (function () { var bias = 0; for (var i = 0; i < segCount - 1; i++) { var range = ranges[i]; - var start = FontsUtils.integerToBytes(range[0], 2); - var end = FontsUtils.integerToBytes(range[1], 2); + var start = range[0]; + var end = range[1]; + var delta = (((start - 1) - bias) ^ 0xffff) + 1; + bias += (end - start + 1); - var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); - bias += (range[1] - range[0] + 1); - - // deltas are signed shorts - delta[0] ^= 0xFF; - delta[1] ^= 0xFF; - delta[1] += 1; + var start = FontsUtils.integerToBytes(start, 2); + var end = FontsUtils.integerToBytes(end, 2); + var delta = FontsUtils.integerToBytes(delta, 2); startCount.push(start[0], start[1]); endCount.push(end[0], end[1]); idDeltas.push(delta[0], delta[1]); idRangeOffsets.push(0x00, 0x00); - for (var j = range[0]; j <= range[1]; j++) + for (var j = start; j <= end; j++) glyphsIdsArray.push(j); } startCount.push(0xFF, 0xFF); From 32880025fc1ccdcc6e47a77fa4c2be4ceed29012 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 04:20:51 -0400 Subject: [PATCH 122/439] write font cmap using a string --- fonts.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/fonts.js b/fonts.js index abdd71db9..54aa46efb 100644 --- a/fonts.js +++ b/fonts.js @@ -342,22 +342,20 @@ var Font = (function () { var searchRange = FontsUtils.getMaxPower2(segCount) * 2; var searchEntry = Math.log(segCount) / Math.log(2); var rangeShift = 2 * segCount - searchRange; - var cmap = [].concat( - [ - 0x00, 0x00, // version - 0x00, 0x01, // numTables - 0x00, 0x03, // platformID - 0x00, 0x01, // encodingID - 0x00, 0x00, 0x00, 0x0C, // start of the table record - 0x00, 0x04 // format - ], - FontsUtils.integerToBytes(headerSize, 2), // length - [0x00, 0x00], // language - FontsUtils.integerToBytes(segCount2, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(searchEntry, 2), - FontsUtils.integerToBytes(rangeShift, 2) - ); + + var cmap = "\x00\x00" + // version + "\x00\x01" + // numTables + "\x00\x03" + // platformID + "\x00\x01" + // encodingID + "\x00\x00\x00\x0C" + // start of the table record + "\x00\x04" + // format + s16(headerSize) + // length + "\x00\x00" + // languages + s16(segCount2) + + s16(searchRange) + + s16(searchEntry) + + s16(rangeShift); + cmap = s2a(cmap); // Fill up the 4 parallel arrays describing the segments. var startCount = []; From 0c948d7b0631215385cd4ffaae1dea01c3650978 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 04:27:21 -0400 Subject: [PATCH 123/439] assemble cmap table from strings instead of arrays --- fonts.js | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/fonts.js b/fonts.js index 54aa46efb..6a8614022 100644 --- a/fonts.js +++ b/fonts.js @@ -332,11 +332,7 @@ var Font = (function () { function createCMAPTable(aGlyphs) { var ranges = getRanges(aGlyphs); - // The size in bytes of the header is equal to the size of the - // different fields * length of a short + (size of the 4 parallels arrays - // describing segments * length of a short). var headerSize = (12 * 2 + (ranges.length * 4 * 2)); - var segCount = ranges.length + 1; var segCount2 = segCount * 2; var searchRange = FontsUtils.getMaxPower2(segCount) * 2; @@ -355,14 +351,13 @@ var Font = (function () { s16(searchRange) + s16(searchEntry) + s16(rangeShift); - cmap = s2a(cmap); // Fill up the 4 parallel arrays describing the segments. - var startCount = []; - var endCount = []; - var idDeltas = []; - var idRangeOffsets = []; - var glyphsIdsArray = []; + var startCount = ""; + var endCount = ""; + var idDeltas = ""; + var idRangeOffsets = ""; + var glyphsIds = ""; var bias = 0; for (var i = 0; i < segCount - 1; i++) { var range = ranges[i]; @@ -371,25 +366,22 @@ var Font = (function () { var delta = (((start - 1) - bias) ^ 0xffff) + 1; bias += (end - start + 1); - var start = FontsUtils.integerToBytes(start, 2); - var end = FontsUtils.integerToBytes(end, 2); - var delta = FontsUtils.integerToBytes(delta, 2); - - startCount.push(start[0], start[1]); - endCount.push(end[0], end[1]); - idDeltas.push(delta[0], delta[1]); - idRangeOffsets.push(0x00, 0x00); + startCount += s16(start); + endCount += s16(end); + idDeltas += s16(delta); + idRangeOffsets += s16(0); for (var j = start; j <= end; j++) - glyphsIdsArray.push(j); + glyphsIds += String.fromCharCode(j); } - startCount.push(0xFF, 0xFF); - endCount.push(0xFF, 0xFF); - idDeltas.push(0x00, 0x01); - idRangeOffsets.push(0x00, 0x00); - return cmap.concat(endCount, [0x00, 0x00], startCount, - idDeltas, idRangeOffsets, glyphsIdsArray); + startCount += "\xFF\xFF"; + endCount += "\xFF\xFF"; + idDeltas += "\x00\x01"; + idRangeOffsets += "\x00\x00"; + + return s2a(cmap + endCount + "\x00\x00" + startCount + + idDeltas + idRangeOffsets + glyphsIds); } // Required Tables From f3fcbd0fbc233abf238e39a53bc2f13a905e91b3 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 14:42:39 -0400 Subject: [PATCH 124/439] remove remaining uses of integerToBytes in type1 font code --- fonts.js | 82 +++++++++++++++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/fonts.js b/fonts.js index 6a8614022..b8a490369 100644 --- a/fonts.js +++ b/fonts.js @@ -247,7 +247,12 @@ var Font = (function () { } function s16(value) { - return String.fromCharCode(value >> 8) + String.fromCharCode(value & 0xff); + return String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); + } + + function s32(value) { + return String.fromCharCode((value >> 24) & 0xff) + String.fromCharCode((value >> 16) & 0xff) + + String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); } function createOpenTypeHeader(aFile, aOffsets, numTables) { @@ -276,18 +281,10 @@ var Font = (function () { } function createTableEntry(aFile, aOffsets, aTag, aData) { - // tag - var tag = [ - aTag.charCodeAt(0), - aTag.charCodeAt(1), - aTag.charCodeAt(2), - aTag.charCodeAt(3) - ]; - // offset var offset = aOffsets.virtualOffset; - // Per spec tables must be 4-bytes align so add some 0x00 if needed + // Per spec tables must be 4-bytes align so add padding as needed while (aData.length & 3) aData.push(0x00); @@ -295,12 +292,15 @@ var Font = (function () { var length = aData.length; // checksum - var checksum = FontsUtils.bytesToInteger(tag) + offset + length; + var checksum = aTag.charCodeAt(0) + + aTag.charCodeAt(1) + + aTag.charCodeAt(2) + + aTag.charCodeAt(3) + + offset + + length; - var tableEntry = [].concat(tag, - FontsUtils.integerToBytes(checksum, 4), - FontsUtils.integerToBytes(offset, 4), - FontsUtils.integerToBytes(length, 4)); + var tableEntry = aTag + s32(checksum) + s32(offset) + s32(length); + tableEntry = s2a(tableEntry); aFile.set(tableEntry, aOffsets.currentOffset); aOffsets.currentOffset += tableEntry.length; aOffsets.virtualOffset += aData.length; @@ -409,7 +409,7 @@ var Font = (function () { // file createOpenTypeHeader(otf, offsets, tables.length); - // XXX It is probable that in a future we want to get rid of this glue + // TODO: It is probable that in a future we want to get rid of this glue // between the CFF and the OTF format in order to be able to embed TrueType // data. createTableEntry(otf, offsets, "CFF ", CFF); @@ -508,45 +508,41 @@ var Font = (function () { createTableEntry(otf, offsets, "hhea", hhea); /** HMTX */ - hmtx = [0x01, 0xF4, 0x00, 0x00]; + hmtx = "\x01\xF4\x00\x00"; for (var i = 0; i < charstrings.length; i++) { var charstring = charstrings[i].charstring; - var width = FontsUtils.integerToBytes(charstring[1], 2); - var lsb = FontsUtils.integerToBytes(charstring[0], 2); - hmtx = hmtx.concat(width, lsb); + var width = charstring[1]; + var lsb = charstring[0]; + hmtx += s16(width) + s16(lsb); } + hmtx = s2a(hmtx); createTableEntry(otf, offsets, "hmtx", hmtx); /** MAXP */ - maxp = [].concat( - [ - 0x00, 0x00, 0x50, 0x00, // Version number - ], - FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...) - ); + maxp = "\x00\x00\x50\x00" + // Version number + s16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) + maxp = s2a(maxp); createTableEntry(otf, offsets, "maxp", maxp); /** NAME */ - name = [ - 0x00, 0x00, // format - 0x00, 0x00, // Number of names Record - 0x00, 0x00 // Storage - ]; + name = "\x00\x00" + // Format + "\x00\x00" + // Number of name records + "\x00\x00"; // Storage + name = s2a(name); createTableEntry(otf, offsets, "name", name); /** POST */ - // FIXME Get those informations from the FontInfo structure - post = s2a( - "\x00\x03\x00\x00" + // Version number - "\x00\x00\x01\x00" + // 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 - ); + // TODO: get those informations from the FontInfo structure + post = "\x00\x03\x00\x00" + // Version number + "\x00\x00\x01\x00" + // 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 + post = s2a(post); createTableEntry(otf, offsets, "post", post); // Once all the table entries header are written, dump the data! From 2feec66b746513f004f8e6707974e7bf3a3050e0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 20 Jun 2011 21:14:33 +0200 Subject: [PATCH 125/439] Add a way to disable fonts that won't load --- fonts.js | 27 ++++++++++++++++++++++++--- pdf.js | 17 +++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index 172d6fa3c..273ef5ea6 100644 --- a/fonts.js +++ b/fonts.js @@ -25,6 +25,12 @@ var kMaxWaitForFontFace = 1000; var fontCount = 0; var fontName = ""; +/** + * If for some reason one want to debug without fonts activated, it just need + * to turn this pref to true/false. + */ +var kDisableFonts = false; + /** * Hold a map of decoded fonts and of the standard fourteen Type1 fonts and * their acronyms. @@ -93,6 +99,16 @@ var Font = function(aName, aFile, aProperties) { } fontCount++; + if (aProperties.ignore || kDisableFonts) { + Fonts[aName] = { + data: aFile, + loading: false, + properties: {}, + cache: Object.create(null) + } + return; + } + switch (aProperties.type) { case "Type1": var cff = new CFF(aName, aFile, aProperties); @@ -203,19 +219,21 @@ Font.prototype = { if (debug) ctx.fillText(testString, 20, 20); - var start = Date.now(); var interval = window.setInterval(function canvasInterval(self) { + this.start = this.start || Date.now(); ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; // For some reasons the font has not loaded, so mark it loaded for the // page to proceed but cry - if ((Date.now() - start) >= kMaxWaitForFontFace) { + if ((Date.now() - this.start) >= kMaxWaitForFontFace) { window.clearInterval(interval); Fonts[fontName].loading = false; warn("Is " + fontName + " for charset: " + charset + " loaded?"); + this.start = 0; } else if (textWidth != ctx.measureText(testString).width) { window.clearInterval(interval); Fonts[fontName].loading = false; + this.start = 0; } if (debug) @@ -747,9 +765,12 @@ var TrueType = function(aName, aFile, aProperties) { }); } + + var offsetDelta = 0; + // Replace the old CMAP table var rewrittedCMAP = this._createCMAPTable(glyphs); - var offsetDelta = rewrittedCMAP.length - originalCMAP.data.length; + offsetDelta = rewrittedCMAP.length - originalCMAP.data.length; originalCMAP.data = rewrittedCMAP; // Rewrite the 'post' table if needed diff --git a/pdf.js b/pdf.js index cc84115cf..d39579f74 100644 --- a/pdf.js +++ b/pdf.js @@ -1900,9 +1900,16 @@ var CanvasGraphics = (function() { error("FontFile not found for font: " + fontName); fontFile = xref.fetchIfRef(fontFile); + // Fonts with an embedded cmap but without any assignment in + // it are not yet supported, so ask the fonts loader to ignore + // them to not pay a stupid one sec latence. + var ignoreFont = true; + var encodingMap = {}; var charset = []; if (fontDict.has("Encoding")) { + ignoreFont = false; + var encoding = xref.fetchIfRef(fontDict.get("Encoding")); if (IsDict(encoding)) { // Build a map between codes and glyphs @@ -1960,8 +1967,9 @@ var CanvasGraphics = (function() { error("useCMap is not implemented"); break; - case "begincodespacerange": case "beginbfrange": + ignoreFont = false; + case "begincodespacerange": token = ""; tokens = []; break; @@ -2002,7 +2010,7 @@ var CanvasGraphics = (function() { } } } - } + } var subType = fontDict.get("Subtype"); var bbox = descriptor.get("FontBBox"); @@ -2013,7 +2021,8 @@ var CanvasGraphics = (function() { type: subType.name, encoding: encodingMap, charset: charset, - bbox: bbox + bbox: bbox, + ignore: ignoreFont }; return { @@ -2275,7 +2284,7 @@ var CanvasGraphics = (function() { } this.current.fontSize = size; - this.ctx.font = this.current.fontSize +'px "' + fontName + '"'; + this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol'; }, setTextRenderingMode: function(mode) { TODO("text rendering mode"); From 0b2d842f830a4b2fb364590aae4c618d86defc47 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 13:38:27 -0700 Subject: [PATCH 126/439] Used symbolic constants --- pdf.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pdf.js b/pdf.js index bf8ff1d97..15b63c1ba 100644 --- a/pdf.js +++ b/pdf.js @@ -2033,6 +2033,9 @@ var CanvasGraphics = (function() { const NORMAL_CLIP = {}; const EO_CLIP = {}; + // Used for tiling patterns + const PAINT_TYPE = [null, "colored", "uncolored"]; + constructor.prototype = { translateFont: function(fontDict, xref, resources) { var descriptor = xref.fetch(fontDict.get("FontDescriptor")); @@ -2461,12 +2464,13 @@ var CanvasGraphics = (function() { error("Unable to find pattern resource"); var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); - - var type = pattern.dict.get("PatternType"); - if (type === 1) - this.tilingFill(pattern); - else + + const types = [null, this.tilingFill]; + var typeNum = pattern.dict.get("PatternType"); + var patternFn = types[typeNum]; + if (!patternFn) error("Unhandled pattern type"); + patternFn.call(this, pattern); } } else { // TODO real impl @@ -2492,15 +2496,15 @@ var CanvasGraphics = (function() { this.save(); var dict = pattern.dict; + var ctx = this.ctx; - var paintType = dict.get("PaintType"); - if (paintType == 2) { - error("Unsupported paint type"); - } else { + var paintType = PAINT_TYPE[dict.get("PaintType")]; + if (paintType == "colored") { // should go to default for color space - var ctx = this.ctx; ctx.fillStyle = this.makeCssRgb(1, 1, 1); ctx.strokeStyle = this.makeCssRgb(0, 0, 0); + } else { + error("Unsupported paint type"); } TODO("TilingType"); @@ -2524,7 +2528,7 @@ var CanvasGraphics = (function() { // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext("2d"); - var savedCtx = this.ctx; + var savedCtx = ctx; this.ctx = tmpCtx; // normalize transform matrix so each step @@ -2663,9 +2667,6 @@ var CanvasGraphics = (function() { // Canvas only allows gradients to be drawn in a rectangle // The following bug should allow us to remove this. // https://bugzilla.mozilla.org/show_bug.cgi?id=664884 - // - // Also, larg numbers seem to cause overflow which causes - // nothing to be drawn. this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); }, From 8ae9b1f3d4f9a2a9bd677e8665ba0122a8888fb4 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 13:47:42 -0700 Subject: [PATCH 127/439] fixed ExtraStateContext.colorSpace impl --- pdf.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 15b63c1ba..001784eea 100644 --- a/pdf.js +++ b/pdf.js @@ -1738,7 +1738,7 @@ var CanvasExtraState = (function() { this.fontSize = 0.0; this.textMatrix = IDENTITY_MATRIX; this.leading = 0.0; - this.colorSpace = "DeviceRGB"; + this.colorSpace = null; // Current point (in user coordinates) this.x = 0.0; this.y = 0.0; @@ -2454,9 +2454,17 @@ var CanvasGraphics = (function() { }, setFillColorN: function(/*...*/) { // TODO real impl - var args = arguments; + var colorSpace = this.current.colorSpace; + if (!colorSpace) { + var stateStack = this.stateStack; + var i = stateStack.length - 1; + while (!colorSpace && i >= 0) { + colorSpace = stateStack[i--].colorSpace; + } + } + if (this.current.colorSpace == "Pattern") { - var patternName = args[0]; + var patternName = arguments[0]; if (IsName(patternName)) { var xref = this.xref; var patternRes = xref.fetchIfRef(this.res.get("Pattern")); From 9c01d8536a859a8392b4a22131deacc54df83665 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 14:10:10 -0700 Subject: [PATCH 128/439] used typeof b == undefined --- pdf.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pdf.js b/pdf.js index 4fd3fedce..5b57d0db6 100644 --- a/pdf.js +++ b/pdf.js @@ -288,7 +288,7 @@ var FlateStream = (function() { while (codeSize < maxLen) { var b; - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad encoding in flate stream"); codeBuf |= (b << codeSize); codeSize += 8; @@ -416,16 +416,16 @@ var FlateStream = (function() { var b; if (hdr == 0) { // uncompressed block - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var blockLen = b; - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); blockLen |= (b << 8); - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var check = b; - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); check |= (b << 8); if (check != (~this.blockLen & 0xffff)) @@ -434,7 +434,7 @@ var FlateStream = (function() { var buffer = this.ensureBuffer(bufferLength + blockLen); this.bufferLength = bufferLength + blockLen; for (var n = bufferLength; n < blockLen; ++n) { - if ((b = bytes[bytesPos++]) == undefined) { + if (typeof (b = bytes[bytesPos++]) == "undefined") { this.eof = true; break; } From efe148e715f9f5d09ae6d04380ce5cc6f505b93e Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 14:14:28 -0700 Subject: [PATCH 129/439] forgot to changed to typeof b == undefined at one location --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 5b57d0db6..8a844be6c 100644 --- a/pdf.js +++ b/pdf.js @@ -267,7 +267,7 @@ var FlateStream = (function() { var b; while (codeSize < bits) { - if ((b = bytes[bytesPos++]) == undefined) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad encoding in flate stream"); codeBuf |= b << codeSize; codeSize += 8; From 8911f7c6c5241c152debceabd3e47d1ac43fdaf0 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 14:22:11 -0700 Subject: [PATCH 130/439] switched to using const enums --- pdf.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index 001784eea..aca7e0b5a 100644 --- a/pdf.js +++ b/pdf.js @@ -2034,7 +2034,7 @@ var CanvasGraphics = (function() { const EO_CLIP = {}; // Used for tiling patterns - const PAINT_TYPE = [null, "colored", "uncolored"]; + const PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; constructor.prototype = { translateFont: function(fontDict, xref, resources) { @@ -2506,12 +2506,15 @@ var CanvasGraphics = (function() { var dict = pattern.dict; var ctx = this.ctx; - var paintType = PAINT_TYPE[dict.get("PaintType")]; - if (paintType == "colored") { + var paintType = dict.get("PaintType"); + switch (paintType) { + case PAINT_TYPE_COLORED: // should go to default for color space ctx.fillStyle = this.makeCssRgb(1, 1, 1); ctx.strokeStyle = this.makeCssRgb(0, 0, 0); - } else { + break; + case PAINT_TYPE_UNCOLORED: + default: error("Unsupported paint type"); } From 28eba6d10e6fd8002ecce72be9c5efb969da47e6 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 19:36:40 -0400 Subject: [PATCH 131/439] cleanup DCTStream rendering code a tad --- pdf.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pdf.js b/pdf.js index 758ea8297..40044300c 100644 --- a/pdf.js +++ b/pdf.js @@ -48,6 +48,14 @@ function shadow(obj, prop, value) { return value; } +function bytesToString(bytes) { + var str = ""; + var length = bytes.length; + for (var n = 0; n < length; ++n) + str += String.fromCharCode(bytes[n]); + return str; +} + var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { this.bytes = Uint8Array(arrayBuffer); @@ -518,26 +526,20 @@ var FlateStream = (function() { return constructor; })(); +// A JpegStream can't be read directly. We use the platform to render the underlying +// JPEG data for us. var JpegStream = (function() { function constructor(bytes, dict) { - // TODO per poppler, some images may have "junk" before that need to be removed - this.bytes = bytes; + // TODO: per poppler, some images may have "junk" before that need to be removed this.dict = dict; // create DOM image - var buffer = "", i, n = bytes.length; - for (i = 0; i < n; ++i) { - buffer += String.fromCharCode(bytes[i]); - } var img = new Image(); - img.src = "data:image/jpeg;base64," + window.btoa(buffer); + img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); this.domImage = img; } constructor.prototype = { - getChar: function() { - TODO("read direct pixels data"); - }, getImage: function() { return this.domImage; } @@ -2441,7 +2443,7 @@ var CanvasGraphics = (function() { Fonts.active = fontName; } if (!fontName) { - // fontDescriptor is not available, fallback to default font (TODO ?) + // TODO: fontDescriptor is not available, fallback to default font this.current.fontSize = size; this.ctx.font = this.current.fontSize + 'px sans-serif'; return; @@ -2854,10 +2856,13 @@ var CanvasGraphics = (function() { // scale the image to the unit square ctx.scale(1/w, -1/h); - if (image instanceof JpegStream) { + // If the platform can render the image format directly, the + // stream has a getImage property which directly returns a + // suitable DOM Image object. + if (image.getImage) { var domImage = image.getImage(); ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, - 0, -h, w, h); + 0, -h, w, h); this.restore(); return; } From 10944be385faf171ef313664bee0758935b5143b Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 03:01:59 +0200 Subject: [PATCH 132/439] Merge with master --- pdf.js | 133 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 36 deletions(-) diff --git a/pdf.js b/pdf.js index 2ce6b48a8..d6c478199 100644 --- a/pdf.js +++ b/pdf.js @@ -48,6 +48,14 @@ function shadow(obj, prop, value) { return value; } +function bytesToString(bytes) { + var str = ""; + var length = bytes.length; + for (var n = 0; n < length; ++n) + str += String.fromCharCode(bytes[n]); + return str; +} + var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { this.bytes = Uint8Array(arrayBuffer); @@ -74,9 +82,9 @@ var Stream = (function() { var pos = this.pos; var end = pos + length; var strEnd = this.end; - if (end > strEnd) + if (!end || end > strEnd) end = strEnd; - + this.pos = end; return bytes.subarray(pos, end); }, @@ -233,10 +241,12 @@ var FlateStream = (function() { ]), 5]; function constructor(stream) { - this.stream = stream; + var bytes = stream.getBytes(); + var bytesPos = 0; + this.dict = stream.dict; - var cmf = stream.getByte(); - var flg = stream.getByte(); + var cmf = bytes[bytesPos++]; + var flg = bytes[bytesPos++]; if (cmf == -1 || flg == -1) error("Invalid header in flate stream"); if ((cmf & 0x0f) != 0x08) @@ -245,6 +255,9 @@ var FlateStream = (function() { error("Bad FCHECK in flate stream"); if (flg & 0x20) error("FDICT bit set in flate stream"); + + this.bytes = bytes; + this.bytesPos = bytesPos; this.eof = false; this.codeSize = 0; this.codeBuf = 0; @@ -255,12 +268,14 @@ var FlateStream = (function() { constructor.prototype = { getBits: function(bits) { - var stream = this.stream; var codeSize = this.codeSize; var codeBuf = this.codeBuf; + var bytes = this.bytes; + var bytesPos = this.bytesPos; + var b; while (codeSize < bits) { - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad encoding in flate stream"); codeBuf |= b << codeSize; codeSize += 8; @@ -268,6 +283,7 @@ var FlateStream = (function() { b = codeBuf & ((1 << bits) - 1); this.codeBuf = codeBuf >> bits; this.codeSize = codeSize -= bits; + this.bytesPos = bytesPos; return b; }, getCode: function(table) { @@ -275,10 +291,12 @@ var FlateStream = (function() { var maxLen = table[1]; var codeSize = this.codeSize; var codeBuf = this.codeBuf; - var stream = this.stream; + var bytes = this.bytes; + var bytesPos = this.bytesPos; + while (codeSize < maxLen) { var b; - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad encoding in flate stream"); codeBuf |= (b << codeSize); codeSize += 8; @@ -290,6 +308,7 @@ var FlateStream = (function() { error("Bad encoding in flate stream"); this.codeBuf = (codeBuf >> codeLen); this.codeSize = (codeSize - codeLen); + this.bytesPos = bytesPos; return codeVal; }, ensureBuffer: function(requested) { @@ -306,9 +325,8 @@ var FlateStream = (function() { return this.buffer = buffer2; }, getByte: function() { - var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength <= pos) { + while (this.bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -331,9 +349,8 @@ var FlateStream = (function() { return this.buffer.subarray(pos, end) }, lookChar: function() { - var bufferLength = this.bufferLength; var pos = this.pos; - if (bufferLength <= pos) { + while (this.bufferLength <= pos) { if (this.eof) return; this.readBlock(); @@ -342,16 +359,15 @@ var FlateStream = (function() { }, getChar: function() { var ch = this.lookChar(); - if (!ch) - return; + // shouldnt matter what the position is if we get past the eof + // so no need to check if ch is undefined this.pos++; return ch; }, skip: function(n) { if (!n) n = 1; - while (n-- > 0) - this.getChar(); + this.pos += n; }, generateHuffmanTable: function(lengths) { var n = lengths.length; @@ -397,7 +413,8 @@ var FlateStream = (function() { array[i++] = what; } - var stream = this.stream; + var bytes = this.bytes; + var bytesPos = this.bytesPos; // read block header var hdr = this.getBits(3); @@ -407,16 +424,16 @@ var FlateStream = (function() { var b; if (hdr == 0) { // uncompressed block - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var blockLen = b; - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); blockLen |= (b << 8); - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var check = b; - if ((b = stream.getByte()) == -1) + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); check |= (b << 8); if (check != (~this.blockLen & 0xffff)) @@ -425,7 +442,7 @@ var FlateStream = (function() { var buffer = this.ensureBuffer(bufferLength + blockLen); this.bufferLength = bufferLength + blockLen; for (var n = bufferLength; n < blockLen; ++n) { - if ((b = stream.getByte()) == -1) { + if (typeof (b = bytes[bytesPos++]) == "undefined") { this.eof = true; break; } @@ -509,9 +526,32 @@ var FlateStream = (function() { return constructor; })(); +// A JpegStream can't be read directly. We use the platform to render the underlying +// JPEG data for us. +var JpegStream = (function() { + function constructor(bytes, dict) { + // TODO: per poppler, some images may have "junk" before that need to be removed + this.dict = dict; + + // create DOM image + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); + this.domImage = img; + } + + constructor.prototype = { + getImage: function() { + return this.domImage; + } + }; + + return constructor; +})(); + var PredictorStream = (function() { function constructor(stream, params) { this.stream = stream; + this.dict = stream.dict; this.predictor = params.get("Predictor") || 1; if (this.predictor <= 1) { return stream; // no prediction @@ -1177,15 +1217,15 @@ var Parser = (function() { this.encAlgorithm, this.keyLength); } - stream = this.filter(stream, dict); + stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; }, - filter: function(stream, dict) { + filter: function(stream, dict, length) { var filter = dict.get2("Filter", "F"); var params = dict.get2("DecodeParms", "DP"); if (IsName(filter)) - return this.makeFilter(stream, filter.name, params); + return this.makeFilter(stream, filter.name, length, params); if (IsArray(filter)) { var filterArray = filter; var paramsArray = params; @@ -1196,18 +1236,21 @@ var Parser = (function() { params = null; if (IsArray(paramsArray) && (i in paramsArray)) params = paramsArray[i]; - stream = this.makeFilter(stream, filter.name, params); + stream = this.makeFilter(stream, filter.name, length, params); } } } return stream; }, - makeFilter: function(stream, name, params) { + makeFilter: function(stream, name, length, params) { if (name == "FlateDecode" || name == "Fl") { if (params) { return new PredictorStream(new FlateStream(stream), params); } return new FlateStream(stream); + } else if (name == "DCTDecode") { + var bytes = stream.getBytes(length); + return new JpegStream(bytes, stream.dict); } else { error("filter '" + name + "' not supported yet"); } @@ -2475,12 +2518,19 @@ var CanvasGraphics = (function() { var fontName = ""; var fontDescriptor = font.get("FontDescriptor"); - if (fontDescriptor.num) { + if (fontDescriptor && fontDescriptor.num) { var fontDescriptor = this.xref.fetchIfRef(fontDescriptor); fontName = fontDescriptor.get("FontName").name.replace("+", "_"); Fonts.active = fontName; } + if (!fontName) { + // TODO: fontDescriptor is not available, fallback to default font + this.current.fontSize = size; + this.ctx.font = this.current.fontSize + 'px sans-serif'; + return; + } + this.current.fontSize = size; this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol'; }, @@ -2508,9 +2558,9 @@ var CanvasGraphics = (function() { }, showText: function(text) { this.ctx.save(); - this.ctx.translate(0, 2 * this.current.y); - this.ctx.scale(1, -1); this.ctx.transform.apply(this.ctx, this.current.textMatrix); + this.ctx.scale(1, -1); + this.ctx.translate(0, -2 * this.current.y); this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; @@ -2882,10 +2932,21 @@ var CanvasGraphics = (function() { if (w < 1 || h < 1) error("Invalid image width or height"); - + var ctx = this.ctx; // scale the image to the unit square - ctx.scale(1/w, 1/h); + ctx.scale(1/w, -1/h); + + // If the platform can render the image format directly, the + // stream has a getImage property which directly returns a + // suitable DOM Image object. + if (image.getImage) { + var domImage = image.getImage(); + ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, + 0, -h, w, h); + this.restore(); + return; + } var interpolate = dict.get2("Interpolate", "I"); if (!IsBool(interpolate)) @@ -2991,7 +3052,7 @@ var CanvasGraphics = (function() { switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = imgArray[imageIdx++]; + var p = imgArray[imgIdx++]; pixels[i] = p; pixels[i+1] = p; pixels[i+2] = p; @@ -3018,7 +3079,7 @@ var CanvasGraphics = (function() { switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = imgArray[imageIdx++]; + var p = imgArray[imgIdx++]; pixels[i] = p; pixels[i+1] = p; pixels[i+2] = p; @@ -3038,7 +3099,7 @@ var CanvasGraphics = (function() { } } tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, 0); + ctx.drawImage(tmpCanvas, 0, -h); this.restore(); }, From 8787e7cbe9af9056767669e1a35dfb6082f2aaba Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 03:05:28 +0200 Subject: [PATCH 133/439] Fix some leftovers --- pdf.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index d6c478199..b140ef6c1 100644 --- a/pdf.js +++ b/pdf.js @@ -2532,7 +2532,7 @@ var CanvasGraphics = (function() { } this.current.fontSize = size; - this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol'; + this.ctx.font = this.current.fontSize +'px "' + fontName + '"'; }, setTextRenderingMode: function(mode) { TODO("text rendering mode"); @@ -2720,7 +2720,7 @@ var CanvasGraphics = (function() { // normalize transform matrix so each step // takes up the entire tmpCanvas (need to remove white borders) if (matrix[1] === 0 && matrix[2] === 0) { - matrix[0] = tmpCanvas.width / xstep; + matrix[0] = tmpCanvas.width / xstep; matrix[3] = tmpCanvas.height / ystep; topLeft = applyMatrix([x0,y0], matrix); } From 3fa6230b37d46a6119965ba3d85bfb790bedca9a Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Mon, 20 Jun 2011 21:08:50 -0400 Subject: [PATCH 134/439] Replaced zoom control with standard HTML + Zoom -
-
    -
  • 50%
  • -
  • 75%
  • -
  • 100%
  • -
  • 125%
  • -
  • 150%
  • -
  • 200%
  • -
-
diff --git a/multi-page-viewer.js b/multi-page-viewer.js index 6cb46a08a..9d9cec702 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -11,7 +11,7 @@ var PDFViewer = { previousPageButton: null, nextPageButton: null, pageNumberInput: null, - scaleInput: null, + scaleSelect: null, willJumpToPage: false, @@ -66,92 +66,103 @@ var PDFViewer = { removePage: function(num) { var div = document.getElementById('pageContainer' + num); - if (div && div.hasChildNodes()) { - while (div.childNodes.length > 0) { + if (div) { + while (div.hasChildNodes()) { div.removeChild(div.firstChild); } } }, drawPage: function(num) { - if (PDFViewer.pdf) { - var page = PDFViewer.pdf.getPage(num); - var div = document.getElementById('pageContainer' + num); - - if (div && !div.hasChildNodes()) { - var canvas = document.createElement('canvas'); - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; + if (!PDFViewer.pdf) { + return; + } - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var fontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); - new Font(font.name, font.file, font.properties); - - fontsReady = false; + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; } - var pageInterval; - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - PDFViewer.drawPage(num); - } - - if (!fontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - div.appendChild(canvas); + new Font(font.name, font.file, font.properties); + + areFontsReady = false; } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); } }, changeScale: function(num) { - while (PDFViewer.element.childNodes.length > 0) { + while (PDFViewer.element.hasChildNodes()) { PDFViewer.element.removeChild(PDFViewer.element.firstChild); } PDFViewer.scale = num / 100; + var i; + if (PDFViewer.pdf) { - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { PDFViewer.createPage(i); } @@ -160,7 +171,21 @@ var PDFViewer = { } } - PDFViewer.scaleInput.value = Math.floor(PDFViewer.scale * 100) + '%'; + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; }, goToPage: function(num) { @@ -217,6 +242,11 @@ var PDFViewer = { if (PDFViewer.numberOfPages > 0) { PDFViewer.drawPage(1); } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } }; @@ -320,40 +350,14 @@ window.onload = function() { this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; - PDFViewer.scaleInput = document.getElementById('scale'); - PDFViewer.scaleInput.buttonElement = document.getElementById('scaleComboBoxButton'); - PDFViewer.scaleInput.buttonElement.listElement = document.getElementById('scaleComboBoxList'); - PDFViewer.scaleInput.onchange = function(evt) { + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { PDFViewer.changeScale(parseInt(this.value)); }; - PDFViewer.scaleInput.buttonElement.onclick = function(evt) { - this.listElement.style.display = (this.listElement.style.display === 'block') ? 'none' : 'block'; - }; - PDFViewer.scaleInput.buttonElement.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.scaleInput.buttonElement.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.scaleInput.buttonElement.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - var listItems = PDFViewer.scaleInput.buttonElement.listElement.getElementsByTagName('LI'); - - for (var i = 0; i < listItems.length; i++) { - var listItem = listItems[i]; - listItem.onclick = function(evt) { - PDFViewer.changeScale(parseInt(this.innerHTML)); - PDFViewer.scaleInput.buttonElement.listElement.style.display = 'none'; - }; - } - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleInput.value) / 100 || 1.0; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); window.onscroll = function(evt) { From 8523896023a9867cf20f5766b6452478cf1efa71 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 04:30:28 +0200 Subject: [PATCH 135/439] Rename s2a, s16, s32 and do some dance inside the bind() code --- fonts.js | 223 ++++++++++++++++++++++++++++--------------------------- pdf.js | 2 +- 2 files changed, 116 insertions(+), 109 deletions(-) diff --git a/fonts.js b/fonts.js index 53db045f0..2f8a6c3df 100644 --- a/fonts.js +++ b/fonts.js @@ -43,38 +43,39 @@ var Fonts = { this._active = this[aName]; }, - chars2Unicode: function(chars) { + charsToUnicode: function fonts_chars2Unicode(chars) { var active = this._active; if (!active) return chars; // if we translated this string before, just grab it from the cache - var ret = active.cache[chars]; - if (ret) - return ret; + var str = active.cache[chars] || ""; + if (str) + return str; // translate the string using the font's encoding var encoding = active.properties.encoding; if (!encoding) return chars; - var ret = ""; for (var i = 0; i < chars.length; ++i) { - var ch = chars.charCodeAt(i); - var uc = encoding[ch]; - if (uc instanceof Name) // we didn't convert the glyph yet - uc = encoding[ch] = GlyphsUnicode[uc.name]; - if (uc > 0xffff) { // handle surrogate pairs - ret += String.fromCharCode(uc & 0xffff); - uc >>= 16; + var charcode = chars.charCodeAt(i); + var unicode = encoding[charcode]; + + // Check if the glyph has already been converted + if (unicode instanceof Name) + unicode = encoding[unicode] = GlyphsUnicode[unicode.name]; + + // Handle surrogate pairs + if (unicode > 0xFFFF) { + str += String.fromCharCode(unicode & 0xFFFF); + unicode >>= 16; } - ret += String.fromCharCode(uc); + str += String.fromCharCode(unicode); } - // enter the translated string into the cache - active.cache[chars] = ret; - - return ret; + // Enter the translated string into the cache + return active.cache[chars] = str; } }; @@ -99,6 +100,8 @@ var Font = (function () { fontCount++; fontName = aName; + // If the font is to be ignored, register it like an already loaded font + // to avoid the cost of waiting for it be be loaded by the platform. if (aProperties.ignore || kDisableFonts) { Fonts[aName] = { data: aFile, @@ -168,31 +171,12 @@ var Font = (function () { bind: function font_bind() { var data = this.font; - - // Get the base64 encoding of the binary font data - var str = ""; - var length = data.length; - for (var i = 0; i < length; ++i) - str += String.fromCharCode(data[i]); - - var dataBase64 = window.btoa(str); var fontName = this.name; /** Hack begin */ // Actually there is not event when a font has finished downloading so - // the following tons of code are a dirty hack to 'guess' when a font is - // ready - var debug = false; - - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); - } - + // the following code are a dirty hack to 'guess' when a font is ready var canvas = document.createElement("canvas"); var style = "border: 1px solid black; position:absolute; top: " + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; @@ -201,33 +185,42 @@ var Font = (function () { canvas.setAttribute("heigth", 100); document.body.appendChild(canvas); - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; - - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); - // Get the font size canvas think it will be for 'spaces' var ctx = canvas.getContext("2d"); - var testString = " "; + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var testString = " "; // When debugging use the characters provided by the charsets to visually - // see what's happening + // see what's happening instead of 'spaces' + var debug = false; if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); + + // Retrieve font charset + var charset = Fonts[fontName].properties.charset || []; + + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); + for (var i = 0; i < charset.length; i++) { var unicode = GlyphsUnicode[charset[i]]; if (!unicode) continue; testString += String.fromCharCode(unicode); } - } - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var textWidth = ctx.measureText(testString).width; - if (debug) ctx.fillText(testString, 20, 20); + } + + // Periodicaly check for the width of the testString, it will be + // different once the real font has loaded + var textWidth = ctx.measureText(testString).width; var interval = window.setInterval(function canvasInterval(self) { this.start = this.start || Date.now(); @@ -248,12 +241,20 @@ var Font = (function () { if (debug) ctx.fillText(testString, 20, 50); - }, 50, this); + }, 30, this); /** Hack end */ + // Get the base64 encoding of the binary font data + var str = ""; + var length = data.length; + for (var i = 0; i < length; ++i) + str += String.fromCharCode(data[i]); + + var base64 = window.btoa(str); + // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");"; + var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); @@ -262,20 +263,23 @@ var Font = (function () { cover: function font_cover(aName, aFont, aProperties) { var otf = Uint8Array(kMaxFontFileSize); - function s2a(s) { - var a = []; - for (var i = 0; i < s.length; ++i) - a[i] = s.charCodeAt(i); - return a; + function stringToArray(str) { + var array = []; + for (var i = 0; i < str.length; ++i) + array[i] = str.charCodeAt(i); + return array; } - function s16(value) { - return String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); + function string16(value) { + return String.fromCharCode((value >> 8) & 0xff) + + String.fromCharCode(value & 0xff); } - function s32(value) { - return String.fromCharCode((value >> 24) & 0xff) + String.fromCharCode((value >> 16) & 0xff) + - String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); + function string32(value) { + return String.fromCharCode((value >> 24) & 0xff) + + String.fromCharCode((value >> 16) & 0xff) + + String.fromCharCode((value >> 8) & 0xff) + + String.fromCharCode(value & 0xff); } function createOpenTypeHeader(aFile, aOffsets, numTables) { @@ -285,20 +289,20 @@ var Font = (function () { header += "\x4F\x54\x54\x4F"; // numTables (2 bytes) - header += s16(numTables); + header += string16(numTables); // searchRange (2 bytes) var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); var searchRange = tablesMaxPower2 * 16; - header += s16(searchRange); + header += string16(searchRange); // entrySelector (2 bytes) - header += s16(Math.log(tablesMaxPower2) / Math.log(2)); + header += string16(Math.log(tablesMaxPower2) / Math.log(2)); // rangeShift (2 bytes) - header += s16(numTables * 16 - searchRange); + header += string16(numTables * 16 - searchRange); - aFile.set(s2a(header), aOffsets.currentOffset); + aFile.set(stringToArray(header), aOffsets.currentOffset); aOffsets.currentOffset += header.length; aOffsets.virtualOffset += header.length; } @@ -322,25 +326,27 @@ var Font = (function () { offset + length; - var tableEntry = aTag + s32(checksum) + s32(offset) + s32(length); - tableEntry = s2a(tableEntry); + var tableEntry = aTag + string32(checksum) + string32(offset) + string32(length); + tableEntry = stringToArray(tableEntry); aFile.set(tableEntry, aOffsets.currentOffset); + aOffsets.currentOffset += tableEntry.length; aOffsets.virtualOffset += aData.length; } function createNameTable(aName) { - var names = - "See original licence" + // Copyright - aName + // Font family - "undefined" + // Font subfamily (font weight) - "uniqueID" + // Unique ID - aName + // Full font name - "0.1" + // Version - "undefined" + // Postscript name - "undefined" + // Trademark - "undefined" + // Manufacturer - "undefined"; // Designer + var names = [ + "See original licence", // Copyright + aName, // Font family + "undefined", // Font subfamily (font weight) + "uniqueID", // Unique ID + aName, // Full font name + "0.1", // Version + "undefined", // Postscript name + "undefined", // Trademark + "undefined", // Manufacturer + "undefined" // Designer + ]; var name = "\x00\x00" + // format @@ -357,14 +363,14 @@ var Font = (function () { "\x00\x00" + // encoding ID "\x00\x00" + // language ID "\x00\x00" + // name ID - s16(str.length) + - s16(strOffset); + string16(str.length) + + string16(strOffset); name += nameRecord; strOffset += str.length; } - name += names; + name += names.join(""); return name; } @@ -407,12 +413,12 @@ var Font = (function () { "\x00\x01" + // encodingID "\x00\x00\x00\x0C" + // start of the table record "\x00\x04" + // format - s16(headerSize) + // length + string16(headerSize) + // length "\x00\x00" + // languages - s16(segCount2) + - s16(searchRange) + - s16(searchEntry) + - s16(rangeShift); + string16(segCount2) + + string16(searchRange) + + string16(searchEntry) + + string16(rangeShift); // Fill up the 4 parallel arrays describing the segments. var startCount = ""; @@ -428,10 +434,10 @@ var Font = (function () { var delta = (((start - 1) - bias) ^ 0xffff) + 1; bias += (end - start + 1); - startCount += s16(start); - endCount += s16(end); - idDeltas += s16(delta); - idRangeOffsets += s16(0); + startCount += string16(start); + endCount += string16(end); + idDeltas += string16(delta); + idRangeOffsets += string16(0); for (var j = start; j <= end; j++) glyphsIds += String.fromCharCode(j); @@ -442,7 +448,7 @@ var Font = (function () { idDeltas += "\x00\x01"; idRangeOffsets += "\x00\x00"; - return s2a(cmap + endCount + "\x00\x00" + startCount + + return stringToArray(cmap + endCount + "\x00\x00" + startCount + idDeltas + idRangeOffsets + glyphsIds); } @@ -477,7 +483,7 @@ var Font = (function () { createTableEntry(otf, offsets, "CFF ", CFF); /** OS/2 */ - OS2 = s2a( + OS2 = stringToArray( "\x00\x03" + // version "\x02\x24" + // xAvgCharWidth "\x01\xF4" + // usWeightClass @@ -526,7 +532,7 @@ var Font = (function () { createTableEntry(otf, offsets, "cmap", cmap); /** HEAD */ - head = s2a( + head = stringToArray( "\x00\x01\x00\x00" + // Version number "\x00\x00\x50\x00" + // fontRevision "\x00\x00\x00\x00" + // checksumAdjustement @@ -548,7 +554,7 @@ var Font = (function () { createTableEntry(otf, offsets, "head", head); /** HHEA */ - hhea = s2a( + hhea = stringToArray( "\x00\x01\x00\x00" + // Version number "\x00\x00" + // Typographic Ascent "\x00\x00" + // Typographic Descent @@ -565,7 +571,7 @@ var Font = (function () { "\x00\x00" + // -reserved- "\x00\x00" + // -reserved- "\x00\x00" + // metricDataFormat - s16(charstrings.length) + string16(charstrings.length) ); createTableEntry(otf, offsets, "hhea", hhea); @@ -575,19 +581,19 @@ var Font = (function () { var charstring = charstrings[i].charstring; var width = charstring[1]; var lsb = charstring[0]; - hmtx += s16(width) + s16(lsb); + hmtx += string16(width) + string16(lsb); } - hmtx = s2a(hmtx); + hmtx = stringToArray(hmtx); createTableEntry(otf, offsets, "hmtx", hmtx); /** MAXP */ maxp = "\x00\x00\x50\x00" + // Version number - s16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) - maxp = s2a(maxp); + string16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) + maxp = stringToArray(maxp); createTableEntry(otf, offsets, "maxp", maxp); /** NAME */ - name = s2a(createNameTable(aName)); + name = stringToArray(createNameTable(aName)); createTableEntry(otf, offsets, "name", name); /** POST */ @@ -601,7 +607,7 @@ var Font = (function () { "\x00\x00\x00\x00" + // maxMemType42 "\x00\x00\x00\x00" + // minMemType1 "\x00\x00\x00\x00"; // maxMemType1 - post = s2a(post); + post = stringToArray(post); createTableEntry(otf, offsets, "post", post); // Once all the table entries header are written, dump the data! @@ -622,6 +628,7 @@ var Font = (function () { return constructor; })(); + /** * FontsUtils is a static class dedicated to hold codes that are not related * to fonts in particular and needs to be share between them. @@ -1300,6 +1307,10 @@ var Type1Parser = function() { } }; +/** + * The CFF class takes a Type1 file and wrap it into a 'Compact Font Format', + * which itself embed Type2 charstrings. + */ const CFFStrings = [ ".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period", @@ -1358,10 +1369,6 @@ const CFFStrings = [ "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. - */ var CFF = function(aName, aFile, aProperties) { // Get the data block containing glyphs and subrs informations var length1 = aFile.dict.get("Length1"); diff --git a/pdf.js b/pdf.js index b140ef6c1..5c49f14dd 100644 --- a/pdf.js +++ b/pdf.js @@ -2561,7 +2561,7 @@ var CanvasGraphics = (function() { this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); this.ctx.translate(0, -2 * this.current.y); - this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); + this.ctx.fillText(Fonts.charsToUnicode(text), this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; this.ctx.restore(); From aa7e1ac6d6b07b45204127560824042ea8fb76c7 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 04:35:28 +0200 Subject: [PATCH 136/439] Add a name to some anonyous functions --- fonts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fonts.js b/fonts.js index 2f8a6c3df..ff749a3f5 100644 --- a/fonts.js +++ b/fonts.js @@ -88,7 +88,7 @@ var Fonts = { * type1Font.bind(); */ var Font = (function () { - var constructor = function(aName, aFile, aProperties) { + var constructor = function font_constructor(aName, aFile, aProperties) { this.name = aName; this.encoding = aProperties.encoding; @@ -833,7 +833,7 @@ var TrueType = function(aName, aFile, aProperties) { }); // Tables needs to be written by ascendant alphabetic order - tables.sort(function(a, b) { + tables.sort(function tables_sort(a, b) { return a.tag > b.tag; }); @@ -1452,7 +1452,7 @@ CFF.prototype = { } }; - charstrings.sort(function(a, b) { + charstrings.sort(function charstrings_sort(a, b) { return a.unicode > b.unicode; }); return charstrings; @@ -1480,7 +1480,7 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function(aGlyph, aCharstring, aSubrs) { + flattenCharstring: function flattenCharstring(aGlyph, aCharstring, aSubrs) { var i = 0; while (true) { var obj = aCharstring[i]; @@ -1584,7 +1584,7 @@ CFF.prototype = { error("failing with i = " + i + " in charstring:" + aCharstring + "(" + aCharstring.length + ")"); }, - wrap: function(aName, aProperties) { + wrap: function wrap(aName, aProperties) { var charstrings = this.getOrderedCharStrings(aProperties.glyphs); // Starts the conversion of the Type1 charstrings to Type2 From 6dc6f5d533f7614ca0af940265ae09cc6868d452 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Mon, 20 Jun 2011 22:39:49 -0400 Subject: [PATCH 137/439] restore getChar in JpegStream --- pdf.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdf.js b/pdf.js index 40044300c..1beeb6ca4 100644 --- a/pdf.js +++ b/pdf.js @@ -542,6 +542,9 @@ var JpegStream = (function() { constructor.prototype = { getImage: function() { return this.domImage; + }, + getChar: function() { + error("internal error: getChar is not valid on JpegStream"); } }; From 4b391d1b8351beb7bbf74d953f3748ed2a914611 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 19:51:36 -0700 Subject: [PATCH 138/439] working implementation of png and tiff predictors --- pdf.js | 105 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 14 deletions(-) diff --git a/pdf.js b/pdf.js index 488db9a9a..1e112e9ee 100644 --- a/pdf.js +++ b/pdf.js @@ -752,14 +752,66 @@ var PredictorStream = (function() { this.rowBytes = rowBytes; this.currentRow = new Uint8Array(rowBytes); + this.bufferLength = rowBytes; this.pos = rowBytes; } constructor.prototype = { readRowTiff : function() { + var currentRow = this.currentRow; + var rowBytes = this.rowBytes; + var pixBytes = this.pixBytes; + var bits = this.bits; + var colors = this.colors; + + var rawBytes = this.stream.getBytes(rowBytes - pixBytes); + + if (bits === 1) { + var inbuf = 0; + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) { + var c = rawBytes[j]; + inBuf = (inBuf << 8) | c; + // bitwise addition is exclusive or + // first shift inBuf and then add + currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF; + // truncate inBuf (assumes colors < 16) + inBuf &= 0xFFFF; + } + } else if (bits === 8) { + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) + currentRow[i] = currentRow[i - colors] + rawBytes[j]; + } else { + var compArray = new Uint8Array(colors + 1); + var bitMask = (1 << bits) - 1; + var inbuf = 0, outbut = 0; + var inbits = 0, outbits = 0; + var j = 0, k = pixBytes; + var columns = this.columns; + for (var i = 0; i < columns; ++i) { + for (var kk = 0; kk < colors; ++kk) { + if (inbits < bits) { + inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF); + inbits += 8; + } + compArray[kk] = (compArray[kk] + (inbuf >> + (inbits - bits))) & bitMask; + inbits -= bits; + outbuf = (outbuf << bits) | compArray[kk]; + outbits += bits; + if (outbits >= 8) { + currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF; + outbits -= 8; + } + } + } + if (outbits > 0) { + currentRow[k++] = (outbuf << (8 - outbits)) + + (inbuf & ((1 << (8 - outbits)) - 1)) + } + } + this.pos = pixBytes; }, readRowPng : function() { - // swap the buffers var currentRow = this.currentRow; var rowBytes = this.rowBytes; @@ -773,31 +825,56 @@ var PredictorStream = (function() { case 0: break; case 1: - for (i = pixBytes; i < rowBytes; ++i) - currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF; + // set the first pixel + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) + currentRow[i] = (currentRow[i - pixBytes] + rawBytes[j]) & 0xFF; break; case 2: - for (i = pixBytes; i < rowBytes; ++i) - currentRow[i] = (currentRow[i] + rawBytes[i]) & 0xFF; + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) + currentRow[i] = (currentRow[i] + rawBytes[j]) & 0xFF; break; case 3: - for (i = pixBytes; i < rowBytes; ++i) - currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) - >> 1) + rawBytes[i]) & 0xFF; + // set the first pixel + for (i = pixBytes, j = 0; i < rowBytes; ++i, ++j) + currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) + >> 1) + rawBytes[j]) & 0xFF; break; case 4: - for (i = pixBytes; i < rowBytes; ++i) { + // we need to save the up left pixels values. the simplest way + // is to create a new buffer + var lastRow = currentRow; + var currentRow = new Uint8Array(rowBytes); + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) { + var up = lastRow[i]; + var upLeft = lastRow[i - pixBytes]; var left = currentRow[i - pixBytes]; - var up = currentRow[i]; - var upLeft = + var p = left + up - upLeft; + + var pa = p - left; + if (pa < 0) + pa = -pa; + var pb = p - up; + if (pb < 0) + pb = -pb; + var pc = p - upLeft; + if (pc < 0) + pc = -pc; + + var c = rawBytes[j]; + if (pa <= pb && pa <= pc) + currentRow[i] = left + c; + else if (pb <= pc) + currentRow[i] = up + c; + else + currentRow[i] = upLeft + c; + break; + this.currentRow = currentRow; } default: error("Unsupported predictor"); break; } - this.pos = 0; - this.bufferLength = currentRow.length; - this.currentRow = currentRow; + this.pos = pixBytes; }, getByte : function() { if (this.pos >= this.bufferLength) { From d32cf251c7fce308be231f46f08d3f8512803831 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 20:19:13 -0700 Subject: [PATCH 139/439] Bug fix when an array of filters is passed in --- pdf.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 40044300c..00e504a6c 100644 --- a/pdf.js +++ b/pdf.js @@ -1229,7 +1229,8 @@ var Parser = (function() { if (IsArray(filter)) { var filterArray = filter; var paramsArray = params; - for (filter in filterArray) { + for (var i = 0, ii = filter.length; i < ii; ++i) { + filter = filter[i]; if (!IsName(filter)) error("Bad filter name"); else { From f5a1d90b8595859dbbcf689d1caa9e6dbfe0c8aa Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 20:28:48 -0700 Subject: [PATCH 140/439] cleaned up code --- pdf.js | 170 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 169 deletions(-) diff --git a/pdf.js b/pdf.js index 1e112e9ee..91d6476a2 100644 --- a/pdf.js +++ b/pdf.js @@ -526,172 +526,6 @@ var FlateStream = (function() { return constructor; })(); -/* -var FilterPredictor = (function() { - function constructor(str, type, width, colors, bits) { - this.str = str; - this.dict = str.dict; - - this.type = type; - this.width = width; - this.colors = colors; - this.bits = bits; - - this.nVals = width * colors; - var pixBytes = (colors * bits + 7) >> 3; - this.pixBytes = pixBytes; - var rowBytes = ((width * colors * bits + 7) >> 3) + pixBytes; - this.rowBytes = rowBytes; - - if (width < 0 || colors < 0 || bits < 0 ||bits > 16) - error("Invalid predictor"); - - var prevLine = []; - for (var i = 0; i < rowBytes; ++i) - prevLine.push(0); - this.prevLine = prevLine; - this.prevIdx = rowBytes; - } - - constructor.prototype = { - getByte: function() { - if (this.prevIdx >= this.rowBytes) { - if(!this.getNextLine()) - return; - } - return this.prevLine[this.prevIdx++]; - }, - getBytes: function(length) { - var buf = new Uint8Array(length); - for (var i = 0; i < length; ++i) - buf[i] = this.getByte(); - return buf; - }, - getNextLine: function() { - if (this.type >= 10) { - var curType = this.str.getByte(); - if (!curType) - return; - curType += 10; - } else { - var curType = this.type; - } - - var line = []; - for (var i = 0; i < this.rowBytes - this.pixBytes; i++) - line.push(this.str.getByte()); - - var pixBytes = this.pixBytes; - var rowBytes = this.rowBytes; - var prevLine = this.prevLine; - - var upLeftBuf = []; - for (var i = 0, ii = pixBytes + 1; i < ii; ++i) - upLeftBuf.push(0); - - for (var i = pixBytes, ii = rowBytes + pixBytes + 1; i < ii; ++i) { - for (var j = pixBytes; j > 0; --j) { - upLeftBuf[j] = upLeftBuf[j - 1]; - } - upLeftBuf[0] = prevLine[i]; - - var c = line[i - pixBytes]; - if (c == undefined) { - if (i > pixBytes) - break; - return; - } - switch (curType) { - case 11: - prevLine[i] = prevLine[i - pixBytes] + c; - break; - case 12: - prevLine[i] = prevLine[i] + c; - break; - case 13: - prevLine[i] = ((prevLine[i - pixBytes] - + prevLine[i]) >> 1) + c; - break; - case 14: - var left = prevLine[i - pixBytes]; - var up = prevLine[i]; - var upLeft = upLeftBuf[pixBytes]; - var p = left + up - upLeft; - - var pa = p - left; - if (pa < 0) - pa = -pa; - var pb = p - up; - if (pb < 0) - pb = -pb; - var pc = p - upLeft; - if (pc < 0) - pc = -pc; - - if (pa <= pb && pa <= pc) - prevLine[i] = left + c; - else if (pb <= pc) - prevLine[i] = up + c; - else - prevLine[i] = upLeft + c; - break; - case 10: - default: - prevLine[i] = c; - break; - } - } - var bits = this.bits; - var colors = this.colors; - - if (curType === 2) { - if (bits === 1) { - var inbuf = prevLine[pixBytes - 1]; - for (var i = pixBytes; i < rowBytes; i+= 8) { - inBuf = (inBuf << 8) | prevLine[i]; - prevLine[i] ^= inBuf >> colors; - } - } else if (bits === 8) { - for (var i = pixBytes; i < rowBytes; ++i) - prevLine[i] += prevLine[i - colors]; - } else { - for (var i = 0, ii = colors + 1; i < ii; ++i) - upLeftBuf[i] = 0; - var bitMask = (1 << bits) - 1; - var inbuf = 0, outbut = 0; - var inbits = 0, outbits = 0; - var j = pixBytes, k = pixBytes; - var width = this.width; - for (var i = 0; i < width; ++i) { - for (var kk = 0; kk < colors; ++kk) { - if (inbits < bits) { - inbuf = (inbuf << 8) | (prevLine[j++] & 255); - inbits += 8; - } - upLeftBuf[kk] = (upLeftBuf[kk] + (inbuf >> - (inbits - bits))) & bitMask; - inbits -= bits; - outbuf = (outbuf << bits) | upLeftBuf[kk]; - outbits += bits; - if (outbits >= 8) { - prevLine[k++] = (outbuf >> (outbits - 8)); - outbits -= 8; - } - } - } - if (outbits > 0) { - prevLine[k++] = (outbuf << (8 - outbits)) + - (inbuf & ((1 << (8 - outbits)) - 1)) - } - } - } - this.prevIdx = pixBytes; - return true; - } - }; - return constructor; -})(); -*/ // A JpegStream can't be read directly. We use the platform to render the underlying // JPEG data for us. var JpegStream = (function() { @@ -747,7 +581,7 @@ var PredictorStream = (function() { var pixBytes = (colors * bits + 7) >> 3; this.pixBytes = pixBytes; - // add an extra pixByte to represent the pixel left column 0 + // add an extra pixByte to represent the pixel left of column 0 var rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; this.rowBytes = rowBytes; @@ -825,7 +659,6 @@ var PredictorStream = (function() { case 0: break; case 1: - // set the first pixel for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) currentRow[i] = (currentRow[i - pixBytes] + rawBytes[j]) & 0xFF; break; @@ -834,7 +667,6 @@ var PredictorStream = (function() { currentRow[i] = (currentRow[i] + rawBytes[j]) & 0xFF; break; case 3: - // set the first pixel for (i = pixBytes, j = 0; i < rowBytes; ++i, ++j) currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) >> 1) + rawBytes[j]) & 0xFF; From 9d4f31a494740f67970bf5542aae3a2d0b64c64b Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 20:41:24 -0700 Subject: [PATCH 141/439] cleaned up code --- pdf.js | 73 +++++++++++++++++----------------------------------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/pdf.js b/pdf.js index 91d6476a2..96c0c5438 100644 --- a/pdf.js +++ b/pdf.js @@ -19,7 +19,6 @@ function warn(msg) { } function error(msg) { - console.trace(); throw new Error(msg); } @@ -540,10 +539,9 @@ var JpegStream = (function() { } constructor.prototype = { - getByte: function() { - // dummy method to pass IsStream test - error("shouldnt be called"); - }, + getChar: function() { + }, + getImage: function() { return this.domImage; } @@ -653,7 +651,6 @@ var PredictorStream = (function() { var predictor = this.stream.getByte(); var rawBytes = this.stream.getBytes(rowBytes - pixBytes); - var i; switch (predictor) { case 0: @@ -667,7 +664,7 @@ var PredictorStream = (function() { currentRow[i] = (currentRow[i] + rawBytes[j]) & 0xFF; break; case 3: - for (i = pixBytes, j = 0; i < rowBytes; ++i, ++j) + for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) >> 1) + rawBytes[j]) & 0xFF; break; @@ -767,9 +764,6 @@ var Name = (function() { } constructor.prototype = { - toString: function() { - return this.name; - } }; return constructor; @@ -781,9 +775,6 @@ var Cmd = (function() { } constructor.prototype = { - toString: function() { - return this.cmd; - } }; return constructor; @@ -796,23 +787,22 @@ var Dict = (function() { constructor.prototype = { get: function(key) { - return this.map[key]; - }, - get2: function(key1, key2) { - return this.get(key1) || this.get(key2); - }, - has: function(key) { - return key in this.map; - }, - set: function(key, value) { - this.map[key] = value; - }, - forEach: function(aCallback) { - for (var key in this.map) - aCallback(key, this.map[key]); + return this.map[key]; + }, + get2: function(key1, key2) { + return this.get(key1) || this.get(key2); + }, + has: function(key) { + return key in this.map; + }, + set: function(key, value) { + this.map[key] = value; + }, + forEach: function(aCallback) { + for (var key in this.map) + aCallback(key, this.map[key]); } }; - return constructor; })(); @@ -865,7 +855,7 @@ function IsArray(v) { } function IsStream(v) { - return typeof v == "object" && "getByte" in v; + return typeof v == "object" && "getChar" in v; } function IsRef(v) { @@ -1364,27 +1354,6 @@ var Parser = (function() { }, makeFilter: function(stream, name, length, params) { if (name == "FlateDecode" || name == "Fl") { -/* var flateStr = new FlateStream(stream); - if (IsDict(params)) { - var predType = params.get("Predictor"); - if (predType && predType > 1) { - var colors = params.get("Colors"); - if (!colors) - colors = 1; - var bpc = params.get("BitsPerComponent"); - if (!bpc) - bpc = 8; - var cols = params.get("Columns"); - if (!cols) - cols = 1; - - log("Predictor being used"); - flateStr = new FilterPredictor(flateStr, predType, cols, - colors, bpc); - } - } - return flateStr; -*/ if (params) { return new PredictorStream(new FlateStream(stream), params); } @@ -3096,8 +3065,8 @@ var CanvasGraphics = (function() { error("unhandled number of bits per component"); if (smask) { - //if (maskColorSpace.numComps != 1) - // error("Incorrect number of components in smask"); + if (maskColorSpace.numComps != 1) + error("Incorrect number of components in smask"); var numComps = colorSpace.numComps; var imgArray = image.getBytes(numComps * w * h); From dbaf83d53f1d487b630c670c8e1ff0f343b9e090 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 20:45:29 -0700 Subject: [PATCH 142/439] working implementation of png and tiff predictors --- pdf.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 96c0c5438..7a38b9729 100644 --- a/pdf.js +++ b/pdf.js @@ -539,8 +539,9 @@ var JpegStream = (function() { } constructor.prototype = { + // Needed to pass IsStream test getChar: function() { - }, + }, getImage: function() { return this.domImage; @@ -3022,7 +3023,7 @@ var CanvasGraphics = (function() { var smask = image.dict.get("SMask"); smask = xref.fetchIfRef(smask); - if (smask) { + if (IsStream(smask)) { if (inline) error("cannot combine smask and inlining"); From 4f11c5c34285cca06f3c6de117d5a75dfa3b99c4 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Mon, 20 Jun 2011 22:55:32 -0500 Subject: [PATCH 143/439] Fixes 09061a2cc48da67768b regression, spaces, and default value for type --- pdf.js | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/pdf.js b/pdf.js index 1beeb6ca4..40e05cf98 100644 --- a/pdf.js +++ b/pdf.js @@ -1444,26 +1444,29 @@ var XRef = (function() { for (i = 0; i < n; ++i) { var type = 0, offset = 0, generation = 0; for (j = 0; j < typeFieldWidth; ++j) - type = (type << 8) | stream.getByte(); + type = (type << 8) | stream.getByte(); + // if type field is absent, its default value = 1 + if (typeFieldWidth == 0) + type = 1; for (j = 0; j < offsetFieldWidth; ++j) - offset = (offset << 8) | stream.getByte(); + offset = (offset << 8) | stream.getByte(); for (j = 0; j < generationFieldWidth; ++j) - generation = (generation << 8) | stream.getByte(); - var entry = new Ref(offset, generation); - if (typeFieldWidth > 0) { - switch (type) { - case 0: - entry.free = true; - break; - case 1: - entry.uncompressed = true; - break; - case 2: - break; - default: - error("Invalid XRef entry type"); - break; - } + generation = (generation << 8) | stream.getByte(); + var entry = {} + entry.offset = offset; + entry.gen = generation; + switch (type) { + case 0: + entry.free = true; + break; + case 1: + entry.uncompressed = true; + break; + case 2: + break; + default: + error("Invalid XRef entry type"); + break; } if (!this.entries[first + i]) this.entries[first + i] = entry; From 2315131b90d99cb82debe1aaaa331111a8f8bdb4 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 06:49:59 +0200 Subject: [PATCH 144/439] Get rid of the TrueType class, adapt the code to conventions and new code --- fonts.js | 1513 +++++++++++++++++++++++------------------------------- pdf.js | 3 +- 2 files changed, 647 insertions(+), 869 deletions(-) diff --git a/fonts.js b/fonts.js index ff749a3f5..ad3d4fd35 100644 --- a/fonts.js +++ b/fonts.js @@ -39,8 +39,8 @@ var Fonts = { return this._active; }, - set active(aName) { - this._active = this[aName]; + set active(name) { + this._active = this[name]; }, charsToUnicode: function fonts_chars2Unicode(chars) { @@ -49,7 +49,7 @@ var Fonts = { return chars; // if we translated this string before, just grab it from the cache - var str = active.cache[chars] || ""; + var str = active.cache[chars]; if (str) return str; @@ -58,6 +58,7 @@ var Fonts = { if (!encoding) return chars; + str = ""; for (var i = 0; i < chars.length; ++i) { var charcode = chars.charCodeAt(i); var unicode = encoding[charcode]; @@ -88,23 +89,23 @@ var Fonts = { * type1Font.bind(); */ var Font = (function () { - var constructor = function font_constructor(aName, aFile, aProperties) { - this.name = aName; - this.encoding = aProperties.encoding; + var constructor = function font_constructor(name, file, properties) { + this.name = name; + this.encoding = properties.encoding; // If the font has already been decoded simply return it - if (Fonts[aName]) { - this.font = Fonts[aName].data; + if (Fonts[name]) { + this.font = Fonts[name].data; return; } fontCount++; - fontName = aName; + fontName = name; // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. - if (aProperties.ignore || kDisableFonts) { - Fonts[aName] = { - data: aFile, + if (properties.ignore || properties.type == "TrueType" || kDisableFonts) { + Fonts[name] = { + data: file, loading: false, properties: {}, cache: Object.create(null) @@ -112,41 +113,31 @@ var Font = (function () { return; } - switch (aProperties.type) { + switch (properties.type) { case "Type1": - var cff = new CFF(aName, aFile, aProperties); + var cff = new CFF(name, file, properties); this.mimetype = "font/opentype"; // Wrap the CFF data inside an OTF font file - this.font = this.cover(aName, cff, aProperties); + this.font = this.convert(name, cff, properties); break; case "TrueType": - // TrueType is disabled for the moment since the sanitizer prevent it - // from loading due to missing tables - return Fonts[aName] = { - data: null, - properties: { - encoding: {}, - charset: null - }, - loading: false, - cache: Object.create(null) - }; - this.mimetype = "font/opentype"; - var ttf = new TrueType(aName, aFile, aProperties); - this.font = ttf.data; + + // Repair the TrueType file if it is can be damaged in the point of + // view of the sanitizer + this.font = this.checkAndRepair(name, file, properties); break; default: - warn("Font " + aProperties.type + " is not supported"); + warn("Font " + properties.type + " is not supported"); break; } - Fonts[aName] = { + Fonts[name] = { data: this.font, - properties: aProperties, + properties: properties, loading: true, cache: Object.create(null) } @@ -155,6 +146,200 @@ var Font = (function () { this.bind(); }; + function stringToArray(str) { + var array = []; + for (var i = 0; i < str.length; ++i) + array[i] = str.charCodeAt(i); + + return array; + }; + + function string16(value) { + return String.fromCharCode((value >> 8) & 0xff) + + String.fromCharCode(value & 0xff); + }; + + function string32(value) { + return String.fromCharCode((value >> 24) & 0xff) + + String.fromCharCode((value >> 16) & 0xff) + + String.fromCharCode((value >> 8) & 0xff) + + String.fromCharCode(value & 0xff); + }; + + function createOpenTypeHeader(sfnt, file, offsets, numTables) { + // sfnt version (4 bytes) + var header = sfnt; + + // numTables (2 bytes) + header += string16(numTables); + + // searchRange (2 bytes) + var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); + var searchRange = tablesMaxPower2 * 16; + header += string16(searchRange); + + // entrySelector (2 bytes) + header += string16(Math.log(tablesMaxPower2) / Math.log(2)); + + // rangeShift (2 bytes) + header += string16(numTables * 16 - searchRange); + + file.set(stringToArray(header), offsets.currentOffset); + offsets.currentOffset += header.length; + offsets.virtualOffset += header.length; + }; + + function createTableEntry(file, offsets, tag, data) { + // offset + var offset = offsets.virtualOffset; + + // Per spec tables must be 4-bytes align so add padding as needed + while (data.length & 3) + data.push(0x00); + + while (offsets.virtualOffset & 3) + offsets.virtualOffset++; + + // length + var length = data.length; + + // checksum + var checksum = tag.charCodeAt(0) + + tag.charCodeAt(1) + + tag.charCodeAt(2) + + tag.charCodeAt(3) + + offset + + length; + + var tableEntry = tag + string32(checksum) + string32(offset) + string32(length); + tableEntry = stringToArray(tableEntry); + file.set(tableEntry, offsets.currentOffset); + + offsets.currentOffset += tableEntry.length; + offsets.virtualOffset += data.length; + }; + + function getRanges(glyphs) { + // Array.sort() sorts by characters, not numerically, so convert to an + // array of characters. + var codes = []; + var length = glyphs.length; + for (var n = 0; n < length; ++n) + codes.push(String.fromCharCode(glyphs[n].unicode)) + codes.sort(); + + // Split the sorted codes into ranges. + var ranges = []; + for (var n = 0; n < length; ) { + var start = codes[n++].charCodeAt(0); + var end = start; + while (n < length && end + 1 == codes[n].charCodeAt(0)) { + ++end; + ++n; + } + ranges.push([start, end]); + } + return ranges; + }; + + function createCMAPTable(glyphs) { + var ranges = getRanges(glyphs); + + var headerSize = (12 * 2 + (ranges.length * 4 * 2)); + var segCount = ranges.length + 1; + var segCount2 = segCount * 2; + var searchRange = FontsUtils.getMaxPower2(segCount) * 2; + var searchEntry = Math.log(segCount) / Math.log(2); + var rangeShift = 2 * segCount - searchRange; + + var cmap = "\x00\x00" + // version + "\x00\x01" + // numTables + "\x00\x03" + // platformID + "\x00\x01" + // encodingID + "\x00\x00\x00\x0C" + // start of the table record + "\x00\x04" + // format + string16(headerSize) + // length + "\x00\x00" + // languages + string16(segCount2) + + string16(searchRange) + + string16(searchEntry) + + string16(rangeShift); + + // Fill up the 4 parallel arrays describing the segments. + var startCount = ""; + var endCount = ""; + var idDeltas = ""; + var idRangeOffsets = ""; + var glyphsIds = ""; + var bias = 0; + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = range[0]; + var end = range[1]; + var delta = (((start - 1) - bias) ^ 0xffff) + 1; + bias += (end - start + 1); + + startCount += string16(start); + endCount += string16(end); + idDeltas += string16(delta); + idRangeOffsets += string16(0); + + for (var j = start; j <= end; j++) + glyphsIds += String.fromCharCode(j); + } + + startCount += "\xFF\xFF"; + endCount += "\xFF\xFF"; + idDeltas += "\x00\x01"; + idRangeOffsets += "\x00\x00"; + + return stringToArray(cmap + endCount + "\x00\x00" + startCount + + idDeltas + idRangeOffsets + glyphsIds); + }; + + function createOS2Table() { + var OS2 = stringToArray( + "\x00\x03" + // version + "\x02\x24" + // xAvgCharWidth + "\x01\xF4" + // usWeightClass + "\x00\x05" + // usWidthClass + "\x00\x00" + // fstype + "\x02\x8A" + // ySubscriptXSize + "\x02\xBB" + // ySubscriptYSize + "\x00\x00" + // ySubscriptXOffset + "\x00\x8C" + // ySubscriptYOffset + "\x02\x8A" + // ySuperScriptXSize + "\x02\xBB" + // ySuperScriptYSize + "\x00\x00" + // ySuperScriptXOffset + "\x01\xDF" + // ySuperScriptYOffset + "\x00\x31" + // yStrikeOutSize + "\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) + "\x2A\x32\x31\x2A" + // achVendID + "\x00\x20" + // fsSelection + "\x00\x2D" + // usFirstCharIndex + "\x00\x7A" + // usLastCharIndex + "\x00\x03" + // sTypoAscender + "\x00\x20" + // sTypeDescender + "\x00\x38" + // sTypoLineGap + "\x00\x5A" + // usWinAscent + "\x02\xB4" + // usWinDescent + "\x00\xCE\x00\x00" + // ulCodePageRange1 (Bits 0-31) + "\x00\x01\x00\x00" + // ulCodePageRange2 (Bits 32-63) + "\x00\x00" + // sxHeight + "\x00\x00" + // sCapHeight + "\x00\x01" + // usDefaultChar + "\x00\xCD" + // usBreakChar + "\x00\x02" // usMaxContext + ); + return OS2; + }; + /** * A bunch of the OpenType code is duplicate between this class and the * TrueType code, this is intentional and will merge in a future version @@ -169,6 +354,347 @@ var Font = (function () { mimetype: null, encoding: null, + checkAndRepair: function font_checkAndRepair(name, font, properties) { + function readTableEntry(file) { + // tag + var tag = file.getBytes(4); + tag = String.fromCharCode(tag[0]) + + String.fromCharCode(tag[1]) + + String.fromCharCode(tag[2]) + + String.fromCharCode(tag[3]); + + var checksum = FontsUtils.bytesToInteger(file.getBytes(4)); + var offset = FontsUtils.bytesToInteger(file.getBytes(4)); + var length = FontsUtils.bytesToInteger(file.getBytes(4)); + + // Read the table associated data + var currentPosition = file.pos; + file.pos = file.start + offset; + + var data = file.getBytes(length); + file.pos = currentPosition; + + return { + tag: tag, + checksum: checksum, + length: offset, + offset: length, + data: data + } + }; + + function readOpenTypeHeader(ttf) { + return { + version: ttf.getBytes(4), + numTables: FontsUtils.bytesToInteger(ttf.getBytes(2)), + searchRange: FontsUtils.bytesToInteger(ttf.getBytes(2)), + entrySelector: FontsUtils.bytesToInteger(ttf.getBytes(2)), + rangeShift: FontsUtils.bytesToInteger(ttf.getBytes(2)) + } + }; + + // Check that required tables are present + var requiredTables = [ "OS/2", "cmap", "head", "hhea", + "hmtx", "maxp", "name", "post" ]; + + var header = readOpenTypeHeader(font); + var numTables = header.numTables; + + // This keep a reference to the CMap and the post tables since they can + // be rewritted + var cmap, post; + + var tables = []; + for (var i = 0; i < numTables; i++) { + var table = readTableEntry(font); + var index = requiredTables.indexOf(table.tag); + if (index != -1) { + if (table.tag == "cmap") + cmap = table; + else if (table.tag == "post") + post = table; + + requiredTables.splice(index, 1); + } + tables.push(table); + } + + // If any tables are still in the array this means some required tables are + // missing, which means that we need to rebuild the font in order to pass + // the sanitizer. + if (requiredTables.length && requiredTables[0] == "OS/2") { + // Create a new file to hold the new version of our truetype with a new + // header and new offsets + var ttf = Uint8Array(kMaxFontFileSize); + + // The offsets object holds at the same time a representation of where + // to write the table entry information about a table and another offset + // representing the offset where to put the actual data of a particular + // table + var numTables = header.numTables + requiredTables.length; + var offsets = { + currentOffset: 0, + virtualOffset: numTables * (4 * 4) + }; + + // The new numbers of tables will be the last one plus the num of missing + // tables + createOpenTypeHeader("\x00\x01\x00\x00", ttf, offsets, numTables); + + // Insert the missing table + var OS2 = createOS2Table(); + tables.push({ + tag: "OS/2", + data: OS2 + }); + + // If the font is missing a OS/2 table it's could be an old mac font + // without a 3-1-4 Unicode BMP table, so let's rewrite it. + var charset = properties.charset; + var glyphs = []; + for (var i = 0; i < charset.length; i++) { + glyphs.push({ + unicode: GlyphsUnicode[charset[i]] + }); + } + + // Replace the old CMAP table with a shiny new one + cmap.data = createCMAPTable(glyphs); + + // Rewrite the 'post' table if needed + if (!post) { + post = + "\x00\x03\x00\x00" + // Version number + "\x00\x00\x01\x00" + // 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 + + tables.unshift({ + tag: "post", + data: stringToArray(post) + }); + } + + // Tables needs to be written by ascendant alphabetic order + tables.sort(function tables_sort(a, b) { + return a.tag > b.tag; + }); + + // rewrite the tables but tweak offsets + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var data = []; + + var tableData = table.data; + for (var j = 0; j < tableData.length; j++) + data.push(tableData[j]); + createTableEntry(ttf, offsets, table.tag, data); + } + + // Add the table datas + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var tableData = table.data; + ttf.set(tableData, offsets.currentOffset); + offsets.currentOffset += tableData.length; + + // 4-byte aligned data + while (offsets.currentOffset & 3) + offsets.currentOffset++; + } + + var fontData = []; + for (var i = 0; i < offsets.currentOffset; i++) + fontData.push(ttf[i]); + + return fontData; + } else if (requiredTables.length) { + error("Table " + requiredTables[0] + " is missing from the TrueType font"); + } + + return font.getBytes(); + }, + + convert: function font_convert(name, font, properties) { + var otf = Uint8Array(kMaxFontFileSize); + + function createNameTable(name) { + var names = [ + "See original licence", // Copyright + name, // Font family + "undefined", // Font subfamily (font weight) + "uniqueID", // Unique ID + name, // Full font name + "0.1", // Version + "undefined", // Postscript name + "undefined", // Trademark + "undefined", // Manufacturer + "undefined" // Designer + ]; + + var name = + "\x00\x00" + // format + "\x00\x0A" + // Number of names Record + "\x00\x7E"; // 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); + name += nameRecord; + + strOffset += str.length; + } + + name += names.join(""); + return name; + } + + // Required Tables + var CFF = + font.data, // PostScript Font Program + OS2, // OS/2 and Windows Specific metrics + cmap, // Character to glyphs mapping + head, // Font eader + hhea, // Horizontal header + hmtx, // Horizontal metrics + maxp, // Maximum profile + name, // Naming tables + post; // PostScript informations + var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; + + // The offsets object holds at the same time a representation of where + // to write the table entry information about a table and another offset + // representing the offset where to draw the actual data of a particular + // table + var offsets = { + currentOffset: 0, + virtualOffset: tables.length * (4 * 4) + }; + + // It there is only one font, offset table is the first bytes of the file + createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, tables.length); + + /** CFF */ + createTableEntry(otf, offsets, "CFF ", CFF); + + /** OS/2 */ + OS2 = createOS2Table(); + createTableEntry(otf, offsets, "OS/2", OS2); + + //XXX Getting charstrings here seems wrong since this is another CFF glue + var charstrings = font.getOrderedCharStrings(properties.glyphs); + + /** CMAP */ + cmap = createCMAPTable(charstrings); + createTableEntry(otf, offsets, "cmap", cmap); + + /** HEAD */ + head = stringToArray( + "\x00\x01\x00\x00" + // Version number + "\x00\x00\x50\x00" + // fontRevision + "\x00\x00\x00\x00" + // checksumAdjustement + "\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" + // xMin + "\x00\x00" + // yMin + "\x00\x00" + // xMax + "\x00\x00" + // yMax + "\x00\x00" + // macStyle + "\x00\x00" + // lowestRecPPEM + "\x00\x00" + // fontDirectionHint + "\x00\x00" + // indexToLocFormat + "\x00\x00" // glyphDataFormat + ); + createTableEntry(otf, offsets, "head", head); + + /** HHEA */ + hhea = stringToArray( + "\x00\x01\x00\x00" + // Version number + "\x00\x00" + // Typographic Ascent + "\x00\x00" + // Typographic Descent + "\x00\x00" + // Line Gap + "\xFF\xFF" + // advanceWidthMax + "\x00\x00" + // minLeftSidebearing + "\x00\x00" + // minRightSidebearing + "\x00\x00" + // xMaxExtent + "\x00\x00" + // caretSlopeRise + "\x00\x00" + // caretSlopeRun + "\x00\x00" + // caretOffset + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // -reserved- + "\x00\x00" + // metricDataFormat + string16(charstrings.length) + ); + createTableEntry(otf, offsets, "hhea", hhea); + + /** HMTX */ + hmtx = "\x01\xF4\x00\x00"; + for (var i = 0; i < charstrings.length; i++) { + var charstring = charstrings[i].charstring; + var width = charstring[1]; + var lsb = charstring[0]; + hmtx += string16(width) + string16(lsb); + } + hmtx = stringToArray(hmtx); + createTableEntry(otf, offsets, "hmtx", hmtx); + + /** MAXP */ + maxp = "\x00\x00\x50\x00" + // Version number + string16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) + maxp = stringToArray(maxp); + createTableEntry(otf, offsets, "maxp", maxp); + + /** NAME */ + name = stringToArray(createNameTable(name)); + createTableEntry(otf, offsets, "name", name); + + /** POST */ + // TODO: get those informations from the FontInfo structure + post = "\x00\x03\x00\x00" + // Version number + "\x00\x00\x01\x00" + // 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 + post = stringToArray(post); + createTableEntry(otf, offsets, "post", post); + + // Once all the table entries header are written, dump the data! + var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + otf.set(table, offsets.currentOffset); + offsets.currentOffset += table.length; + } + + var fontData = []; + for (var i = 0; i < offsets.currentOffset; i++) + fontData.push(otf[i]); + return fontData; + }, + bind: function font_bind() { var data = this.font; var fontName = this.name; @@ -258,370 +784,6 @@ var Font = (function () { var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); - }, - - cover: function font_cover(aName, aFont, aProperties) { - var otf = Uint8Array(kMaxFontFileSize); - - function stringToArray(str) { - var array = []; - for (var i = 0; i < str.length; ++i) - array[i] = str.charCodeAt(i); - return array; - } - - function string16(value) { - return String.fromCharCode((value >> 8) & 0xff) + - String.fromCharCode(value & 0xff); - } - - function string32(value) { - return String.fromCharCode((value >> 24) & 0xff) + - String.fromCharCode((value >> 16) & 0xff) + - String.fromCharCode((value >> 8) & 0xff) + - String.fromCharCode(value & 0xff); - } - - function createOpenTypeHeader(aFile, aOffsets, numTables) { - var header = ""; - - // sfnt version (4 bytes) - header += "\x4F\x54\x54\x4F"; - - // numTables (2 bytes) - header += string16(numTables); - - // searchRange (2 bytes) - var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); - var searchRange = tablesMaxPower2 * 16; - header += string16(searchRange); - - // entrySelector (2 bytes) - header += string16(Math.log(tablesMaxPower2) / Math.log(2)); - - // rangeShift (2 bytes) - header += string16(numTables * 16 - searchRange); - - aFile.set(stringToArray(header), aOffsets.currentOffset); - aOffsets.currentOffset += header.length; - aOffsets.virtualOffset += header.length; - } - - function createTableEntry(aFile, aOffsets, aTag, aData) { - // offset - var offset = aOffsets.virtualOffset; - - // Per spec tables must be 4-bytes align so add padding as needed - while (aData.length & 3) - aData.push(0x00); - - // length - var length = aData.length; - - // checksum - var checksum = aTag.charCodeAt(0) + - aTag.charCodeAt(1) + - aTag.charCodeAt(2) + - aTag.charCodeAt(3) + - offset + - length; - - var tableEntry = aTag + string32(checksum) + string32(offset) + string32(length); - tableEntry = stringToArray(tableEntry); - aFile.set(tableEntry, aOffsets.currentOffset); - - aOffsets.currentOffset += tableEntry.length; - aOffsets.virtualOffset += aData.length; - } - - function createNameTable(aName) { - var names = [ - "See original licence", // Copyright - aName, // Font family - "undefined", // Font subfamily (font weight) - "uniqueID", // Unique ID - aName, // Full font name - "0.1", // Version - "undefined", // Postscript name - "undefined", // Trademark - "undefined", // Manufacturer - "undefined" // Designer - ]; - - var name = - "\x00\x00" + // format - "\x00\x0A" + // Number of names Record - "\x00\x7E"; // 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); - name += nameRecord; - - strOffset += str.length; - } - - name += names.join(""); - return name; - } - - function getRanges(glyphs) { - // Array.sort() sorts by characters, not numerically, so convert to an - // array of characters. - var codes = []; - var length = glyphs.length; - for (var n = 0; n < length; ++n) - codes.push(String.fromCharCode(glyphs[n].unicode)) - codes.sort(); - - // Split the sorted codes into ranges. - var ranges = []; - for (var n = 0; n < length; ) { - var start = codes[n++].charCodeAt(0); - var end = start; - while (n < length && end + 1 == codes[n].charCodeAt(0)) { - ++end; - ++n; - } - ranges.push([start, end]); - } - return ranges; - } - - function createCMAPTable(aGlyphs) { - var ranges = getRanges(aGlyphs); - - var headerSize = (12 * 2 + (ranges.length * 4 * 2)); - var segCount = ranges.length + 1; - var segCount2 = segCount * 2; - var searchRange = FontsUtils.getMaxPower2(segCount) * 2; - var searchEntry = Math.log(segCount) / Math.log(2); - var rangeShift = 2 * segCount - searchRange; - - var cmap = "\x00\x00" + // version - "\x00\x01" + // numTables - "\x00\x03" + // platformID - "\x00\x01" + // encodingID - "\x00\x00\x00\x0C" + // start of the table record - "\x00\x04" + // format - string16(headerSize) + // length - "\x00\x00" + // languages - string16(segCount2) + - string16(searchRange) + - string16(searchEntry) + - string16(rangeShift); - - // Fill up the 4 parallel arrays describing the segments. - var startCount = ""; - var endCount = ""; - var idDeltas = ""; - var idRangeOffsets = ""; - var glyphsIds = ""; - var bias = 0; - for (var i = 0; i < segCount - 1; i++) { - var range = ranges[i]; - var start = range[0]; - var end = range[1]; - var delta = (((start - 1) - bias) ^ 0xffff) + 1; - bias += (end - start + 1); - - startCount += string16(start); - endCount += string16(end); - idDeltas += string16(delta); - idRangeOffsets += string16(0); - - for (var j = start; j <= end; j++) - glyphsIds += String.fromCharCode(j); - } - - startCount += "\xFF\xFF"; - endCount += "\xFF\xFF"; - idDeltas += "\x00\x01"; - idRangeOffsets += "\x00\x00"; - - return stringToArray(cmap + endCount + "\x00\x00" + startCount + - idDeltas + idRangeOffsets + glyphsIds); - } - - // Required Tables - var CFF = aFont.data, // PostScript Font Program - OS2 = [], // OS/2 and Windows Specific metrics - cmap = [], // Character to glyphs mapping - head = [], // Font eader - hhea = [], // Horizontal header - hmtx = [], // Horizontal metrics - maxp = [], // Maximum profile - name = [], // Naming tables - post = []; // PostScript informations - var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; - - // The offsets object holds at the same time a representation of where - // to write the table entry information about a table and another offset - // representing the offset where to draw the actual data of a particular - // table - var offsets = { - currentOffset: 0, - virtualOffset: tables.length * (4 * 4) - }; - - // For files with only one font the offset table is the first thing of the - // file - createOpenTypeHeader(otf, offsets, tables.length); - - // TODO: It is probable that in a future we want to get rid of this glue - // between the CFF and the OTF format in order to be able to embed TrueType - // data. - createTableEntry(otf, offsets, "CFF ", CFF); - - /** OS/2 */ - OS2 = stringToArray( - "\x00\x03" + // version - "\x02\x24" + // xAvgCharWidth - "\x01\xF4" + // usWeightClass - "\x00\x05" + // usWidthClass - "\x00\x00" + // fstype - "\x02\x8A" + // ySubscriptXSize - "\x02\xBB" + // ySubscriptYSize - "\x00\x00" + // ySubscriptXOffset - "\x00\x8C" + // ySubscriptYOffset - "\x02\x8A" + // ySuperScriptXSize - "\x02\xBB" + // ySuperScriptYSize - "\x00\x00" + // ySuperScriptXOffset - "\x01\xDF" + // ySuperScriptYOffset - "\x00\x31" + // yStrikeOutSize - "\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) - "\x2A\x32\x31\x2A" + // achVendID - "\x00\x20" + // fsSelection - "\x00\x2D" + // usFirstCharIndex - "\x00\x7A" + // usLastCharIndex - "\x00\x03" + // sTypoAscender - "\x00\x20" + // sTypeDescender - "\x00\x38" + // sTypoLineGap - "\x00\x5A" + // usWinAscent - "\x02\xB4" + // usWinDescent - "\x00\xCE\x00\x00" + // ulCodePageRange1 (Bits 0-31) - "\x00\x01\x00\x00" + // ulCodePageRange2 (Bits 32-63) - "\x00\x00" + // sxHeight - "\x00\x00" + // sCapHeight - "\x00\x01" + // usDefaultChar - "\x00\xCD" + // usBreakChar - "\x00\x02" // usMaxContext - ); - createTableEntry(otf, offsets, "OS/2", OS2); - - //XXX Getting charstrings here seems wrong since this is another CFF glue - var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs); - - /** CMAP */ - cmap = createCMAPTable(charstrings); - createTableEntry(otf, offsets, "cmap", cmap); - - /** HEAD */ - head = stringToArray( - "\x00\x01\x00\x00" + // Version number - "\x00\x00\x50\x00" + // fontRevision - "\x00\x00\x00\x00" + // checksumAdjustement - "\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" + // xMin - "\x00\x00" + // yMin - "\x00\x00" + // xMax - "\x00\x00" + // yMax - "\x00\x00" + // macStyle - "\x00\x00" + // lowestRecPPEM - "\x00\x00" + // fontDirectionHint - "\x00\x00" + // indexToLocFormat - "\x00\x00" // glyphDataFormat - ); - createTableEntry(otf, offsets, "head", head); - - /** HHEA */ - hhea = stringToArray( - "\x00\x01\x00\x00" + // Version number - "\x00\x00" + // Typographic Ascent - "\x00\x00" + // Typographic Descent - "\x00\x00" + // Line Gap - "\xFF\xFF" + // advanceWidthMax - "\x00\x00" + // minLeftSidebearing - "\x00\x00" + // minRightSidebearing - "\x00\x00" + // xMaxExtent - "\x00\x00" + // caretSlopeRise - "\x00\x00" + // caretSlopeRun - "\x00\x00" + // caretOffset - "\x00\x00" + // -reserved- - "\x00\x00" + // -reserved- - "\x00\x00" + // -reserved- - "\x00\x00" + // -reserved- - "\x00\x00" + // metricDataFormat - string16(charstrings.length) - ); - createTableEntry(otf, offsets, "hhea", hhea); - - /** HMTX */ - hmtx = "\x01\xF4\x00\x00"; - for (var i = 0; i < charstrings.length; i++) { - var charstring = charstrings[i].charstring; - var width = charstring[1]; - var lsb = charstring[0]; - hmtx += string16(width) + string16(lsb); - } - hmtx = stringToArray(hmtx); - createTableEntry(otf, offsets, "hmtx", hmtx); - - /** MAXP */ - maxp = "\x00\x00\x50\x00" + // Version number - string16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) - maxp = stringToArray(maxp); - createTableEntry(otf, offsets, "maxp", maxp); - - /** NAME */ - name = stringToArray(createNameTable(aName)); - createTableEntry(otf, offsets, "name", name); - - /** POST */ - // TODO: get those informations from the FontInfo structure - post = "\x00\x03\x00\x00" + // Version number - "\x00\x00\x01\x00" + // 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 - post = stringToArray(post); - createTableEntry(otf, offsets, "post", post); - - // Once all the table entries header are written, dump the data! - var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post]; - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - otf.set(table, offsets.currentOffset); - offsets.currentOffset += table.length; - } - - var fontData = []; - for (var i = 0; i < offsets.currentOffset; i++) - fontData.push(otf[i]); - return fontData; } }; @@ -635,31 +797,31 @@ var Font = (function () { */ var FontsUtils = { _bytesArray: new Uint8Array(4), - integerToBytes: function fu_integerToBytes(aValue, aBytesCount) { + integerToBytes: function fu_integerToBytes(value, bytesCount) { var bytes = this._bytesArray; - if (aBytesCount == 1) { - bytes.set([aValue]); + if (bytesCount == 1) { + bytes.set([value]); return bytes[0]; - } else if (aBytesCount == 2) { - bytes.set([aValue >> 8, aValue]); + } else if (bytesCount == 2) { + bytes.set([value >> 8, value]); return [bytes[0], bytes[1]]; - } else if (aBytesCount == 4) { - bytes.set([aValue >> 24, aValue >> 16, aValue >> 8, aValue]); + } else if (bytesCount == 4) { + bytes.set([value >> 24, value >> 16, value >> 8, value]); return [bytes[0], bytes[1], bytes[2], bytes[3]]; } }, - bytesToInteger: function fu_bytesToInteger(aBytesArray) { + bytesToInteger: function fu_bytesToInteger(bytesArray) { var value = 0; - for (var i = 0; i < aBytesArray.length; i++) - value = (value << 8) + aBytesArray[i]; + for (var i = 0; i < bytesArray.length; i++) + value = (value << 8) + bytesArray[i]; return value; }, - getMaxPower2: function fu_getMaxPower2(aNumber) { + getMaxPower2: function fu_getMaxPower2(number) { var maxPower = 0; - var value = aNumber; + var value = number; while (value >= 2) { value /= 2; maxPower++; @@ -673,391 +835,6 @@ var FontsUtils = { }; -/** - * The TrueType class verify that the ttf embedded inside the PDF is correct in - * the point of view of the OTS sanitizer and rewrite it on the fly otherwise. - * - * At the moment the rewiting only support rewriting missing 'OS/2' table. - * This class is unused at the moment since the 'cmap' table of the test - * document is not missing but use and old version of the 'cmap' table that - * is deprecated and not supported by the sanitizer... - * - */ -var TrueType = function(aName, aFile, aProperties) { - var header = this._readOpenTypeHeader(aFile); - var numTables = header.numTables; - - // Check that required tables are present - var requiredTables = [ - "OS/2", - "cmap", - "head", - "hhea", - "hmtx", - "maxp", - "name", - "post" - ]; - - var originalCMAP = null; - - var tables = []; - for (var i = 0; i < numTables; i++) { - var table = this._readTableEntry(aFile); - var index = requiredTables.indexOf(table.tag); - if (index != -1) { - if (table.tag == "cmap") - originalCMAP = table; - - tables.push(table); - } - } - - // If any tables are still in the array this means some required tables are - // missing, which means that we need to rebuild the font in order to pass - // the sanitizer. - if (requiredTables.length && requiredTables[0] == "OS/2") { - var OS2 = [ - 0x00, 0x03, // version - 0x02, 0x24, // xAvgCharWidth - 0x01, 0xF4, // usWeightClass - 0x00, 0x05, // usWidthClass - 0x00, 0x00, // fstype - 0x02, 0x8A, // ySubscriptXSize - 0x02, 0xBB, // ySubscriptYSize - 0x00, 0x00, // ySubscriptXOffset - 0x00, 0x8C, // ySubscriptYOffset - 0x02, 0x8A, // ySuperScriptXSize - 0x02, 0xBB, // ySuperScriptYSize - 0x00, 0x00, // ySuperScriptXOffset - 0x01, 0xDF, // ySuperScriptYOffset - 0x00, 0x31, // yStrikeOutSize - 0x01, 0x02, // yStrikeOutPosition - 0x00, 0x00, // sFamilyClass - 0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95) - 0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127) - 0x2A, 0x32, 0x31, 0x2A, // achVendID - 0x00, 0x20, // fsSelection - 0x00, 0x2D, // usFirstCharIndex - 0x00, 0x7A, // usLastCharIndex - 0x00, 0x03, // sTypoAscender - 0x00, 0x20, // sTypeDescender - 0x00, 0x38, // sTypoLineGap - 0x00, 0x5A, // usWinAscent - 0x02, 0xB4, // usWinDescent - 0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31) - 0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63) - 0x00, 0x00, // sxHeight - 0x00, 0x00, // sCapHeight - 0x00, 0x01, // usDefaultChar - 0x00, 0xCD, // usBreakChar - 0x00, 0x02 // usMaxContext - ]; - - // If the font is missing a OS/2 table it's could be an old mac font - // without a 3-1-4 Unicode BMP table, so let's rewrite it. - var charset = aProperties.charset; - var glyphs = []; - for (var i = 0; i < charset.length; i++) { - glyphs.push({ - unicode: GlyphsUnicode[charset[i]] - }); - } - - - var offsetDelta = 0; - - // Replace the old CMAP table - var rewrittedCMAP = this._createCMAPTable(glyphs); - offsetDelta = rewrittedCMAP.length - originalCMAP.data.length; - originalCMAP.data = rewrittedCMAP; - - // Rewrite the 'post' table if needed - var postTable = null; - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - if (table.tag == "post") { - postTable = table; - break; - } - } - - if (!postTable) { - var post = [ - 0x00, 0x03, 0x00, 0x00, // Version number - 0x00, 0x00, 0x01, 0x00, // italicAngle - 0x00, 0x00, // underlinePosition - 0x00, 0x00, // underlineThickness - 0x00, 0x00, 0x00, 0x00, // isFixedPitch - 0x00, 0x00, 0x00, 0x00, // minMemType42 - 0x00, 0x00, 0x00, 0x00, // maxMemType42 - 0x00, 0x00, 0x00, 0x00, // minMemType1 - 0x00, 0x00, 0x00, 0x00 // maxMemType1 - ]; - - offsetDelta += post.length; - tables.unshift({ - tag: "post", - data: post - }); - } - - // Create a new file to hold the new version of our truetype with a new - // header and new offsets - var stream = aFile.stream || aFile; - var ttf = new Uint8Array(stream.length + 1024); - - // The new numbers of tables will be the last one plus the num of missing - // tables - var numTables = header.numTables + 1; - - // The offsets object holds at the same time a representation of where - // to write the table entry information about a table and another offset - // representing the offset where to draw the actual data of a particular - // table - var offsets = { - currentOffset: 0, - virtualOffset: numTables * (4 * 4) - }; - - // Write the sfnt header with one more table - this._createOpenTypeHeader(ttf, offsets, numTables); - - // Insert the missing table - tables.unshift({ - tag: "OS/2", - data: OS2 - }); - - // Tables needs to be written by ascendant alphabetic order - tables.sort(function tables_sort(a, b) { - return a.tag > b.tag; - }); - - // rewrite the tables but tweak offsets - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - var data = []; - - var tableData = table.data; - for (var j = 0; j < tableData.length; j++) - data.push(tableData[j]); - this._createTableEntry(ttf, offsets, table.tag, data); - } - - // Add the table datas - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - var tableData = table.data; - ttf.set(tableData, offsets.currentOffset); - offsets.currentOffset += tableData.length; - - // 4-byte aligned data - while (offsets.currentOffset & 3) - offsets.currentOffset++; - } - - var fontData = []; - for (var i = 0; i < offsets.currentOffset; i++) - fontData.push(ttf[i]); - - this.data = fontData; - return; - } else if (requiredTables.length) { - error("Table " + requiredTables[0] + " is missing from the TruType font"); - } else { - this.data = aFile.getBytes(); - } -}; - -TrueType.prototype = { - _createOpenTypeHeader: function tt_createOpenTypeHeader(aFile, aOffsets, aNumTables) { - // sfnt version (4 bytes) - // XXX if we want to merge this function and the one from the Font class - // XXX this need to be adapted - var version = [0x00, 0x01, 0x00, 0X00]; - - // numTables (2 bytes) - var numTables = aNumTables; - - // searchRange (2 bytes) - var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); - var searchRange = tablesMaxPower2 * 16; - - // entrySelector (2 bytes) - var entrySelector = Math.log(tablesMaxPower2) / Math.log(2); - - // rangeShift (2 bytes) - var rangeShift = numTables * 16 - searchRange; - - var header = [].concat(version, - FontsUtils.integerToBytes(numTables, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(entrySelector, 2), - FontsUtils.integerToBytes(rangeShift, 2)); - aFile.set(header, aOffsets.currentOffset); - aOffsets.currentOffset += header.length; - aOffsets.virtualOffset += header.length; - }, - - _createCMAPTable: function font_createCMAPTable(aGlyphs) { - var characters = Uint16Array(65535); - for (var i = 0; i < aGlyphs.length; i++) - characters[aGlyphs[i].unicode] = i + 1; - - // Separate the glyphs into continuous range of codes, aka segment. - var ranges = []; - var range = []; - var count = characters.length; - for (var i = 0; i < count; i++) { - if (characters[i]) { - range.push(i); - } else if (range.length) { - ranges.push(range.slice()); - range = []; - } - } - - // The size in bytes of the header is equal to the size of the - // different fields * length of a short + (size of the 4 parallels arrays - // describing segments * length of a short). - var headerSize = (12 * 2 + (ranges.length * 4 * 2)); - - var segCount = ranges.length + 1; - var segCount2 = segCount * 2; - var searchRange = FontsUtils.getMaxPower2(segCount) * 2; - var searchEntry = Math.log(segCount) / Math.log(2); - var rangeShift = 2 * segCount - searchRange; - var cmap = [].concat( - [ - 0x00, 0x00, // version - 0x00, 0x01, // numTables - 0x00, 0x03, // platformID - 0x00, 0x01, // encodingID - 0x00, 0x00, 0x00, 0x0C, // start of the table record - 0x00, 0x04 // format - ], - FontsUtils.integerToBytes(headerSize, 2), // length - [0x00, 0x00], // language - FontsUtils.integerToBytes(segCount2, 2), - FontsUtils.integerToBytes(searchRange, 2), - FontsUtils.integerToBytes(searchEntry, 2), - FontsUtils.integerToBytes(rangeShift, 2) - ); - - // Fill up the 4 parallel arrays describing the segments. - var startCount = []; - var endCount = []; - var idDeltas = []; - var idRangeOffsets = []; - var glyphsIdsArray = []; - var bias = 0; - for (var i = 0; i < segCount - 1; i++) { - var range = ranges[i]; - var start = FontsUtils.integerToBytes(range[0], 2); - var end = FontsUtils.integerToBytes(range[range.length - 1], 2); - - var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2); - bias += range.length; - - // deltas are signed shorts - delta[0] ^= 0xFF; - delta[1] ^= 0xFF; - delta[1] += 1; - - startCount.push(start[0], start[1]); - endCount.push(end[0], end[1]); - idDeltas.push(delta[0], delta[1]); - idRangeOffsets.push(0x00, 0x00); - - for (var j = 0; j < range.length; j++) - glyphsIdsArray.push(range[j]); - } - startCount.push(0xFF, 0xFF); - endCount.push(0xFF, 0xFF); - idDeltas.push(0x00, 0x01); - idRangeOffsets.push(0x00, 0x00); - - return cmap.concat(endCount, [0x00, 0x00], startCount, - idDeltas, idRangeOffsets, glyphsIdsArray); - }, - - _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) { - // tag - var tag = [ - aTag.charCodeAt(0), - aTag.charCodeAt(1), - aTag.charCodeAt(2), - aTag.charCodeAt(3) - ]; - - // Per spec tables must be 4-bytes align so add some 0x00 if needed - while (aData.length & 3) - aData.push(0x00); - - while (aOffsets.virtualOffset & 3) - aOffsets.virtualOffset++; - - // offset - var offset = aOffsets.virtualOffset; - - // length - var length = aData.length; - - // checksum - var checksum = FontsUtils.bytesToInteger(tag) + offset + length; - - var tableEntry = [].concat(tag, - FontsUtils.integerToBytes(checksum, 4), - FontsUtils.integerToBytes(offset, 4), - FontsUtils.integerToBytes(length, 4)); - aFile.set(tableEntry, aOffsets.currentOffset); - aOffsets.currentOffset += tableEntry.length; - aOffsets.virtualOffset += aData.length; - }, - - _readOpenTypeHeader: function tt_readOpenTypeHeader(aFile) { - return { - version: aFile.getBytes(4), - numTables: FontsUtils.bytesToInteger(aFile.getBytes(2)), - searchRange: FontsUtils.bytesToInteger(aFile.getBytes(2)), - entrySelector: FontsUtils.bytesToInteger(aFile.getBytes(2)), - rangeShift: FontsUtils.bytesToInteger(aFile.getBytes(2)) - } - }, - - _readTableEntry: function tt_readTableEntry(aFile) { - // tag - var tag = aFile.getBytes(4); - tag = String.fromCharCode(tag[0]) + - String.fromCharCode(tag[1]) + - String.fromCharCode(tag[2]) + - String.fromCharCode(tag[3]); - - var checksum = FontsUtils.bytesToInteger(aFile.getBytes(4)); - var offset = FontsUtils.bytesToInteger(aFile.getBytes(4)); - var length = FontsUtils.bytesToInteger(aFile.getBytes(4)); - - // Read the table associated data - var currentPosition = aFile.pos; - aFile.pos = aFile.start + offset; - var data = aFile.getBytes(length); - aFile.pos = currentPosition; - - return { - tag: tag, - checksum: checksum, - length: offset, - offset: length, - data: data - } - } -}; - - /** * Type1Parser encapsulate the needed code for parsing a Type1 font * program. @@ -1072,18 +849,18 @@ var Type1Parser = function() { var kEexecEncryptionKey = 55665; var kCharStringsEncryptionKey = 4330; - function decrypt(aStream, aKey, aDiscardNumber) { - var r = aKey, c1 = 52845, c2 = 22719; + function decrypt(stream, key, discardNumber) { + var r = key, c1 = 52845, c2 = 22719; var decryptedString = []; var value = ""; - var count = aStream.length; + var count = stream.length; for (var i = 0; i < count; i++) { - value = aStream[i]; + value = stream[i]; decryptedString[i] = value ^ (r >> 8); r = ((value + r) * c1 + c2) & ((1 << 16) - 1); } - return decryptedString.slice(aDiscardNumber); + return decryptedString.slice(discardNumber); }; /* @@ -1193,18 +970,18 @@ var Type1Parser = function() { "31": "hvcurveto" }; - function decodeCharString(aArray) { + function decodeCharString(array) { var charString = []; var value = ""; - var count = aArray.length; + var count = array.length; for (var i = 0; i < count; i++) { - value = parseInt(aArray[i]); + value = parseInt(array[i]); if (value < 32) { var command = null; if (value == 12) { - var escape = aArray[++i]; + var escape = array[++i]; command = charStringDictionary["12"][escape]; } else { command = charStringDictionary[value]; @@ -1224,14 +1001,14 @@ var Type1Parser = function() { } else if (value <= 246) { value = parseInt(value) - 139; } else if (value <= 250) { - value = ((value - 247) * 256) + parseInt(aArray[++i]) + 108; + value = ((value - 247) * 256) + parseInt(array[++i]) + 108; } else if (value <= 254) { - value = -((value - 251) * 256) - parseInt(aArray[++i]) - 108; + value = -((value - 251) * 256) - parseInt(array[++i]) - 108; } else { - var byte = aArray[++i]; + var byte = array[++i]; var high = (byte >> 1); - value = (byte - high) << 24 | aArray[++i] << 16 | - aArray[++i] << 8 | aArray[++i]; + value = (byte - high) << 24 | array[++i] << 16 | + array[++i] << 8 | array[++i]; } charString.push(value); @@ -1244,8 +1021,8 @@ var Type1Parser = function() { * Returns an object containing a Subrs array and a CharStrings array * extracted from and eexec encrypted block of data */ - this.extractFontProgram = function t1_extractFontProgram(aStream) { - var eexecString = decrypt(aStream, kEexecEncryptionKey, 4); + this.extractFontProgram = function t1_extractFontProgram(stream) { + var eexecString = decrypt(stream, kEexecEncryptionKey, 4); var subrs = [], glyphs = []; var inGlyphs = false; var inSubrs = false; @@ -1369,26 +1146,26 @@ const CFFStrings = [ "001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold" ]; -var CFF = function(aName, aFile, aProperties) { +var CFF = function(name, file, properties) { // Get the data block containing glyphs and subrs informations - var length1 = aFile.dict.get("Length1"); - var length2 = aFile.dict.get("Length2"); - aFile.skip(length1); - var eexecBlock = aFile.getBytes(length2); + var length1 = file.dict.get("Length1"); + var length2 = file.dict.get("Length2"); + file.skip(length1); + var eexecBlock = file.getBytes(length2); // Decrypt the data blocks and retrieve the informations from it var parser = new Type1Parser(); var fontInfo = parser.extractFontProgram(eexecBlock); - aProperties.subrs = fontInfo.subrs; - aProperties.glyphs = fontInfo.charstrings; - this.data = this.wrap(aName, aProperties); + properties.subrs = fontInfo.subrs; + properties.glyphs = fontInfo.charstrings; + this.data = this.wrap(name, properties); }; CFF.prototype = { - createCFFIndexHeader: function(aObjects, aIsByte) { + createCFFIndexHeader: function(objects, isByte) { // First 2 bytes contains the number of objects contained into this index - var count = aObjects.length; + var count = objects.length; // If there is no object, just create an array saying that with another // offset byte. @@ -1412,33 +1189,33 @@ CFF.prototype = { for (var j = 0; j < bytes.length; j++) data.push(bytes[j]); - if (aObjects[i]) - relativeOffset += aObjects[i].length; + if (objects[i]) + relativeOffset += objects[i].length; } for (var i =0; i < count; i++) { - for (var j = 0; j < aObjects[i].length; j++) - data.push(aIsByte ? aObjects[i][j] : aObjects[i].charCodeAt(j)); + for (var j = 0; j < objects[i].length; j++) + data.push(isByte ? objects[i][j] : objects[i].charCodeAt(j)); } return data; }, - encodeNumber: function(aValue) { + encodeNumber: function(value) { var x = 0; - if (aValue >= -32768 && aValue <= 32767) { - return [ 28, aValue >> 8, aValue & 0xFF ]; - } else if (aValue >= (-2147483647-1) && aValue <= 2147483647) { - return [ 0xFF, aValue >> 24, Value >> 16, aValue >> 8, aValue & 0xFF ]; + if (value >= -32768 && value <= 32767) { + return [ 28, value >> 8, value & 0xFF ]; + } else if (value >= (-2147483647-1) && value <= 2147483647) { + return [ 0xFF, value >> 24, Value >> 16, value >> 8, value & 0xFF ]; } else { - error("Value: " + aValue + " is not allowed"); + error("Value: " + value + " is not allowed"); } }, - getOrderedCharStrings: function(aGlyphs) { + getOrderedCharStrings: function(glyphs) { var charstrings = []; - for (var i = 0; i < aGlyphs.length; i++) { - var glyph = aGlyphs[i].glyph; + for (var i = 0; i < glyphs.length; i++) { + var glyph = glyphs[i].glyph; var unicode = GlyphsUnicode[glyph]; if (!unicode) { if (glyph != ".notdef") @@ -1447,7 +1224,7 @@ CFF.prototype = { charstrings.push({ glyph: glyph, unicode: unicode, - charstring: aGlyphs[i].data.slice() + charstring: glyphs[i].data.slice() }); } }; @@ -1480,100 +1257,100 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function flattenCharstring(aGlyph, aCharstring, aSubrs) { + flattenCharstring: function flattenCharstring(glyph, charstring, subrs) { var i = 0; while (true) { - var obj = aCharstring[i]; + var obj = charstring[i]; if (obj == null) return []; if (obj.charAt) { switch (obj) { case "callsubr": - var subr = aSubrs[aCharstring[i - 1]].slice(); + var subr = subrs[charstring[i - 1]].slice(); if (subr.length > 1) { - subr = this.flattenCharstring(aGlyph, subr, aSubrs); + subr = this.flattenCharstring(glyph, subr, subrs); subr.pop(); - aCharstring.splice(i - 1, 2, subr); + charstring.splice(i - 1, 2, subr); } else { - aCharstring.splice(i - 1, 2); + charstring.splice(i - 1, 2); } i -= 1; break; case "callothersubr": - var index = aCharstring[i - 1]; - var count = aCharstring[i - 2]; - var data = aCharstring[i - 3]; + var index = charstring[i - 1]; + var count = charstring[i - 2]; + var data = charstring[i - 3]; // XXX The callothersubr needs to support at least the 3 defaults // otherSubrs of the spec if (index != 3) - error("callothersubr for index: " + index + " (" + aCharstring + ")"); + error("callothersubr for index: " + index + " (" + charstring + ")"); if (!data) { - aCharstring.splice(i - 2, 4, "pop", 3); + charstring.splice(i - 2, 4, "pop", 3); i -= 3; } else { // 5 to remove the arguments, the callothersubr call and the pop command - aCharstring.splice(i - 3, 5, 3); + charstring.splice(i - 3, 5, 3); i -= 3; } break; case "div": - var num2 = aCharstring[i - 1]; - var num1 = aCharstring[i - 2]; - aCharstring.splice(i - 2, 3, num1 / num2); + var num2 = charstring[i - 1]; + var num1 = charstring[i - 2]; + charstring.splice(i - 2, 3, num1 / num2); i -= 2; break; case "pop": if (i) - aCharstring.splice(i - 2, 2); + charstring.splice(i - 2, 2); else - aCharstring.splice(i - 1, 1); + charstring.splice(i - 1, 1); i -= 1; break; case "hsbw": - var charWidthVector = aCharstring[i - 1]; - var leftSidebearing = aCharstring[i - 2]; + var charWidthVector = charstring[i - 1]; + var leftSidebearing = charstring[i - 2]; if (leftSidebearing) - aCharstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto"); + charstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto"); else - aCharstring.splice(i - 2, 3, charWidthVector); + charstring.splice(i - 2, 3, charWidthVector); break; case "endchar": case "return": // CharString is ready to be re-encode to commands number at this point - for (var j = 0; j < aCharstring.length; j++) { - var command = aCharstring[j]; + for (var j = 0; j < charstring.length; j++) { + var command = charstring[j]; if (parseFloat(command) == command) { - aCharstring.splice(j, 1, 28, command >> 8, command); + charstring.splice(j, 1, 28, command >> 8, command); j+= 2; } else if (command.charAt) { var command = this.commandsMap[command]; if (IsArray(command)) { - aCharstring.splice(j - 1, 1, command[0], command[1]); + charstring.splice(j - 1, 1, command[0], command[1]); j += 1; } else { - aCharstring[j] = command; + charstring[j] = command; } } else { - aCharstring.splice(j, 1); + charstring.splice(j, 1); // command has already been translated, just add them to the // charstring directly for (var k = 0; k < command.length; k++) - aCharstring.splice(j + k, 0, command[k]); + charstring.splice(j + k, 0, command[k]); j+= command.length - 1; } } - return aCharstring; + return charstring; default: break; @@ -1581,11 +1358,11 @@ CFF.prototype = { } i++; } - error("failing with i = " + i + " in charstring:" + aCharstring + "(" + aCharstring.length + ")"); + error("failing with i = " + i + " in charstring:" + charstring + "(" + charstring.length + ")"); }, - wrap: function wrap(aName, aProperties) { - var charstrings = this.getOrderedCharStrings(aProperties.glyphs); + wrap: function wrap(name, properties) { + var charstrings = this.getOrderedCharStrings(properties.glyphs); // Starts the conversion of the Type1 charstrings to Type2 var charstringsCount = 0; @@ -1595,7 +1372,7 @@ CFF.prototype = { var charstring = charstrings[i].charstring.slice(); var glyph = charstrings[i].glyph; - var flattened = this.flattenCharstring(glyph, charstring, aProperties.subrs); + var flattened = this.flattenCharstring(glyph, charstring, properties.subrs); glyphs.push(flattened); charstringsCount++; charstringsDataLength += flattened.length; @@ -1611,7 +1388,7 @@ CFF.prototype = { cff.set(header); // Names Index - var nameIndex = this.createCFFIndexHeader([aName]); + var nameIndex = this.createCFFIndexHeader([name]); cff.set(nameIndex, currentOffset); currentOffset += nameIndex.length; @@ -1655,7 +1432,7 @@ CFF.prototype = { 248, 31, 4 // Weight ]; - var fontBBox = aProperties.bbox; + var fontBBox = properties.bbox; for (var i = 0; i < fontBBox.length; i++) topDictIndex = topDictIndex.concat(this.encodeNumber(fontBBox[i])); topDictIndex.push(5) // FontBBox; diff --git a/pdf.js b/pdf.js index 5c49f14dd..4db4ef06f 100644 --- a/pdf.js +++ b/pdf.js @@ -80,6 +80,7 @@ var Stream = (function() { getBytes: function(length) { var bytes = this.bytes; var pos = this.pos; + var end = pos + length; var strEnd = this.end; if (!end || end > strEnd) @@ -2198,7 +2199,7 @@ var CanvasGraphics = (function() { var tokens = []; var token = ""; - var buffer = cmapObj.ensureBuffer(); + var buffer = cmapObj.ensureBuffer ? cmapObj.ensureBuffer() : cmapObj; var cmap = cmapObj.getBytes(buffer.byteLength); for (var i =0; i < cmap.length; i++) { var byte = cmap[i]; From bae46a9187ed9e0c3e1b73c82631456da0ccd81a Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 20 Jun 2011 22:44:08 -0700 Subject: [PATCH 145/439] removed redundant getChar --- pdf.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pdf.js b/pdf.js index be324d54f..fe52b5c4e 100644 --- a/pdf.js +++ b/pdf.js @@ -540,10 +540,6 @@ var JpegStream = (function() { } constructor.prototype = { - // Needed to pass IsStream test - getChar: function() { - }, - getImage: function() { return this.domImage; }, From 8eb589c9dc174b26cb2d1fa23022e4695d916148 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 21 Jun 2011 03:04:33 -0400 Subject: [PATCH 146/439] style fixes and fix bug in numComps calculation (missing break) --- pdf.js | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/pdf.js b/pdf.js index fe52b5c4e..57e53061f 100644 --- a/pdf.js +++ b/pdf.js @@ -553,8 +553,7 @@ var JpegStream = (function() { var PredictorStream = (function() { function constructor(stream, params) { - var predictor = params.get("Predictor") || 1; - this.predictor = predictor; + var predictor = this.predictor = params.get("Predictor") || 1; if (predictor <= 1) return stream; // no prediction @@ -571,18 +570,13 @@ var PredictorStream = (function() { if (params.has("EarlyChange")) { error("EarlyChange predictor parameter is not supported"); } - var colors = params.get("Colors") || 1; - this.colors = colors; - var bits = params.get("BitsPerComponent") || 8; - this.bits = bits; - var columns = params.get("Columns") || 1; - this.columns = columns; + var colors = this.colors = params.get("Colors") || 1; + var bits = this.bits = params.get("BitsPerComponent") || 8; + var columns = this.columns = params.get("Columns") || 1; - var pixBytes = (colors * bits + 7) >> 3; - this.pixBytes = pixBytes; + var pixBytes = this.pixBytes = (colors * bits + 7) >> 3; // add an extra pixByte to represent the pixel left of column 0 - var rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; - this.rowBytes = rowBytes; + var rowBytes = this.rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; this.currentRow = new Uint8Array(rowBytes); this.bufferLength = rowBytes; @@ -626,8 +620,8 @@ var PredictorStream = (function() { inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF); inbits += 8; } - compArray[kk] = (compArray[kk] + (inbuf >> - (inbits - bits))) & bitMask; + compArray[kk] = (compArray[kk] + + (inbuf >> (inbits - bits))) & bitMask; inbits -= bits; outbuf = (outbuf << bits) | compArray[kk]; outbits += bits; @@ -639,7 +633,7 @@ var PredictorStream = (function() { } if (outbits > 0) { currentRow[k++] = (outbuf << (8 - outbits)) + - (inbuf & ((1 << (8 - outbits)) - 1)) + (inbuf & ((1 << (8 - outbits)) - 1)) } } this.pos = pixBytes; @@ -707,18 +701,16 @@ var PredictorStream = (function() { this.pos = pixBytes; }, getByte : function() { - if (this.pos >= this.bufferLength) { + if (this.pos >= this.bufferLength) this.readRow(); - } return this.currentRow[this.pos++]; }, getBytes : function(n) { var i, bytes; bytes = new Uint8Array(n); for (i = 0; i < n; ++i) { - if (this.pos >= this.bufferLength) { + if (this.pos >= this.bufferLength) this.readRow(); - } bytes[i] = this.currentRow[this.pos++]; } return bytes; @@ -727,9 +719,8 @@ var PredictorStream = (function() { return String.formCharCode(this.getByte()); }, lookChar : function() { - if (this.pos >= this.bufferLength) { + if (this.pos >= this.bufferLength) this.readRow(); - } return String.formCharCode(this.currentRow[this.pos]); }, skip : function(n) { @@ -3288,6 +3279,7 @@ var ColorSpace = (function() { case "DeviceGray": case "G": this.numComps = 1; + break; case "DeviceRGB": this.numComps = 3; break; From ec278e57242589119534d2464c19b7c74f20c0f0 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 21 Jun 2011 03:42:01 -0400 Subject: [PATCH 147/439] don't die when translating fonts without a charset --- pdf.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 57e53061f..fda5b512e 100644 --- a/pdf.js +++ b/pdf.js @@ -2267,10 +2267,10 @@ var CanvasGraphics = (function() { // Get the font charset if any var charset = descriptor.get("CharSet"); - if (charset) + if (charset) { assertWellFormed(IsString(charset), "invalid charset"); - - charset = charset.split("/"); + charset = charset.split("/"); + } } else if (IsName(encoding)) { var encoding = Encodings[encoding.name]; if (!encoding) From 505bb3ed103721bb33588f3a1da8d3531ff6394a Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 21 Jun 2011 10:49:02 -0700 Subject: [PATCH 148/439] minor fix to render page, add F command, added inhertable dictionary entries --- pdf.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index fda5b512e..21a131bfd 100644 --- a/pdf.js +++ b/pdf.js @@ -784,6 +784,16 @@ var Dict = (function() { get2: function(key1, key2) { return this.get(key1) || this.get(key2); }, + getOrInherit: function(key, xref) { + var obj = this.map[key]; + var dict = this; + while (!obj && dict) { + dict = xref.fetchIfRef(dict.get("Parent")); + if (dict) + obj = dict.get(key); + } + return obj; + }, has: function(key) { return key in this.map; }, @@ -1701,10 +1711,11 @@ var Page = (function() { return shadow(this, "content", this.pageDict.get("Contents")); }, get resources() { - return shadow(this, "resources", this.pageDict.get("Resources")); + return shadow(this, "resources", + this.pageDict.getOrInherit("Resources", this.xref)); }, get mediaBox() { - var obj = this.pageDict.get("MediaBox"); + var obj = this.pageDict.getOrInherit("MediaBox", this.xref); return shadow(this, "mediaBox", ((IsArray(obj) && obj.length == 4) ? obj : null)); @@ -2154,6 +2165,7 @@ var CanvasGraphics = (function() { S: "stroke", s: "closeStroke", f: "fill", + F: "fill", "f*": "eoFill", B: "fillStroke", "B*": "eoFillStroke", From ca75b31e84531e3068a666dcb5ea86bd0e1b99f0 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 21 Jun 2011 14:42:41 -0400 Subject: [PATCH 149/439] indentation fix --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 21a131bfd..c12cb2b08 100644 --- a/pdf.js +++ b/pdf.js @@ -1712,7 +1712,7 @@ var Page = (function() { }, get resources() { return shadow(this, "resources", - this.pageDict.getOrInherit("Resources", this.xref)); + this.pageDict.getOrInherit("Resources", this.xref)); }, get mediaBox() { var obj = this.pageDict.getOrInherit("MediaBox", this.xref); From 51b9659f5539ef3fa753d6f0fe7de2eea13e468a Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 21 Jun 2011 15:05:33 -0400 Subject: [PATCH 150/439] whitespace fixes and move inheriting of dict props into the page since it only happens there --- pdf.js | 128 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/pdf.js b/pdf.js index c12cb2b08..fff135816 100644 --- a/pdf.js +++ b/pdf.js @@ -554,12 +554,12 @@ var JpegStream = (function() { var PredictorStream = (function() { function constructor(stream, params) { var predictor = this.predictor = params.get("Predictor") || 1; - + if (predictor <= 1) return stream; // no prediction if (predictor !== 2 && (predictor < 10 || predictor > 15)) error("Unsupported predictor"); - + if (predictor === 2) this.readRow = this.readRowTiff; else @@ -573,7 +573,7 @@ var PredictorStream = (function() { var colors = this.colors = params.get("Colors") || 1; var bits = this.bits = params.get("BitsPerComponent") || 8; var columns = this.columns = params.get("Columns") || 1; - + var pixBytes = this.pixBytes = (colors * bits + 7) >> 3; // add an extra pixByte to represent the pixel left of column 0 var rowBytes = this.rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; @@ -784,16 +784,6 @@ var Dict = (function() { get2: function(key1, key2) { return this.get(key1) || this.get(key2); }, - getOrInherit: function(key, xref) { - var obj = this.map[key]; - var dict = this; - while (!obj && dict) { - dict = xref.fetchIfRef(dict.get("Parent")); - if (dict) - obj = dict.get(key); - } - return obj; - }, has: function(key) { return key in this.map; }, @@ -1116,7 +1106,7 @@ var Lexer = (function() { break; } } - + // start reading token switch (ch) { case '0': case '1': case '2': case '3': case '4': @@ -1290,7 +1280,7 @@ var Parser = (function() { } return str; } - + // simple object var obj = this.buf1; this.shift(); @@ -1303,7 +1293,7 @@ var Parser = (function() { // get stream start position lexer.skipToNextLine(); var pos = stream.pos; - + // get length var length = dict.get("Length"); var xref = this.xref; @@ -1373,7 +1363,7 @@ var Parser = (function() { return constructor; })(); - + var Linearization = (function() { function constructor(stream) { this.parser = new Parser(new Lexer(stream), false); @@ -1707,15 +1697,28 @@ var Page = (function() { } constructor.prototype = { + getPageProp: function(key) { + return this.pageDict.get(key); + }, + inheritPageProp: function(key) { + var dict = this.pageDict; + var obj = dict.get(key); + while (!obj) { + dict = this.xref.fetchIfRef(dict.get("Parent")); + if (!dict) + break; + obj = dict.get(key); + } + return obj; + }, get content() { - return shadow(this, "content", this.pageDict.get("Contents")); + return shadow(this, "content", this.getPageProp("Contents")); }, get resources() { - return shadow(this, "resources", - this.pageDict.getOrInherit("Resources", this.xref)); + return shadow(this, "resources", this.inheritPageProp("Resources")); }, get mediaBox() { - var obj = this.pageDict.getOrInherit("MediaBox", this.xref); + var obj = this.inheritPageProp("MediaBox"); return shadow(this, "mediaBox", ((IsArray(obj) && obj.length == 4) ? obj : null)); @@ -1804,7 +1807,7 @@ var Catalog = (function() { pageCache.push(new Page(this.xref, pageCache.length, obj)); } else { // must be a child page dictionary assertWellFormed(IsDict(obj), - "page dictionary kid reference points to wrong type of object"); + "page dictionary kid reference points to wrong type of object"); this.traverseKids(obj); } } @@ -2890,7 +2893,6 @@ var CanvasGraphics = (function() { shadingFill: function(entryRef) { var xref = this.xref; var res = this.res; - var shadingRes = xref.fetchIfRef(res.get("Shading")); if (!shadingRes) error("No shading resource found"); @@ -2915,12 +2917,14 @@ var CanvasGraphics = (function() { if (background) TODO("handle background colors"); - const types = [null, this.fillFunctionShading, - this.fillAxialShading, this.fillRadialShading]; - + const types = [null, + this.fillFunctionShading, + this.fillAxialShading, + this.fillRadialShading]; + var typeNum = shading.get("ShadingType"); var fillFn = types[typeNum]; - if (!fillFn) + if (!fillFn) error("Unknown type of shading"); fillFn.apply(this, [shading]); @@ -2931,7 +2935,7 @@ var CanvasGraphics = (function() { var coordsArr = sh.get("Coords"); var x0 = coordsArr[0], y0 = coordsArr[1], x1 = coordsArr[2], y1 = coordsArr[3]; - + var t0 = 0.0, t1 = 1.0; if (sh.has("Domain")) { var domainArr = sh.get("Domain"); @@ -2990,12 +2994,12 @@ var CanvasGraphics = (function() { return; xobj = this.xref.fetchIfRef(xobj); assertWellFormed(IsStream(xobj), "XObject should be a stream"); - + var oc = xobj.dict.get("OC"); if (oc) { TODO("oc for xobject"); } - + var opi = xobj.dict.get("OPI"); if (opi) { TODO("opi for xobject"); @@ -3097,15 +3101,14 @@ var CanvasGraphics = (function() { // actual image var csStream = dict.get2("ColorSpace", "CS"); csStream = xref.fetchIfRef(csStream); - if (IsName(csStream) && inline) + if (IsName(csStream) && inline) csStream = colorSpaces.get(csStream); - - var colorSpace = new ColorSpace(xref, csStream); + var colorSpace = new ColorSpace(xref, csStream); var decode = dict.get2("Decode", "D"); TODO("create color map"); - + var mask = image.dict.get("Mask"); mask = xref.fetchIfRef(mask); var smask = image.dict.get("SMask"); @@ -3130,7 +3133,7 @@ var CanvasGraphics = (function() { var maskBPC = maskDict.get2("BitsPerComponent", "BPC"); if (!maskBPC) error("Invalid image mask bpc"); - + var maskCsStream = maskDict.get2("ColorSpace", "CS"); maskCsStream = xref.fetchIfRef(maskCsStream); var maskColorSpace = new ColorSpace(xref, maskCsStream); @@ -3140,7 +3143,7 @@ var CanvasGraphics = (function() { var maskDecode = maskDict.get2("Decode", "D"); if (maskDecode) TODO("Handle mask decode"); - // handle matte object + // handle matte object } var tmpCanvas = document.createElement("canvas"); @@ -3149,21 +3152,21 @@ var CanvasGraphics = (function() { var tmpCtx = tmpCanvas.getContext("2d"); var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; - + if (bitsPerComponent != 8) - error("unhandled number of bits per component"); - + error("unhandled number of bits per component"); + if (smask) { if (maskColorSpace.numComps != 1) error("Incorrect number of components in smask"); - + var numComps = colorSpace.numComps; var imgArray = image.getBytes(numComps * w * h); var imgIdx = 0; var smArray = smask.getBytes(w * h); var smIdx = 0; - + var length = 4 * w * h; switch (numComps) { case 1: @@ -3190,7 +3193,7 @@ var CanvasGraphics = (function() { var numComps = colorSpace.numComps; var imgArray = image.getBytes(numComps * w * h); var imgIdx = 0; - + var length = 4 * w * h; switch (numComps) { case 1: @@ -3300,7 +3303,7 @@ var ColorSpace = (function() { } else if (IsArray(cs)) { var mode = cs[0].name; this.mode = mode; - + var stream = cs[1]; stream = xref.fetchIfRef(stream); @@ -3313,7 +3316,6 @@ var ColorSpace = (function() { break; case "ICCBased": var dict = stream.dict; - this.stream = stream; this.dict = dict; this.numComps = dict.get("N"); @@ -3325,7 +3327,7 @@ var ColorSpace = (function() { error("unrecognized color space object"); } }; - + constructor.prototype = { }; @@ -3338,13 +3340,15 @@ var PDFFunction = (function() { if (!dict) dict = fn; - const types = [this.constructSampled, null, - this.constructInterpolated, this.constructStiched, - this.constructPostScript]; - + const types = [this.constructSampled, + null, + this.constructInterpolated, + this.constructStiched, + this.constructPostScript]; + var typeNum = dict.get("FunctionType"); var typeFn = types[typeNum]; - if (!typeFn) + if (!typeFn) error("Unknown type of function"); typeFn.apply(this, [fn, dict]); @@ -3357,7 +3361,7 @@ var PDFFunction = (function() { if (!domain || !range) error("No domain or range"); - + var inputSize = domain.length / 2; var outputSize = range.length / 2; @@ -3371,7 +3375,7 @@ var PDFFunction = (function() { order = 1; if (order !== 1) error ("No support for cubic spline interpolation"); - + var encode = dict.get("Encode"); if (!encode) { encode = []; @@ -3400,15 +3404,14 @@ var PDFFunction = (function() { for (var i = 0; i < inputSize; i++) { var i2 = i * 2; - + // clip to the domain var v = clip(args[i], domain[i2], domain[i2 + 1]); // encode - v = encode[i2] + ((v - domain[i2]) * - (encode[i2 + 1] - encode[i2]) / - (domain[i2 + 1] - domain[i2])); - + v = encode[i2] + ((v - domain[i2]) * + (encode[i2 + 1] - encode[i2]) / + (domain[i2 + 1] - domain[i2])); // clip to the size args[i] = clip(v, 0, size[i] - 1); } @@ -3431,12 +3434,11 @@ var PDFFunction = (function() { var high = samples[ceil + i]; var v = low * scale + high * (1 - scale); } - + var i2 = i * 2; // decode - v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) / - ((1 << bps) - 1)); - + v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) / + ((1 << bps) - 1)); // clip to the domain output.push(clip(v, range[i2], range[i2 + 1])); } @@ -3471,10 +3473,10 @@ var PDFFunction = (function() { }, constructInterpolated: function() { error("unhandled type of function"); - }, + }, constructStiched: function() { error("unhandled type of function"); - }, + }, constructPostScript: function() { error("unhandled type of function"); } From 34357eac191fbe1ed3495e4c244221d53bb3fc08 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 21:11:59 +0200 Subject: [PATCH 151/439] Start displaying TrueType fonts --- fonts.js | 10 +++++----- pdf.js | 9 +++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index ad3d4fd35..80a9f4bc2 100644 --- a/fonts.js +++ b/fonts.js @@ -103,7 +103,7 @@ var Font = (function () { // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. - if (properties.ignore || properties.type == "TrueType" || kDisableFonts) { + if (properties.ignore || kDisableFonts) { Fonts[name] = { data: file, loading: false, @@ -368,11 +368,11 @@ var Font = (function () { var length = FontsUtils.bytesToInteger(file.getBytes(4)); // Read the table associated data - var currentPosition = file.pos; - file.pos = file.start + offset; - + var previousPosition = file.pos; + file.pos = file.start ? file.start : 0; + file.skip(offset); var data = file.getBytes(length); - file.pos = currentPosition; + file.pos = previousPosition; return { tag: tag, diff --git a/pdf.js b/pdf.js index 4db4ef06f..8268f1673 100644 --- a/pdf.js +++ b/pdf.js @@ -2199,8 +2199,13 @@ var CanvasGraphics = (function() { var tokens = []; var token = ""; - var buffer = cmapObj.ensureBuffer ? cmapObj.ensureBuffer() : cmapObj; - var cmap = cmapObj.getBytes(buffer.byteLength); + var length = cmapObj.length; + if (cmapObj instanceof FlateStream) { + cmapObj.readBlock(); + length = cmapObj.bufferLength; + } + + var cmap = cmapObj.getBytes(length); for (var i =0; i < cmap.length; i++) { var byte = cmap[i]; if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { From 11a1ebaada2de99c3cb9a4c17728c3f04bbb893e Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 21 Jun 2011 21:11:59 +0200 Subject: [PATCH 152/439] Start displaying TrueType fonts --- fonts.js | 10 +++++----- pdf.js | 9 +++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index ad3d4fd35..80a9f4bc2 100644 --- a/fonts.js +++ b/fonts.js @@ -103,7 +103,7 @@ var Font = (function () { // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. - if (properties.ignore || properties.type == "TrueType" || kDisableFonts) { + if (properties.ignore || kDisableFonts) { Fonts[name] = { data: file, loading: false, @@ -368,11 +368,11 @@ var Font = (function () { var length = FontsUtils.bytesToInteger(file.getBytes(4)); // Read the table associated data - var currentPosition = file.pos; - file.pos = file.start + offset; - + var previousPosition = file.pos; + file.pos = file.start ? file.start : 0; + file.skip(offset); var data = file.getBytes(length); - file.pos = currentPosition; + file.pos = previousPosition; return { tag: tag, diff --git a/pdf.js b/pdf.js index 4db4ef06f..8268f1673 100644 --- a/pdf.js +++ b/pdf.js @@ -2199,8 +2199,13 @@ var CanvasGraphics = (function() { var tokens = []; var token = ""; - var buffer = cmapObj.ensureBuffer ? cmapObj.ensureBuffer() : cmapObj; - var cmap = cmapObj.getBytes(buffer.byteLength); + var length = cmapObj.length; + if (cmapObj instanceof FlateStream) { + cmapObj.readBlock(); + length = cmapObj.bufferLength; + } + + var cmap = cmapObj.getBytes(length); for (var i =0; i < cmap.length; i++) { var byte = cmap[i]; if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { From 0073e3c6184aff0ade0fcf30d0a727a7a74d5c1a Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 21 Jun 2011 13:34:35 -0700 Subject: [PATCH 153/439] initial impl of ASCII85 Decoding --- pdf.js | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/pdf.js b/pdf.js index fff135816..dfb47ea16 100644 --- a/pdf.js +++ b/pdf.js @@ -750,6 +750,116 @@ var DecryptStream = (function() { return constructor; })(); +var Ascii85Stream = (function() { + function constructor(str) { + this.str = str; + this.dict = str.dict; + this.eof = false; + this.pos = 0; + this.bufferLength = 0; + this.buffer = new Uint8Array(4); + } + constructor.prototype = { + getByte: function() { + if (this.pos >= this.bufferLength) + this.readBlock(); + return this.buffer[this.pos++]; + }, + getBytes: function(n) { + var i, bytes; + bytes = new Uint8Array(n); + for (i = 0; i < n; ++i) { + if (this.pos >= this.bufferLength) + this.readBlock(); + if (this.eof) + break; + bytes[i] = this.buffer[this.pos++]; + } + return bytes; + }, + getChar : function() { + return String.fromCharCode(this.getByte()); + }, + lookChar : function() { + if (this.pos >= this.bufferLength) + this.readRow(); + return String.fromCharCode(this.currentRow[this.pos]); + }, + skip : function(n) { + var i; + if (!n) { + n = 1; + } + while (n > this.bufferLength - this.pos) { + n -= this.bufferLength - this.pos; + this.readBlock(); + if (this.bufferLength === 0) break; + } + this.pos += n; + }, + readBlock: function() { + if (this.eof) { + this.bufferLength = 0; + this.buffer = []; + this.pos = 0; + return; + } + + const tildaCode = "~".charCodeAt(0); + const zCode = "z".charCodeAt(0); + var str = this.str; + + var c = str.getByte(); + while (Lexer.isSpace(String.fromCharCode(c))) + c = str.getByte(); + if (!c || c === tildaCode) { + this.eof = true; + return; + } + + var buffer = this.buffer; + // special code for z + if (c == zCode) { + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + buffer[3] = 0; + this.bufferLength = 4; + } else { + var input = new Uint8Array(5); + input[0] = c; + for (var i = 1; i < 5; ++i){ + c = str.getByte(); + while (Lexer.isSpace(String.fromCharCode(c))) + c = str.getByte(); + + input[i] = c; + + if (!c || c == tildaCode) + break; + } + this.bufferLength = i - 1; + // partial ending; + if (i < 5) { + for (++i; i < 5; ++i) + input[i] = 0x21 + 84; + this.eof = true; + } + var t = 0; + for (var i = 0; i < 5; ++i) + t = t * 85 + (input[i] - 0x21); + + for (var i = 3; i >= 0; --i){ + buffer[i] = t & 0xFF; + t >>= 8; + } + } + } + }; + + return constructor; +})(); + var Name = (function() { function constructor(name) { this.name = name; @@ -1354,6 +1464,8 @@ var Parser = (function() { } else if (name == "DCTDecode") { var bytes = stream.getBytes(length); return new JpegStream(bytes, stream.dict); + } else if (name == "ASCII85Decode") { + return new Ascii85Stream(stream); } else { error("filter '" + name + "' not supported yet"); } From 1c3be696afd1b330adc0e04239d9b485a69409c2 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Tue, 21 Jun 2011 13:40:21 -0700 Subject: [PATCH 154/439] Don't error out for FontFile3 descriptors. --- pdf.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index fff135816..cffb1c0fa 100644 --- a/pdf.js +++ b/pdf.js @@ -784,6 +784,9 @@ var Dict = (function() { get2: function(key1, key2) { return this.get(key1) || this.get(key2); }, + get3: function(key1, key2, key3) { + return this.get(key1) || this.get(key2) || this.get(key3); + }, has: function(key) { return key in this.map; }, @@ -2255,7 +2258,7 @@ var CanvasGraphics = (function() { assertWellFormed(IsName(fontName), "invalid font name"); fontName = fontName.name.replace("+", "_"); - var fontFile = descriptor.get2("FontFile", "FontFile2"); + var fontFile = descriptor.get3("FontFile", "FontFile2", "FontFile3"); if (!fontFile) error("FontFile not found for font: " + fontName); fontFile = xref.fetchIfRef(fontFile); From 8f6006137d8adaa5d16a4437ee212d1392f12ad6 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Tue, 21 Jun 2011 13:56:49 -0700 Subject: [PATCH 155/439] fix typo --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index cffb1c0fa..52a65f1e3 100644 --- a/pdf.js +++ b/pdf.js @@ -2624,7 +2624,7 @@ var CanvasGraphics = (function() { setWordSpacing: function(spacing) { TODO("word spacing"); }, - setHSpacing: function(scale) { + setHScale: function(scale) { TODO("horizontal text scale"); }, setLeading: function(leading) { From 4ced0495137c116d2bf551ac3942fa19bff366d1 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 21 Jun 2011 14:34:13 -0700 Subject: [PATCH 156/439] fixed getBytes in Ascii85Stream --- pdf.js | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/pdf.js b/pdf.js index dfb47ea16..5ff97fa91 100644 --- a/pdf.js +++ b/pdf.js @@ -766,16 +766,38 @@ var Ascii85Stream = (function() { return this.buffer[this.pos++]; }, getBytes: function(n) { - var i, bytes; - bytes = new Uint8Array(n); - for (i = 0; i < n; ++i) { - if (this.pos >= this.bufferLength) - this.readBlock(); - if (this.eof) - break; - bytes[i] = this.buffer[this.pos++]; + if (n) { + var i, bytes; + bytes = new Uint8Array(n); + for (i = 0; i < n; ++i) { + if (this.pos >= this.bufferLength) + this.readBlock(); + if (this.eof) + break; + bytes[i] = this.buffer[this.pos++]; + } + return bytes; + } else { + var length = 0; + var size = 1 << 8; + var bytes = new Uint8Array(size); + while (true) { + if (this.pos >= this.bufferLength) + this.readBlock(); + if (this.eof) + break; + if (length == size) { + var oldSize = size; + size <<= 1; + var oldBytes = bytes; + bytes = new Uint8Array(size); + for (var i = 0; i < oldSize; ++i) + bytes[i] = oldBytes[i]; + } + bytes[length++] = this.buffer[this.pos++]; + } + return bytes.subarray(0, length); } - return bytes; }, getChar : function() { return String.fromCharCode(this.getByte()); @@ -1441,8 +1463,8 @@ var Parser = (function() { if (IsArray(filter)) { var filterArray = filter; var paramsArray = params; - for (var i = 0, ii = filter.length; i < ii; ++i) { - filter = filter[i]; + for (var i = 0, ii = filterArray.length; i < ii; ++i) { + filter = filterArray[i]; if (!IsName(filter)) error("Bad filter name"); else { From a64625b48dc457215381507ee641acc6672aa1bb Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Tue, 21 Jun 2011 14:53:57 -0700 Subject: [PATCH 157/439] test-harness improvements --- test.py | 59 ++++++++++++++++++++++++++++++++++------------ test_manifest.json | 4 ++-- test_slave.html | 23 +++++++++++++++--- 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/test.py b/test.py index 46d30fef5..7c3c4048a 100644 --- a/test.py +++ b/test.py @@ -1,7 +1,10 @@ import json, os, sys, subprocess from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from urlparse import urlparse ANAL = True +DEFAULT_MANIFEST_FILE = 'test_manifest.json' +REFDIR = 'ref' VERBOSE = False MIMEs = { @@ -34,8 +37,11 @@ class PDFTestHandler(BaseHTTPRequestHandler): BaseHTTPRequestHandler.log_request(code, size) def do_GET(self): + url = urlparse(self.path) + # Ignore query string + path, _ = url.path, url.query cwd = os.getcwd() - path = os.path.abspath(os.path.realpath(cwd + os.sep + self.path)) + path = os.path.abspath(os.path.realpath(cwd + os.sep + path)) cwd = os.path.abspath(cwd) prefix = os.path.commonprefix(( path, cwd )) _, ext = os.path.splitext(path) @@ -69,10 +75,10 @@ class PDFTestHandler(BaseHTTPRequestHandler): self.end_headers() result = json.loads(self.rfile.read(numBytes)) - browser = 'firefox4' - id, failure, round, page, snapshot = result['id'], result['failure'], result['round'], result['page'], result['snapshot'] + browser, id, failure, round, page, snapshot = result['browser'], result['id'], result['failure'], result['round'], result['page'], result['snapshot'] taskResults = State.taskResults[browser][id] - taskResults[round][page - 1] = Result(snapshot, failure) + taskResults[round].append(Result(snapshot, failure)) + assert len(taskResults[round]) == page if result['taskDone']: check(State.manifest[id], taskResults, browser) @@ -81,7 +87,7 @@ class PDFTestHandler(BaseHTTPRequestHandler): State.done = (0 == State.remaining) -def set_up(): +def set_up(manifestFile): # Only serve files from a pdf.js clone assert not ANAL or os.path.isfile('pdf.js') and os.path.isdir('.git') @@ -90,7 +96,7 @@ def set_up(): #'chrome12', 'chrome13', 'firefox5', 'firefox6','opera11' ): if os.access(b, os.R_OK | os.X_OK) ] - mf = open('test_manifest.json') + mf = open(manifestFile) manifestList = json.load(mf) mf.close() @@ -101,15 +107,16 @@ def set_up(): State.manifest[id] = item taskResults = [ ] for r in xrange(rounds): - taskResults.append([ None ] * 100) + taskResults.append([ ]) State.taskResults[b][id] = taskResults State.remaining = len(manifestList) for b in testBrowsers: print 'Launching', b + qs = 'browser='+ b +'&manifestFile='+ manifestFile subprocess.Popen(( os.path.abspath(os.path.realpath(b)), - 'http://localhost:8080/test_slave.html' )) + 'http://localhost:8080/test_slave.html?'+ qs)) def check(task, results, browser): @@ -129,7 +136,7 @@ def check(task, results, browser): return kind = task['type'] - if '==' == kind: + if 'eq' == kind: checkEq(task, results, browser) elif 'fbf' == kind: checkFBF(task, results, browser) @@ -140,8 +147,26 @@ def check(task, results, browser): def checkEq(task, results, browser): - print ' !!! [TODO: == tests] !!!' - print 'TEST-PASS | == test', task['id'], '| in', browser + pfx = os.path.join(REFDIR, sys.platform, browser, task['id']) + results = results[0] + + passed = True + for page in xrange(len(results)): + ref = None + try: + path = os.path.join(pfx, str(page + 1)) + f = open(path) + ref = f.read() + f.close() + except IOError, ioe: + continue + + snapshot = results[page] + if ref != snapshot: + print 'TEST-UNEXPECTED-FAIL | eq', task['id'], '| in', browser, '| rendering of page', page + 1, '!= reference rendering' + passed = False + if passed: + print 'TEST-PASS | eq test', task['id'], '| in', browser printed = [False] @@ -150,13 +175,16 @@ def checkFBF(task, results, browser): round0, round1 = results[0], results[1] assert len(round0) == len(round1) + passed = True for page in xrange(len(round1)): r0Page, r1Page = round0[page], round1[page] if r0Page is None: break if r0Page.snapshot != r1Page.snapshot: print 'TEST-UNEXPECTED-FAIL | forward-back-forward test', task['id'], '| in', browser, '| first rendering of page', page + 1, '!= second' - print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser + passed = False + if passed: + print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser def checkLoad(task, results, browser): @@ -165,11 +193,12 @@ def checkLoad(task, results, browser): print 'TEST-PASS | load test', task['id'], '| in', browser -def main(): - set_up() +def main(args): + manifestFile = args[0] if len(args) == 1 else DEFAULT_MANIFEST_FILE + set_up(manifestFile) server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) while not State.done: server.handle_request() if __name__ == '__main__': - main() + main(sys.argv[1:]) diff --git a/test_manifest.json b/test_manifest.json index 2f45a026c..e31b8b2b4 100644 --- a/test_manifest.json +++ b/test_manifest.json @@ -1,8 +1,8 @@ [ - { "id": "tracemonkey-==", + { "id": "tracemonkey-eq", "file": "tests/tracemonkey.pdf", "rounds": 1, - "type": "==" + "type": "eq" }, { "id": "tracemonkey-fbf", "file": "tests/tracemonkey.pdf", diff --git a/test_slave.html b/test_slave.html index c560d90d0..cff9b3f7d 100644 --- a/test_slave.html +++ b/test_slave.html @@ -5,9 +5,24 @@ @@ -31,7 +32,7 @@ function load() { stdout = document.getElementById("stdout"); log("Harness thinks this browser is '"+ browser +"'\n"); - log("Fetching manifest ..."); + log("Fetching manifest "+ manifestFile +"..."); var r = new XMLHttpRequest(); r.open("GET", manifestFile, false); @@ -81,38 +82,69 @@ function nextPage() { } failure = ''; - log(" drawing page "+ currentTask.pageNum +"..."); + log(" loading page "+ currentTask.pageNum +"... "); var ctx = canvas.getContext("2d"); clear(ctx); var fonts = []; + var fontsReady = true; var gfx = new CanvasGraphics(ctx); try { currentPage = pdfDoc.getPage(currentTask.pageNum); currentPage.compile(gfx, fonts); + + // Inspect fonts and translate the missing ones + var count = fonts.length; + for (var i = 0; i < count; ++i) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + new Font(font.name, font.file, font.properties); + fontsReady = false; + } } catch(e) { failure = 'compile: '+ e.toString(); } - // TODO load fonts - setTimeout(function() { - if (!failure) { - try { - currentPage.display(gfx); - } catch(e) { - failure = 'render: '+ e.toString(); - } + var checkFontsLoadedIntervalTimer = null; + function checkFontsLoaded() { + for (var i = 0; i < count; i++) { + if (Fonts[font.name].loading) { + return; } - currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages - && (1 + currentTask.round) == currentTask.rounds); - sendTaskResult(canvas.toDataURL("image/png")); - log("done"+ (failure ? " (failed!)" : "") +"\n"); + } + window.clearInterval(checkFontsLoadedIntervalTimer); - ++currentTask.pageNum, nextPage(); - }, - 0 - ); + snapshotCurrentPage(gfx); + } + + if (failure || fontsReady) { + snapshotCurrentPage(gfx); + } else { + checkFontsLoadedIntervalTimer = setInterval(checkFontsLoaded, 10); + } +} + +function snapshotCurrentPage(gfx) { + log("done, snapshotting... "); + + if (!failure) { + try { + currentPage.display(gfx); + } catch(e) { + failure = 'render: '+ e.toString(); + } + } + + currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages + && (1 + currentTask.round) == currentTask.rounds); + sendTaskResult(canvas.toDataURL("image/png")); + log("done"+ (failure ? " (failed!)" : "") +"\n"); + + ++currentTask.pageNum, nextPage(); } function done() { From 4ae16721fad131dc08994e149c6640ae65117e9f Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 18:37:58 -0700 Subject: [PATCH 198/439] actually wait for fonts to be loaded, and write out a log of failed eq comparisons --- test.py | 25 +++++++++++++++++- test_slave.html | 68 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/test.py b/test.py index 0c326ec09..26a86b6dd 100644 --- a/test.py +++ b/test.py @@ -9,6 +9,7 @@ def prompt(question): ANAL = True DEFAULT_MANIFEST_FILE = 'test_manifest.json' +EQLOG_FILE = 'eq.log' REFDIR = 'ref' TMPDIR = 'tmp' VERBOSE = False @@ -35,6 +36,7 @@ class State: numEqNoSnapshot = 0 numFBFFailures = 0 numLoadFailures = 0 + eqLog = None class Result: def __init__(self, snapshot, failure): @@ -190,6 +192,7 @@ def check(task, results, browser): def checkEq(task, results, browser): pfx = os.path.join(REFDIR, sys.platform, browser, task['id']) results = results[0] + taskId = task['id'] passed = True for page in xrange(len(results)): @@ -208,7 +211,21 @@ def checkEq(task, results, browser): eq = (ref == snapshot) if not eq: - print 'TEST-UNEXPECTED-FAIL | eq', task['id'], '| in', browser, '| rendering of page', page + 1, '!= reference rendering' + print 'TEST-UNEXPECTED-FAIL | eq', taskId, '| in', browser, '| rendering of page', page + 1, '!= reference rendering' + # XXX need to dump this always, somehow, when we have + # the reference repository + if State.masterMode: + if not State.eqLog: + State.eqLog = open(EQLOG_FILE, 'w') + eqLog = State.eqLog + + # NB: this follows the format of Mozilla reftest + # output so that we can reuse its reftest-analyzer + # script + print >>eqLog, 'REFTEST TEST-UNEXPECTED-FAIL |', browser +'-'+ taskId +'-page'+ str(page + 1), '| image comparison (==)' + print >>eqLog, 'REFTEST IMAGE 1 (TEST):', snapshot + print >>eqLog, 'REFTEST IMAGE 2 (REFERENCE):', ref + passed = False State.numEqFailures += 1 @@ -292,6 +309,12 @@ def main(args): masterMode = (args[0] == '-m') manifestFile = args[0] if not masterMode else manifestFile + + + masterMode = True + + + setUp(manifestFile, masterMode) server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) diff --git a/test_slave.html b/test_slave.html index 06b911810..718e887e0 100644 --- a/test_slave.html +++ b/test_slave.html @@ -1,6 +1,7 @@ pdf.js test slave + @@ -31,7 +32,7 @@ function load() { stdout = document.getElementById("stdout"); log("Harness thinks this browser is '"+ browser +"'\n"); - log("Fetching manifest ..."); + log("Fetching manifest "+ manifestFile +"..."); var r = new XMLHttpRequest(); r.open("GET", manifestFile, false); @@ -81,38 +82,69 @@ function nextPage() { } failure = ''; - log(" drawing page "+ currentTask.pageNum +"..."); + log(" loading page "+ currentTask.pageNum +"... "); var ctx = canvas.getContext("2d"); clear(ctx); var fonts = []; + var fontsReady = true; var gfx = new CanvasGraphics(ctx); try { currentPage = pdfDoc.getPage(currentTask.pageNum); currentPage.compile(gfx, fonts); + + // Inspect fonts and translate the missing ones + var count = fonts.length; + for (var i = 0; i < count; ++i) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + new Font(font.name, font.file, font.properties); + fontsReady = false; + } } catch(e) { failure = 'compile: '+ e.toString(); } - // TODO load fonts - setTimeout(function() { - if (!failure) { - try { - currentPage.display(gfx); - } catch(e) { - failure = 'render: '+ e.toString(); - } + var checkFontsLoadedIntervalTimer = null; + function checkFontsLoaded() { + for (var i = 0; i < count; i++) { + if (Fonts[font.name].loading) { + return; } - currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages - && (1 + currentTask.round) == currentTask.rounds); - sendTaskResult(canvas.toDataURL("image/png")); - log("done"+ (failure ? " (failed!)" : "") +"\n"); + } + window.clearInterval(checkFontsLoadedIntervalTimer); - ++currentTask.pageNum, nextPage(); - }, - 0 - ); + snapshotCurrentPage(gfx); + } + + if (failure || fontsReady) { + snapshotCurrentPage(gfx); + } else { + checkFontsLoadedIntervalTimer = setInterval(checkFontsLoaded, 10); + } +} + +function snapshotCurrentPage(gfx) { + log("done, snapshotting... "); + + if (!failure) { + try { + currentPage.display(gfx); + } catch(e) { + failure = 'render: '+ e.toString(); + } + } + + currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages + && (1 + currentTask.round) == currentTask.rounds); + sendTaskResult(canvas.toDataURL("image/png")); + log("done"+ (failure ? " (failed!)" : "") +"\n"); + + ++currentTask.pageNum, nextPage(); } function done() { From 90b24079d5e4201b3cc1c3814e37e2ef96725ec9 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 18:40:20 -0700 Subject: [PATCH 199/439] remove debugging code --- test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test.py b/test.py index 26a86b6dd..2d4a3e0f2 100644 --- a/test.py +++ b/test.py @@ -309,12 +309,6 @@ def main(args): masterMode = (args[0] == '-m') manifestFile = args[0] if not masterMode else manifestFile - - - masterMode = True - - - setUp(manifestFile, masterMode) server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) From 2ad48898682e6c8f043e5c2317ccd30a3094eeb4 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 18:40:20 -0700 Subject: [PATCH 200/439] remove debugging code --- test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test.py b/test.py index 26a86b6dd..2d4a3e0f2 100644 --- a/test.py +++ b/test.py @@ -309,12 +309,6 @@ def main(args): masterMode = (args[0] == '-m') manifestFile = args[0] if not masterMode else manifestFile - - - masterMode = True - - - setUp(manifestFile, masterMode) server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) From 35b6569f5e0bd6c2050b6065108ce10454b40ad6 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 18:50:38 -0700 Subject: [PATCH 201/439] fix strict-mode violations in chrome --- fonts.js | 6 +++--- pdf.js | 50 +++++++++++++++++++++++++------------------------- test.py | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/fonts.js b/fonts.js index a008dfce0..d5943b7a3 100644 --- a/fonts.js +++ b/fonts.js @@ -495,7 +495,7 @@ var Font = (function () { if (requiredTables.length && requiredTables[0] == "OS/2") { // Create a new file to hold the new version of our truetype with a new // header and new offsets - var ttf = Uint8Array(kMaxFontFileSize); + var ttf = new Uint8Array(kMaxFontFileSize); // The offsets object holds at the same time a representation of where // to write the table entry information about a table and another offset @@ -581,7 +581,7 @@ var Font = (function () { }, convert: function font_convert(name, font, properties) { - var otf = Uint8Array(kMaxFontFileSize); + var otf = new Uint8Array(kMaxFontFileSize); function createNameTable(name) { var names = [ @@ -1148,7 +1148,7 @@ var Type1Parser = function() { * The CFF class takes a Type1 file and wrap it into a 'Compact Font Format', * which itself embed Type2 charstrings. */ -const CFFStrings = [ +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", diff --git a/pdf.js b/pdf.js index 39e9e26df..5d9caf490 100644 --- a/pdf.js +++ b/pdf.js @@ -58,7 +58,7 @@ function bytesToString(bytes) { var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { - this.bytes = Uint8Array(arrayBuffer); + this.bytes = new Uint8Array(arrayBuffer); this.start = start || 0; this.pos = this.start; this.end = (start + length) || this.bytes.length; @@ -125,7 +125,7 @@ var Stream = (function() { var StringStream = (function() { function constructor(str) { var length = str.length; - var bytes = Uint8Array(length); + var bytes = new Uint8Array(length); for (var n = 0; n < length; ++n) bytes[n] = str.charCodeAt(n); Stream.call(this, bytes); @@ -154,7 +154,7 @@ var DecodeStream = (function() { var size = 512; while (size < requested) size <<= 1; - var buffer2 = Uint8Array(size); + var buffer2 = new Uint8Array(size); for (var i = 0; i < current; ++i) buffer2[i] = buffer[i]; return this.buffer = buffer2; @@ -222,11 +222,11 @@ var DecodeStream = (function() { var FlateStream = (function() { - const codeLenCodeMap = Uint32Array([ + var codeLenCodeMap = new Uint32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); - const lengthDecode = Uint32Array([ + var lengthDecode = new Uint32Array([ 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, @@ -234,7 +234,7 @@ var FlateStream = (function() { 0x00102, 0x00102, 0x00102 ]); - const distDecode = Uint32Array([ + var distDecode = new Uint32Array([ 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, @@ -242,7 +242,7 @@ var FlateStream = (function() { 0xd4001, 0xd6001 ]); - const fixedLitCodeTab = [Uint32Array([ + var fixedLitCodeTab = [new Uint32Array([ 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, @@ -319,7 +319,7 @@ var FlateStream = (function() { 0x900ff ]), 9]; - const fixedDistCodeTab = [Uint32Array([ + var fixedDistCodeTab = [new Uint32Array([ 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, @@ -410,7 +410,7 @@ var FlateStream = (function() { // build the table var size = 1 << maxLen; - var codes = Uint32Array(size); + var codes = new Uint32Array(size); for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { @@ -782,8 +782,8 @@ var Ascii85Stream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { - const tildaCode = "~".charCodeAt(0); - const zCode = "z".charCodeAt(0); + var tildaCode = "~".charCodeAt(0); + var zCode = "z".charCodeAt(0); var str = this.str; var c = str.getByte(); @@ -1001,10 +1001,10 @@ var Lexer = (function() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx ]; - const MIN_INT = (1<<31) | 0; - const MAX_INT = (MIN_INT - 1) | 0; - const MIN_UINT = 0; - const MAX_UINT = ((1<<30) * 4) - 1; + var MIN_INT = (1<<31) | 0; + var MAX_INT = (MIN_INT - 1) | 0; + var MIN_UINT = 0; + var MAX_UINT = ((1<<30) * 4) - 1; function ToHexDigit(ch) { if (ch >= "0" && ch <= "9") @@ -2031,7 +2031,7 @@ var PDFDoc = (function() { return constructor; })(); -const IDENTITY_MATRIX = [ 1, 0, 0, 1, 0, 0 ]; +var IDENTITY_MATRIX = [ 1, 0, 0, 1, 0, 0 ]; // contexts store most of the state we need natively. // However, PDF needs a bit more state, which we store here. @@ -2055,7 +2055,7 @@ var CanvasExtraState = (function() { return constructor; })(); -const Encodings = { +var Encodings = { get ExpertEncoding() { return shadow(this, "ExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", @@ -2333,13 +2333,13 @@ var CanvasGraphics = (function() { }; } - const LINE_CAP_STYLES = [ "butt", "round", "square" ]; - const LINE_JOIN_STYLES = [ "miter", "round", "bevel" ]; - const NORMAL_CLIP = {}; - const EO_CLIP = {}; + var LINE_CAP_STYLES = [ "butt", "round", "square" ]; + var LINE_JOIN_STYLES = [ "miter", "round", "bevel" ]; + var NORMAL_CLIP = {}; + var EO_CLIP = {}; // Used for tiling patterns - const PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; + var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; constructor.prototype = { translateFont: function(fontDict, xref, resources) { @@ -2874,7 +2874,7 @@ var CanvasGraphics = (function() { var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); var patternDict = IsStream(pattern) ? pattern.dict : pattern; - const types = [null, this.tilingFill, + var types = [null, this.tilingFill, function() { TODO("Shading Patterns"); }]; var typeNum = patternDict.get("PatternType"); var patternFn = types[typeNum]; @@ -3023,7 +3023,7 @@ var CanvasGraphics = (function() { if (background) TODO("handle background colors"); - const types = [null, + var types = [null, this.fillFunctionShading, this.fillAxialShading, this.fillRadialShading]; @@ -3460,7 +3460,7 @@ var PDFFunction = (function() { if (!dict) dict = fn; - const types = [this.constructSampled, + var types = [this.constructSampled, null, this.constructInterpolated, this.constructStiched, diff --git a/test.py b/test.py index 2d4a3e0f2..1557714d6 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,7 @@ VERBOSE = False MIMEs = { '.css': 'text/css', '.html': 'text/html', - '.js': 'application/json', + '.js': 'application/javascript', '.json': 'application/json', '.pdf': 'application/pdf', '.xhtml': 'application/xhtml+xml', From 57e7e798a63ff54b19fffd2b67c3d3b55f06fad5 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 18:50:38 -0700 Subject: [PATCH 202/439] fix strict-mode violations in chrome --- fonts.js | 6 +++--- pdf.js | 50 +++++++++++++++++++++++++------------------------- test.py | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/fonts.js b/fonts.js index a008dfce0..d5943b7a3 100644 --- a/fonts.js +++ b/fonts.js @@ -495,7 +495,7 @@ var Font = (function () { if (requiredTables.length && requiredTables[0] == "OS/2") { // Create a new file to hold the new version of our truetype with a new // header and new offsets - var ttf = Uint8Array(kMaxFontFileSize); + var ttf = new Uint8Array(kMaxFontFileSize); // The offsets object holds at the same time a representation of where // to write the table entry information about a table and another offset @@ -581,7 +581,7 @@ var Font = (function () { }, convert: function font_convert(name, font, properties) { - var otf = Uint8Array(kMaxFontFileSize); + var otf = new Uint8Array(kMaxFontFileSize); function createNameTable(name) { var names = [ @@ -1148,7 +1148,7 @@ var Type1Parser = function() { * The CFF class takes a Type1 file and wrap it into a 'Compact Font Format', * which itself embed Type2 charstrings. */ -const CFFStrings = [ +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", diff --git a/pdf.js b/pdf.js index 39e9e26df..5d9caf490 100644 --- a/pdf.js +++ b/pdf.js @@ -58,7 +58,7 @@ function bytesToString(bytes) { var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { - this.bytes = Uint8Array(arrayBuffer); + this.bytes = new Uint8Array(arrayBuffer); this.start = start || 0; this.pos = this.start; this.end = (start + length) || this.bytes.length; @@ -125,7 +125,7 @@ var Stream = (function() { var StringStream = (function() { function constructor(str) { var length = str.length; - var bytes = Uint8Array(length); + var bytes = new Uint8Array(length); for (var n = 0; n < length; ++n) bytes[n] = str.charCodeAt(n); Stream.call(this, bytes); @@ -154,7 +154,7 @@ var DecodeStream = (function() { var size = 512; while (size < requested) size <<= 1; - var buffer2 = Uint8Array(size); + var buffer2 = new Uint8Array(size); for (var i = 0; i < current; ++i) buffer2[i] = buffer[i]; return this.buffer = buffer2; @@ -222,11 +222,11 @@ var DecodeStream = (function() { var FlateStream = (function() { - const codeLenCodeMap = Uint32Array([ + var codeLenCodeMap = new Uint32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); - const lengthDecode = Uint32Array([ + var lengthDecode = new Uint32Array([ 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, @@ -234,7 +234,7 @@ var FlateStream = (function() { 0x00102, 0x00102, 0x00102 ]); - const distDecode = Uint32Array([ + var distDecode = new Uint32Array([ 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, @@ -242,7 +242,7 @@ var FlateStream = (function() { 0xd4001, 0xd6001 ]); - const fixedLitCodeTab = [Uint32Array([ + var fixedLitCodeTab = [new Uint32Array([ 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, @@ -319,7 +319,7 @@ var FlateStream = (function() { 0x900ff ]), 9]; - const fixedDistCodeTab = [Uint32Array([ + var fixedDistCodeTab = [new Uint32Array([ 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, @@ -410,7 +410,7 @@ var FlateStream = (function() { // build the table var size = 1 << maxLen; - var codes = Uint32Array(size); + var codes = new Uint32Array(size); for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) { @@ -782,8 +782,8 @@ var Ascii85Stream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { - const tildaCode = "~".charCodeAt(0); - const zCode = "z".charCodeAt(0); + var tildaCode = "~".charCodeAt(0); + var zCode = "z".charCodeAt(0); var str = this.str; var c = str.getByte(); @@ -1001,10 +1001,10 @@ var Lexer = (function() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx ]; - const MIN_INT = (1<<31) | 0; - const MAX_INT = (MIN_INT - 1) | 0; - const MIN_UINT = 0; - const MAX_UINT = ((1<<30) * 4) - 1; + var MIN_INT = (1<<31) | 0; + var MAX_INT = (MIN_INT - 1) | 0; + var MIN_UINT = 0; + var MAX_UINT = ((1<<30) * 4) - 1; function ToHexDigit(ch) { if (ch >= "0" && ch <= "9") @@ -2031,7 +2031,7 @@ var PDFDoc = (function() { return constructor; })(); -const IDENTITY_MATRIX = [ 1, 0, 0, 1, 0, 0 ]; +var IDENTITY_MATRIX = [ 1, 0, 0, 1, 0, 0 ]; // contexts store most of the state we need natively. // However, PDF needs a bit more state, which we store here. @@ -2055,7 +2055,7 @@ var CanvasExtraState = (function() { return constructor; })(); -const Encodings = { +var Encodings = { get ExpertEncoding() { return shadow(this, "ExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", @@ -2333,13 +2333,13 @@ var CanvasGraphics = (function() { }; } - const LINE_CAP_STYLES = [ "butt", "round", "square" ]; - const LINE_JOIN_STYLES = [ "miter", "round", "bevel" ]; - const NORMAL_CLIP = {}; - const EO_CLIP = {}; + var LINE_CAP_STYLES = [ "butt", "round", "square" ]; + var LINE_JOIN_STYLES = [ "miter", "round", "bevel" ]; + var NORMAL_CLIP = {}; + var EO_CLIP = {}; // Used for tiling patterns - const PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; + var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; constructor.prototype = { translateFont: function(fontDict, xref, resources) { @@ -2874,7 +2874,7 @@ var CanvasGraphics = (function() { var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); var patternDict = IsStream(pattern) ? pattern.dict : pattern; - const types = [null, this.tilingFill, + var types = [null, this.tilingFill, function() { TODO("Shading Patterns"); }]; var typeNum = patternDict.get("PatternType"); var patternFn = types[typeNum]; @@ -3023,7 +3023,7 @@ var CanvasGraphics = (function() { if (background) TODO("handle background colors"); - const types = [null, + var types = [null, this.fillFunctionShading, this.fillAxialShading, this.fillRadialShading]; @@ -3460,7 +3460,7 @@ var PDFFunction = (function() { if (!dict) dict = fn; - const types = [this.constructSampled, + var types = [this.constructSampled, null, this.constructInterpolated, this.constructStiched, diff --git a/test.py b/test.py index 2d4a3e0f2..1557714d6 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,7 @@ VERBOSE = False MIMEs = { '.css': 'text/css', '.html': 'text/html', - '.js': 'application/json', + '.js': 'application/javascript', '.json': 'application/json', '.pdf': 'application/pdf', '.xhtml': 'application/xhtml+xml', From 3121991de5504feff97c7c132685beb8886dec7d Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 22 Jun 2011 18:56:33 -0700 Subject: [PATCH 203/439] Cleaning up FaxStream --- pdf.js | 199 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 74 deletions(-) diff --git a/pdf.js b/pdf.js index 8cb1d07d1..a43dcf559 100644 --- a/pdf.js +++ b/pdf.js @@ -839,7 +839,7 @@ var Ascii85Stream = (function() { return constructor; })(); -var CcittFaxStream = (function() { +var CCITTFaxStream = (function() { const ccittEOL = -2; const twoDimPass = 0; @@ -1284,12 +1284,15 @@ var CcittFaxStream = (function() { this.codingLine = new Uint8Array(this.columns + 1); this.codingLine[0] = this.columns; + this.a0i = 0; + this.refLine = new Uint8Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; - this.a0i = 0; + this.inputBuf; this.outputBits = 0; + this.buf = EOF; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1310,57 +1313,81 @@ var CcittFaxStream = (function() { constructor.prototype.readBlock = function() { }; constructor.prototype.addPixels(a1, blackPixels) { - if (a1 > this.codingLine[this.a01]) { + var codingLine = this.codingLine; + var a0i = this.a0i; + + if (a1 > codingLine[a0i]) { if (a1 > this.columns) error("row is wrong length"); - if (this.a0i & 1) ^ this.blackPixels) - this.a0i++; + if (a0i & 1) ^ blackPixels) { + ++a0i; + this.a0i = a0i; + } - this.codingLine[this.a0i] = a1; - }; - constructor.prototype.addPixelsNeg(a1, blackPixels) { - if (a1 > this.codingLine[this.a01]) { - if (a1 > this.columns) - error("row is wrong length"); - if (this.a0i & 1) ^ this.blackPixels) - this.a0i++; - - this.codingLine[this.a0i] = a1; - } else if (at < this.codingLine[this.a0i]) { - if (a1 < 0) - error("invalid code"); - while (this.a0i > 0 && a1 < this.codingLine[this.a0i -i]) - this.a0i--; - this.codingLine[this.a0i] = a1; + codingLine[a0i] = a1; } }; - constructor.prototype.lookChar(a1, blackPixels) { + constructor.prototype.addPixelsNeg(a1, blackPixels) { + var codingLine = this.codingLine; + var a0i = this.a0i; + + if (a1 > codingLine[a0i]) { + if (a1 > this.columns) + error("row is wrong length"); + if (a0i & 1) ^ blackPixels) + ++a0i; + + codingLine[a0i] = a1; + } else if (a1 < codingLine[a0i]) { + if (a1 < 0) + error("invalid code"); + while (a0i > 0 && a1 < codingLine[a0i - 1]) + --a0i; + this.codingLine[a0i] = a1; + } + + this.a0i = a0i; + }; + constructor.prototype.lookChar() { var refLine = this.refLine; var codingLine = this.codingLine; var columns = this.columns; - if (this.outputBits == 0) { + var outputBits = this.outputBits; + var a0i = this.a0i; + + var b1i, blackPixels, bits; + + if (this.buf != EOF) + return buf; + + if (outputBits == 0) { + if (this.eof) + return; + if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) - refLine[i] = codeLine[i]; + refLine[i] = codingLine[i]; + refLine[i++] = columns; refLine[i] = columns; codingLine[0] = 0; - this.a0i = 0; - this.bl1 = 0; - this.blackPixels = 0; + a0i = 0; + bl1 = 0; + blackPixels = 0; - while (codingLine[this.a0i] < columns) { + while (codingLine[a0i] < columns) { var code1 = this.getTwoDumCode(); switch (code1) { case twoDimPass: - this.addPixels(refLine[this.bli + 1], this.blackPixels); - if (refLine[this.bli + 1] < columns) - this.bli += 2; + this.addPixels(refLine[b1i + 1], blackPixels); + a0i = this.a0i; + if (refLine[bli + 1] < columns) + bli += 2; break; case twoDimHoriz: var code1 = 0, code2 = 0; - if (this.blackPixels) { + if (blackPixels) { var code3; do { code1 += (code3 = this.getBlackCode()); @@ -1371,75 +1398,99 @@ var CcittFaxStream = (function() { else { var code3; do { - code1 += (code3 = getWhiteCode()); + code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); - this.addPixels(codeLine[this.a0i + code1, this.blackPixels); - if (codeLine[a0i] < columns) { - addPixels(codeLine[a0i] + code2, this.blackPixels ^ 1); - } - while (refLine[this.bli] <= codingLine[a0i] - && refLine[this.bli] < columns) { - this.bli += 2; - } + do { + code2 += (code3 = this.getBlackCode()); + } while (code3 >= 64); + } + this.addPixels(codingLine[a0i] + code1, blackPixels); + a0i = this.a0i; + if (codingLine[a0i] < columns) { + this.addPixels(codeLine[a0i] + code2, + blackPixels ^ 1); + a0i = this.a0i; + } + while (refLine[b1i] <= codingLine[a0i] + && refLine[bli] < columns) { + bli += 2; + } + break; + case twoDimVertR3: + this.addPixels(refLine[b1i] + 3, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && + refLine[b1i] < columns) + b1i += 2; } break; case twoDimVertR2: - this.addPixels(this.refLine[this.bli], blackPixels); + this.addPixels(refLine[b1i] + 2, blackPixels); + a0i = this.a0i; blackPixels ^= 1; - if (codeLine[this.a01] < columns) { - this.bli++; - while (refLine[this.bli] <= codeLine[this.a0i] && + if (codingLine[a01] < columns) { + ++bli; + while (refLine[bli] <= codingLine[a0i] && refLine[bli] < columns) { - this.bli += 2; + bli += 2; } } break; case twoDimVertR1: - this.addPixels(refLine[this.bli] + 1, blackPixels); - this.blackPixels ^= 1; - if (codeLine[this.a01] < columns) { - this.bli++; - while (refLine[this.bli] < codingLine[this.a0i] && - refLine[this.bli] < columns) + this.addPixels(refLine[bli] + 1, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a01] < columns) { + ++bli; + while (refLine[bli] < codingLine[a0i] && + refLine[bli] < columns) this.bli += 2; } break; case twoDimVert0: - this.addPixels(refLine[this.bli], blackPixels); - this.blackPixels ^= 1; - if (codingLine[this.a0i] < columns) { - this.bli++; - while (refLine[this.bli] <= codingLine[a0i] && - refLine[this.bli] < columns) - this.bli += 2; - } - break; - case twoDimVertL3: - this.addPixelsNeg(refLine[this.bli] - 3, blackPixels); - this.blackPixels ^= 1; - if (codeLine[a0i] < columns) { - if (bli > 0) - --bli; - else - ++bli; + this.addPixels(refLine[bli], blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++bli; while (refLine[bli] <= codingLine[a0i] && refLine[bli] < columns) bli += 2; } break; - case twoDimVertL2: - this.addPixelsNeg(refLine[bli] - 2, blackPixels); + case twoDimVertL3: + this.addPixelsNeg(refLine[bli] - 3, blackPixels); + a0i = this.a0i; blackPixels ^= 1; - if (codingLine[a0i] < columns) { + if (codeLine[a0i] < columns) { if (bli > 0) --bli; else ++bli; - while (refLine[bli] <= codingLine[a0i] && - refLine[bl1] < columns) + while (refLine[b1i] <= codingLine[a0i] && + refLine[b1i] < columns) bli += 2; } break; + case twoDimVertL2: + this.addPixelsNeg(refLine[b1i] - 2, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + if (b1i > 0) + --b1i; + else + ++bli; + while (refLine[b1i] <= codingLine[a0i] && + refLine[b11] < columns) + b1i += 2; + } + break; + +///////// STOPPED HERE case twoDimVertL1: this.addPixelsNeg(refLine[bli] - 1, blackPixels); this.blackPixels ^= 1; From 325170a5fcc5e5c33e5abd966d0d7e8d6914ec6b Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 22 Jun 2011 18:56:33 -0700 Subject: [PATCH 204/439] Cleaning up FaxStream --- pdf.js | 199 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 74 deletions(-) diff --git a/pdf.js b/pdf.js index 8cb1d07d1..a43dcf559 100644 --- a/pdf.js +++ b/pdf.js @@ -839,7 +839,7 @@ var Ascii85Stream = (function() { return constructor; })(); -var CcittFaxStream = (function() { +var CCITTFaxStream = (function() { const ccittEOL = -2; const twoDimPass = 0; @@ -1284,12 +1284,15 @@ var CcittFaxStream = (function() { this.codingLine = new Uint8Array(this.columns + 1); this.codingLine[0] = this.columns; + this.a0i = 0; + this.refLine = new Uint8Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; - this.a0i = 0; + this.inputBuf; this.outputBits = 0; + this.buf = EOF; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1310,57 +1313,81 @@ var CcittFaxStream = (function() { constructor.prototype.readBlock = function() { }; constructor.prototype.addPixels(a1, blackPixels) { - if (a1 > this.codingLine[this.a01]) { + var codingLine = this.codingLine; + var a0i = this.a0i; + + if (a1 > codingLine[a0i]) { if (a1 > this.columns) error("row is wrong length"); - if (this.a0i & 1) ^ this.blackPixels) - this.a0i++; + if (a0i & 1) ^ blackPixels) { + ++a0i; + this.a0i = a0i; + } - this.codingLine[this.a0i] = a1; - }; - constructor.prototype.addPixelsNeg(a1, blackPixels) { - if (a1 > this.codingLine[this.a01]) { - if (a1 > this.columns) - error("row is wrong length"); - if (this.a0i & 1) ^ this.blackPixels) - this.a0i++; - - this.codingLine[this.a0i] = a1; - } else if (at < this.codingLine[this.a0i]) { - if (a1 < 0) - error("invalid code"); - while (this.a0i > 0 && a1 < this.codingLine[this.a0i -i]) - this.a0i--; - this.codingLine[this.a0i] = a1; + codingLine[a0i] = a1; } }; - constructor.prototype.lookChar(a1, blackPixels) { + constructor.prototype.addPixelsNeg(a1, blackPixels) { + var codingLine = this.codingLine; + var a0i = this.a0i; + + if (a1 > codingLine[a0i]) { + if (a1 > this.columns) + error("row is wrong length"); + if (a0i & 1) ^ blackPixels) + ++a0i; + + codingLine[a0i] = a1; + } else if (a1 < codingLine[a0i]) { + if (a1 < 0) + error("invalid code"); + while (a0i > 0 && a1 < codingLine[a0i - 1]) + --a0i; + this.codingLine[a0i] = a1; + } + + this.a0i = a0i; + }; + constructor.prototype.lookChar() { var refLine = this.refLine; var codingLine = this.codingLine; var columns = this.columns; - if (this.outputBits == 0) { + var outputBits = this.outputBits; + var a0i = this.a0i; + + var b1i, blackPixels, bits; + + if (this.buf != EOF) + return buf; + + if (outputBits == 0) { + if (this.eof) + return; + if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) - refLine[i] = codeLine[i]; + refLine[i] = codingLine[i]; + refLine[i++] = columns; refLine[i] = columns; codingLine[0] = 0; - this.a0i = 0; - this.bl1 = 0; - this.blackPixels = 0; + a0i = 0; + bl1 = 0; + blackPixels = 0; - while (codingLine[this.a0i] < columns) { + while (codingLine[a0i] < columns) { var code1 = this.getTwoDumCode(); switch (code1) { case twoDimPass: - this.addPixels(refLine[this.bli + 1], this.blackPixels); - if (refLine[this.bli + 1] < columns) - this.bli += 2; + this.addPixels(refLine[b1i + 1], blackPixels); + a0i = this.a0i; + if (refLine[bli + 1] < columns) + bli += 2; break; case twoDimHoriz: var code1 = 0, code2 = 0; - if (this.blackPixels) { + if (blackPixels) { var code3; do { code1 += (code3 = this.getBlackCode()); @@ -1371,75 +1398,99 @@ var CcittFaxStream = (function() { else { var code3; do { - code1 += (code3 = getWhiteCode()); + code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); - this.addPixels(codeLine[this.a0i + code1, this.blackPixels); - if (codeLine[a0i] < columns) { - addPixels(codeLine[a0i] + code2, this.blackPixels ^ 1); - } - while (refLine[this.bli] <= codingLine[a0i] - && refLine[this.bli] < columns) { - this.bli += 2; - } + do { + code2 += (code3 = this.getBlackCode()); + } while (code3 >= 64); + } + this.addPixels(codingLine[a0i] + code1, blackPixels); + a0i = this.a0i; + if (codingLine[a0i] < columns) { + this.addPixels(codeLine[a0i] + code2, + blackPixels ^ 1); + a0i = this.a0i; + } + while (refLine[b1i] <= codingLine[a0i] + && refLine[bli] < columns) { + bli += 2; + } + break; + case twoDimVertR3: + this.addPixels(refLine[b1i] + 3, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++b1i; + while (refLine[b1i] <= codingLine[a0i] && + refLine[b1i] < columns) + b1i += 2; } break; case twoDimVertR2: - this.addPixels(this.refLine[this.bli], blackPixels); + this.addPixels(refLine[b1i] + 2, blackPixels); + a0i = this.a0i; blackPixels ^= 1; - if (codeLine[this.a01] < columns) { - this.bli++; - while (refLine[this.bli] <= codeLine[this.a0i] && + if (codingLine[a01] < columns) { + ++bli; + while (refLine[bli] <= codingLine[a0i] && refLine[bli] < columns) { - this.bli += 2; + bli += 2; } } break; case twoDimVertR1: - this.addPixels(refLine[this.bli] + 1, blackPixels); - this.blackPixels ^= 1; - if (codeLine[this.a01] < columns) { - this.bli++; - while (refLine[this.bli] < codingLine[this.a0i] && - refLine[this.bli] < columns) + this.addPixels(refLine[bli] + 1, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a01] < columns) { + ++bli; + while (refLine[bli] < codingLine[a0i] && + refLine[bli] < columns) this.bli += 2; } break; case twoDimVert0: - this.addPixels(refLine[this.bli], blackPixels); - this.blackPixels ^= 1; - if (codingLine[this.a0i] < columns) { - this.bli++; - while (refLine[this.bli] <= codingLine[a0i] && - refLine[this.bli] < columns) - this.bli += 2; - } - break; - case twoDimVertL3: - this.addPixelsNeg(refLine[this.bli] - 3, blackPixels); - this.blackPixels ^= 1; - if (codeLine[a0i] < columns) { - if (bli > 0) - --bli; - else - ++bli; + this.addPixels(refLine[bli], blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + ++bli; while (refLine[bli] <= codingLine[a0i] && refLine[bli] < columns) bli += 2; } break; - case twoDimVertL2: - this.addPixelsNeg(refLine[bli] - 2, blackPixels); + case twoDimVertL3: + this.addPixelsNeg(refLine[bli] - 3, blackPixels); + a0i = this.a0i; blackPixels ^= 1; - if (codingLine[a0i] < columns) { + if (codeLine[a0i] < columns) { if (bli > 0) --bli; else ++bli; - while (refLine[bli] <= codingLine[a0i] && - refLine[bl1] < columns) + while (refLine[b1i] <= codingLine[a0i] && + refLine[b1i] < columns) bli += 2; } break; + case twoDimVertL2: + this.addPixelsNeg(refLine[b1i] - 2, blackPixels); + a0i = this.a0i; + blackPixels ^= 1; + if (codingLine[a0i] < columns) { + if (b1i > 0) + --b1i; + else + ++bli; + while (refLine[b1i] <= codingLine[a0i] && + refLine[b11] < columns) + b1i += 2; + } + break; + +///////// STOPPED HERE case twoDimVertL1: this.addPixelsNeg(refLine[bli] - 1, blackPixels); this.blackPixels ^= 1; From 553250a5d2579769723407604f390eb33c6be8d8 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 22 Jun 2011 19:20:03 -0700 Subject: [PATCH 205/439] fake stream for unimplemented filters --- pdf.js | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/pdf.js b/pdf.js index 39e9e26df..cd3cdfba5 100644 --- a/pdf.js +++ b/pdf.js @@ -220,6 +220,43 @@ var DecodeStream = (function() { })(); +var FakeStream = (function() { + function constructor(stream) { + this.dict = stream.dict; + DecodeStream.call(this); + }; + + constructor.prototype = Object.create(DecodeStream.prototype); + constructor.prototype.readBlock = function() { + var bufferLength = this.bufferLength; + bufferLength += 1024; + var buffer = this.ensureBuffer(bufferLength); + this.bufferLength = bufferLength; + }; + constructor.prototype.getBytes = function(length) { + var pos = this.pos; + + if (length) { + this.ensureBuffer(pos + length); + var end = pos + length; + + while (!this.eof && this.bufferLength < end) + this.readBlock(); + + var bufEnd = this.bufferLength; + if (end > bufEnd) + end = bufEnd; + } else { + this.eof = true; + var end = this.bufferLength; + } + + this.pos = end; + return this.buffer.subarray(pos, end) + }; + + return constructor; +})(); var FlateStream = (function() { const codeLenCodeMap = Uint32Array([ @@ -597,9 +634,6 @@ var PredictorStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlockTiff = function() { - var buffer = this.buffer; - var pos = this.pos; - var rowBytes = this.rowBytes; var pixBytes = this.pixBytes; @@ -660,9 +694,6 @@ var PredictorStream = (function() { this.bufferLength += rowBytes; }; constructor.prototype.readBlockPng = function() { - var buffer = this.buffer; - var pos = this.pos; - var rowBytes = this.rowBytes; var pixBytes = this.pixBytes; @@ -1448,6 +1479,9 @@ var Parser = (function() { return new JpegStream(bytes, stream.dict); } else if (name == "ASCII85Decode") { return new Ascii85Stream(stream); + } else if (name == "CCITTFaxDecode") { + TODO("implement fax stream"); + return new FakeStream(stream); } else { error("filter '" + name + "' not supported yet"); } From d610397d1e4ec6500da543e7a866a957ccc629f7 Mon Sep 17 00:00:00 2001 From: sbarman Date: Wed, 22 Jun 2011 19:20:03 -0700 Subject: [PATCH 206/439] fake stream for unimplemented filters --- pdf.js | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/pdf.js b/pdf.js index 39e9e26df..cd3cdfba5 100644 --- a/pdf.js +++ b/pdf.js @@ -220,6 +220,43 @@ var DecodeStream = (function() { })(); +var FakeStream = (function() { + function constructor(stream) { + this.dict = stream.dict; + DecodeStream.call(this); + }; + + constructor.prototype = Object.create(DecodeStream.prototype); + constructor.prototype.readBlock = function() { + var bufferLength = this.bufferLength; + bufferLength += 1024; + var buffer = this.ensureBuffer(bufferLength); + this.bufferLength = bufferLength; + }; + constructor.prototype.getBytes = function(length) { + var pos = this.pos; + + if (length) { + this.ensureBuffer(pos + length); + var end = pos + length; + + while (!this.eof && this.bufferLength < end) + this.readBlock(); + + var bufEnd = this.bufferLength; + if (end > bufEnd) + end = bufEnd; + } else { + this.eof = true; + var end = this.bufferLength; + } + + this.pos = end; + return this.buffer.subarray(pos, end) + }; + + return constructor; +})(); var FlateStream = (function() { const codeLenCodeMap = Uint32Array([ @@ -597,9 +634,6 @@ var PredictorStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlockTiff = function() { - var buffer = this.buffer; - var pos = this.pos; - var rowBytes = this.rowBytes; var pixBytes = this.pixBytes; @@ -660,9 +694,6 @@ var PredictorStream = (function() { this.bufferLength += rowBytes; }; constructor.prototype.readBlockPng = function() { - var buffer = this.buffer; - var pos = this.pos; - var rowBytes = this.rowBytes; var pixBytes = this.pixBytes; @@ -1448,6 +1479,9 @@ var Parser = (function() { return new JpegStream(bytes, stream.dict); } else if (name == "ASCII85Decode") { return new Ascii85Stream(stream); + } else if (name == "CCITTFaxDecode") { + TODO("implement fax stream"); + return new FakeStream(stream); } else { error("filter '" + name + "' not supported yet"); } From 7b454d403bdce69d4be1feeaa59932cf6491bc31 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 23 Jun 2011 05:38:05 +0200 Subject: [PATCH 207/439] Use the real content of the string to measure it's size --- pdf.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 5d9caf490..addcea6de 100644 --- a/pdf.js +++ b/pdf.js @@ -2787,7 +2787,9 @@ var CanvasGraphics = (function() { this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); this.ctx.translate(0, -2 * this.current.y); - this.ctx.fillText(Fonts.charsToUnicode(text), this.current.x, this.current.y); + + text = Fonts.charsToUnicode(text); + this.ctx.fillText(text, this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; this.ctx.restore(); From b54164d2a95054727a3f01b0bb861516566b2ac8 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 23 Jun 2011 05:38:05 +0200 Subject: [PATCH 208/439] Use the real content of the string to measure it's size --- pdf.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 5d9caf490..addcea6de 100644 --- a/pdf.js +++ b/pdf.js @@ -2787,7 +2787,9 @@ var CanvasGraphics = (function() { this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); this.ctx.translate(0, -2 * this.current.y); - this.ctx.fillText(Fonts.charsToUnicode(text), this.current.x, this.current.y); + + text = Fonts.charsToUnicode(text); + this.ctx.fillText(text, this.current.x, this.current.y); this.current.x += this.ctx.measureText(text).width; this.ctx.restore(); From 0d4be031b98926a27b7a6ceec70ab13e596509ee Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 20:47:37 -0700 Subject: [PATCH 209/439] fix bug in testing multiple browsers --- test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 1557714d6..9eab0e80e 100644 --- a/test.py +++ b/test.py @@ -117,8 +117,8 @@ def setUp(manifestFile, masterMode): assert not os.path.isdir(TMPDIR) testBrowsers = [ b for b in - ( 'firefox5', ) -#'chrome12', 'chrome13', 'firefox4', 'firefox6','opera11' ): + ( 'firefox5', 'firefox6', ) +#'chrome12', 'chrome13', 'firefox4', 'opera11' ): if os.access(b, os.R_OK | os.X_OK) ] mf = open(manifestFile) @@ -152,7 +152,7 @@ def setUp(manifestFile, masterMode): taskResults.append([ ]) State.taskResults[b][id] = taskResults - State.remaining = len(manifestList) + State.remaining = len(testBrowsers) * len(manifestList) for b in testBrowsers: print 'Launching', b From 1532e86dcb82ff78d2fe0b52c0b7f1bc45eca0ce Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 22 Jun 2011 20:47:37 -0700 Subject: [PATCH 210/439] fix bug in testing multiple browsers --- test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 1557714d6..9eab0e80e 100644 --- a/test.py +++ b/test.py @@ -117,8 +117,8 @@ def setUp(manifestFile, masterMode): assert not os.path.isdir(TMPDIR) testBrowsers = [ b for b in - ( 'firefox5', ) -#'chrome12', 'chrome13', 'firefox4', 'firefox6','opera11' ): + ( 'firefox5', 'firefox6', ) +#'chrome12', 'chrome13', 'firefox4', 'opera11' ): if os.access(b, os.R_OK | os.X_OK) ] mf = open(manifestFile) @@ -152,7 +152,7 @@ def setUp(manifestFile, masterMode): taskResults.append([ ]) State.taskResults[b][id] = taskResults - State.remaining = len(manifestList) + State.remaining = len(testBrowsers) * len(manifestList) for b in testBrowsers: print 'Launching', b From 5ae4857efd8ad907dedb6d8817affcae38818296 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Thu, 23 Jun 2011 09:05:51 -0700 Subject: [PATCH 211/439] Add new test directories. --- test/.gitignore | 0 test/pdfs/.gitignore | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/.gitignore create mode 100644 test/pdfs/.gitignore diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore new file mode 100644 index 000000000..e69de29bb From 2ac8bbed51a5eace305842a62ebe2527751bfe6d Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Thu, 23 Jun 2011 09:05:51 -0700 Subject: [PATCH 212/439] Add new test directories. --- test/.gitignore | 0 test/pdfs/.gitignore | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/.gitignore create mode 100644 test/pdfs/.gitignore diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore new file mode 100644 index 000000000..e69de29bb From 0d5f92deedb16d3e8b85fc2c6dcf753f572cedd2 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Thu, 23 Jun 2011 09:10:06 -0700 Subject: [PATCH 213/439] Move some files around. --- browser_manifest.json => test/browser_manifest.json | 0 {tests => test/pdfs}/canvas.pdf | Bin {tests => test/pdfs}/pdf.pdf.link | 0 {tests => test/pdfs}/tracemonkey.pdf | Bin test.py => test/test.py | 0 test_manifest.json => test/test_manifest.json | 0 test_slave.html => test/test_slave.html | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename browser_manifest.json => test/browser_manifest.json (100%) rename {tests => test/pdfs}/canvas.pdf (100%) rename {tests => test/pdfs}/pdf.pdf.link (100%) rename {tests => test/pdfs}/tracemonkey.pdf (100%) rename test.py => test/test.py (100%) rename test_manifest.json => test/test_manifest.json (100%) rename test_slave.html => test/test_slave.html (100%) diff --git a/browser_manifest.json b/test/browser_manifest.json similarity index 100% rename from browser_manifest.json rename to test/browser_manifest.json diff --git a/tests/canvas.pdf b/test/pdfs/canvas.pdf similarity index 100% rename from tests/canvas.pdf rename to test/pdfs/canvas.pdf diff --git a/tests/pdf.pdf.link b/test/pdfs/pdf.pdf.link similarity index 100% rename from tests/pdf.pdf.link rename to test/pdfs/pdf.pdf.link diff --git a/tests/tracemonkey.pdf b/test/pdfs/tracemonkey.pdf similarity index 100% rename from tests/tracemonkey.pdf rename to test/pdfs/tracemonkey.pdf diff --git a/test.py b/test/test.py similarity index 100% rename from test.py rename to test/test.py diff --git a/test_manifest.json b/test/test_manifest.json similarity index 100% rename from test_manifest.json rename to test/test_manifest.json diff --git a/test_slave.html b/test/test_slave.html similarity index 100% rename from test_slave.html rename to test/test_slave.html From 2454354b5907778bb4f3fd6db012ab8b8f2c44fc Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Thu, 23 Jun 2011 09:10:06 -0700 Subject: [PATCH 214/439] Move some files around. --- browser_manifest.json => test/browser_manifest.json | 0 {tests => test/pdfs}/canvas.pdf | Bin {tests => test/pdfs}/pdf.pdf.link | 0 {tests => test/pdfs}/tracemonkey.pdf | Bin test.py => test/test.py | 0 test_manifest.json => test/test_manifest.json | 0 test_slave.html => test/test_slave.html | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename browser_manifest.json => test/browser_manifest.json (100%) rename {tests => test/pdfs}/canvas.pdf (100%) rename {tests => test/pdfs}/pdf.pdf.link (100%) rename {tests => test/pdfs}/tracemonkey.pdf (100%) rename test.py => test/test.py (100%) rename test_manifest.json => test/test_manifest.json (100%) rename test_slave.html => test/test_slave.html (100%) diff --git a/browser_manifest.json b/test/browser_manifest.json similarity index 100% rename from browser_manifest.json rename to test/browser_manifest.json diff --git a/tests/canvas.pdf b/test/pdfs/canvas.pdf similarity index 100% rename from tests/canvas.pdf rename to test/pdfs/canvas.pdf diff --git a/tests/pdf.pdf.link b/test/pdfs/pdf.pdf.link similarity index 100% rename from tests/pdf.pdf.link rename to test/pdfs/pdf.pdf.link diff --git a/tests/tracemonkey.pdf b/test/pdfs/tracemonkey.pdf similarity index 100% rename from tests/tracemonkey.pdf rename to test/pdfs/tracemonkey.pdf diff --git a/test.py b/test/test.py similarity index 100% rename from test.py rename to test/test.py diff --git a/test_manifest.json b/test/test_manifest.json similarity index 100% rename from test_manifest.json rename to test/test_manifest.json diff --git a/test_slave.html b/test/test_slave.html similarity index 100% rename from test_slave.html rename to test/test_slave.html From fd5412ac1270ade070e6e002216577ba3c99a0d7 Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 23 Jun 2011 09:41:59 -0700 Subject: [PATCH 215/439] fix for uncompressed flatestream blocks --- pdf.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index d940c4f8b..326c31234 100644 --- a/pdf.js +++ b/pdf.js @@ -479,17 +479,17 @@ var FlateStream = (function() { array[i++] = what; } - var bytes = this.bytes; - var bytesPos = this.bytesPos; - // read block header var hdr = this.getBits(3); if (hdr & 1) this.eof = true; hdr >>= 1; - var b; if (hdr == 0) { // uncompressed block + var bytes = this.bytes; + var bytesPos = this.bytesPos; + var b; + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var blockLen = b; @@ -502,18 +502,24 @@ var FlateStream = (function() { if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); check |= (b << 8); - if (check != (~this.blockLen & 0xffff)) + if (check != (~blockLen & 0xffff)) error("Bad uncompressed block length in flate stream"); + + this.codeBuf = 0; + this.codeSize = 0; + var bufferLength = this.bufferLength; var buffer = this.ensureBuffer(bufferLength + blockLen); - this.bufferLength = bufferLength + blockLen; - for (var n = bufferLength; n < blockLen; ++n) { + var end = bufferLength + blockLen; + this.bufferLength = end; + for (var n = bufferLength; n < end; ++n) { if (typeof (b = bytes[bytesPos++]) == "undefined") { this.eof = true; break; } buffer[n] = b; } + this.bytesPos = bytesPos; return; } From 18afc896f610253a20040067a3dc8c53eaed9f8d Mon Sep 17 00:00:00 2001 From: sbarman Date: Thu, 23 Jun 2011 09:41:59 -0700 Subject: [PATCH 216/439] fix for uncompressed flatestream blocks --- pdf.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index d940c4f8b..326c31234 100644 --- a/pdf.js +++ b/pdf.js @@ -479,17 +479,17 @@ var FlateStream = (function() { array[i++] = what; } - var bytes = this.bytes; - var bytesPos = this.bytesPos; - // read block header var hdr = this.getBits(3); if (hdr & 1) this.eof = true; hdr >>= 1; - var b; if (hdr == 0) { // uncompressed block + var bytes = this.bytes; + var bytesPos = this.bytesPos; + var b; + if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); var blockLen = b; @@ -502,18 +502,24 @@ var FlateStream = (function() { if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad block header in flate stream"); check |= (b << 8); - if (check != (~this.blockLen & 0xffff)) + if (check != (~blockLen & 0xffff)) error("Bad uncompressed block length in flate stream"); + + this.codeBuf = 0; + this.codeSize = 0; + var bufferLength = this.bufferLength; var buffer = this.ensureBuffer(bufferLength + blockLen); - this.bufferLength = bufferLength + blockLen; - for (var n = bufferLength; n < blockLen; ++n) { + var end = bufferLength + blockLen; + this.bufferLength = end; + for (var n = bufferLength; n < end; ++n) { if (typeof (b = bytes[bytesPos++]) == "undefined") { this.eof = true; break; } buffer[n] = b; } + this.bytesPos = bytesPos; return; } From 0a8e1110a33cbe3c7f4be3ad259647a4fc69485f Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Thu, 23 Jun 2011 09:48:34 -0700 Subject: [PATCH 217/439] Modify paths of web resources to work with test resources more buried. --- test/browser_manifest.json | 2 +- test/test.py | 18 +++++++++--------- test/test_manifest.json | 8 ++++---- test/test_slave.html | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/browser_manifest.json b/test/browser_manifest.json index 79115d1a4..f11c97c11 100644 --- a/test/browser_manifest.json +++ b/test/browser_manifest.json @@ -1,6 +1,6 @@ [ { - "name":"Firefox 5", + "name":"firefox5", "path":"/Applications/Firefox.app", "type":"firefox" } diff --git a/test/test.py b/test/test.py index 75810f43e..acdd0c552 100644 --- a/test/test.py +++ b/test/test.py @@ -5,6 +5,9 @@ from urlparse import urlparse USAGE_EXAMPLE = "%prog" +# The local web server uses the git repo as the document root. +DOC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) + ANAL = True DEFAULT_MANIFEST_FILE = 'test_manifest.json' DEFAULT_BROWSER_MANIFEST_FILE = 'browser_manifest.json' @@ -73,15 +76,14 @@ class PDFTestHandler(BaseHTTPRequestHandler): def do_GET(self): url = urlparse(self.path) + print "GET",url # Ignore query string path, _ = url.path, url.query - cwd = os.getcwd() - path = os.path.abspath(os.path.realpath(cwd + os.sep + path)) - cwd = os.path.abspath(cwd) - prefix = os.path.commonprefix(( path, cwd )) + path = os.path.abspath(os.path.realpath(DOC_ROOT + os.sep + path)) + prefix = os.path.commonprefix(( path, DOC_ROOT )) _, ext = os.path.splitext(path) - if not (prefix == cwd + if not (prefix == DOC_ROOT and os.path.isfile(path) and ext in MIMEs): self.send_error(404) @@ -146,7 +148,7 @@ def makeBrowserCommands(browserManifestFile): def setUp(options): # Only serve files from a pdf.js clone - assert not ANAL or os.path.isfile('pdf.js') and os.path.isdir('.git') + assert not ANAL or os.path.isfile('../pdf.js') and os.path.isdir('../.git') State.masterMode = options.masterMode if options.masterMode and os.path.isdir(TMPDIR): @@ -191,13 +193,11 @@ def setUp(options): State.remaining = len(manifestList) - - for b in testBrowsers: print 'Launching', b.name qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) subprocess.Popen(( os.path.abspath(os.path.realpath(b.path)), - 'http://localhost:8080/test_slave.html?'+ qs)) + 'http://localhost:8080/test/test_slave.html?'+ qs)) def check(task, results, browser): diff --git a/test/test_manifest.json b/test/test_manifest.json index 036b7aafc..e4a7ada81 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1,21 +1,21 @@ [ { "id": "tracemonkey-eq", - "file": "tests/tracemonkey.pdf", + "file": "pdfs/tracemonkey.pdf", "rounds": 1, "type": "eq" }, { "id": "tracemonkey-fbf", - "file": "tests/tracemonkey.pdf", + "file": "pdfs/tracemonkey.pdf", "rounds": 2, "type": "fbf" }, { "id": "html5-canvas-cheat-sheet-load", - "file": "tests/canvas.pdf", + "file": "pdfs/canvas.pdf", "rounds": 1, "type": "load" }, { "id": "pdfspec-load", - "file": "tests/pdf.pdf", + "file": "pdfs/pdf.pdf", "link": true, "rounds": 1, "type": "load" diff --git a/test/test_slave.html b/test/test_slave.html index 06b911810..80e374709 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -1,9 +1,9 @@ pdf.js test slave - - - + + + - - + + + + + + + +
+ + + + + + -- + +
+ +
+ + + +
+ + + diff --git a/worker.js b/worker.js new file mode 100644 index 000000000..fdc762afd --- /dev/null +++ b/worker.js @@ -0,0 +1,113 @@ +"use strict"; + +function log() { + var args = Array.prototype.slice.call(arguments); + postMessage("log"); + postMessage(JSON.stringify(args)) +} + +var console = { + log: log +} + +importScripts("canvas_proxy.js"); +importScripts("pdf.js"); +importScripts("fonts.js"); +importScripts("glyphlist.js") + +// var array = new Uint8Array(2); +// array[0] = 1; +// array[1] = 300; +// postMessage(array); + +var timer = null; +function tic() { + timer = Date.now(); +} + +function toc(msg) { + log("Took ", (Date.now() - timer)); + timer = null; +} + + +var canvas = new CanvasProxy(1224, 1584); +// canvas.moveTo(0, 10); +// canvas.lineTo(0, 20); +// canvas.lineTo(500, 500); +// canvas.flush(); +// canvas.stroke(); +// canvas.flush(); +log("test"); + +onmessage = function(event) { + var data = event.data; + var pdfDocument = new PDFDoc(new Stream(data)); + var numPages = pdfDocument.numPages; + + tic(); + // Let's try to render the first page... + var page = pdfDocument.getPage(1); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + + var gfx = new CanvasGraphics(canvas); + page.compile(gfx, fonts); + toc("compiled page"); + + // + var fontsReady = true; + // Inspect fonts and translate the missing one + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + fontsReady = false; + } + + function delayLoadFont() { + for (var i = 0; i < count; i++) { + if (Fonts[font.name].loading) + return; + } + clearInterval(pageInterval); + page.display(gfx); + + canvas.flush(); + }; + + if (fontsReady) { + delayLoadFont(); + } else { + pageInterval = setInterval(delayLoadFont, 10); + } + postMessage(page.code.src); +} + +// function open(url) { +// var req = new XMLHttpRequest(); +// req.open("GET", url); +// // req.responseType = "arraybuffer"; +// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200; +// req.onreadystatechange = function() { +// postMessage("loaded"); +// if (req.readyState == 4 && req.status == req.expected) { +// var data = req.mozResponseArrayBuffer || req.mozResponse || +// req.responseArrayBuffer || req.response; +// pdfDocument = new PDFDoc(new Stream(data)); +// numPages = pdfDocument.numPages; +// // document.getElementById("numPages").innerHTML = numPages.toString(); +// // goToPage(pageNum); +// } +// }; +// req.send(null); +// } +// +// open("compressed.tracemonkey-pldi-09.pdf") \ No newline at end of file From 986ef148c47a6d5199a8962c8d07351a4630ff6a Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Tue, 21 Jun 2011 23:33:11 +0200 Subject: [PATCH 240/439] Backup work --- canvas_proxy.js | 109 +++++++++++++++++++++++++++++++++++++++++++ pdf.js | 13 +++++- viewer_worker.html | 110 +++++++++++++++++++++++++++++++++++++++++++ worker.js | 113 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 canvas_proxy.js create mode 100644 viewer_worker.html create mode 100644 worker.js diff --git a/canvas_proxy.js b/canvas_proxy.js new file mode 100644 index 000000000..1b100beae --- /dev/null +++ b/canvas_proxy.js @@ -0,0 +1,109 @@ +function CanvasProxy(width, height) { + var stack = this.$stack = []; + + // Expose only the minimum of the canvas object - there is no dom to do + // more here. + this.canvas = { + width: width, + height: height + } + + var ctxFunc = [ + "createRadialGradient", + "arcTo", + "arc", + "fillText", + "strokeText", + "drawImage", + "getImageData", + "putImageData", + "createImageData", + "drawWindow", + "save", + "restore", + "scale", + "rotate", + "translate", + "transform", + "setTransform", + "createLinearGradient", + "createPattern", + "clearRect", + "fillRect", + "strokeRect", + "beginPath", + "closePath", + "moveTo", + "lineTo", + "quadraticCurveTo", + "bezierCurveTo", + "rect", + "fill", + "stroke", + "clip", + "measureText", + "isPointInPath" + ]; + function buildFuncCall(name) { + return function() { + console.log("funcCall", name) + stack.push([name, Array.prototype.slice.call(arguments)]); + } + } + var name; + for (var i = 0; i < ctxFunc.length; i++) { + name = ctxFunc[i]; + this[name] = buildFuncCall(name); + } + + var ctxProp = { + // "canvas" + "globalAlpha": "1", + "globalCompositeOperation": "source-over", + "strokeStyle": "#000000", + "fillStyle": "#000000", + "lineWidth": "1", + "lineCap": "butt", + "lineJoin": "miter", + "miterLimit": "10", + "shadowOffsetX": "0", + "shadowOffsetY": "0", + "shadowBlur": "0", + "shadowColor": "rgba(0, 0, 0, 0)", + "font": "10px sans-serif", + "textAlign": "start", + "textBaseline": "alphabetic", + "mozTextStyle": "10px sans-serif", + "mozImageSmoothingEnabled": "true", + "DRAWWINDOW_DRAW_CARET": "1", + "DRAWWINDOW_DO_NOT_FLUSH": "2", + "DRAWWINDOW_DRAW_VIEW": "4", + "DRAWWINDOW_USE_WIDGET_LAYERS": "8", + "DRAWWINDOW_ASYNC_DECODE_IMAGES": "16", + } + + function buildGetter(name) { + return function() { + return this["$" + name]; + } + } + + function buildSetter(name) { + return function(value) { + stack.push(["$", name, value]); + return this["$" + name] = value; + } + } + + for (var name in ctxProp) { + this["$" + name] = ctxProp[name]; + this.__defineGetter__(name, buildGetter(name)); + this.__defineSetter__(name, buildSetter(name)); + } +} + +CanvasProxy.prototype.flush = function() { + postMessage("canvas_proxy_stack"); + postMessage(JSON.stringify(this.$stack)); + this.$stack.length = 0; +} diff --git a/pdf.js b/pdf.js index 326c31234..09d1c874e 100644 --- a/pdf.js +++ b/pdf.js @@ -2277,7 +2277,10 @@ var CanvasGraphics = (function() { this.pendingClip = null; this.res = null; this.xobjs = null; - this.map = { + } + + constructor.prototype = { + map: { // Graphics state w: "setLineWidth", J: "setLineCap", @@ -2634,7 +2637,9 @@ var CanvasGraphics = (function() { } var fn = Function("objpool", src); - return function (gfx) { fn.call(gfx, objpool); }; + var ret = function (gfx) { fn.call(gfx, objpool); }; + ret.src = src; + return ret; }, endDrawing: function() { @@ -3041,6 +3046,7 @@ var CanvasGraphics = (function() { shadingFill: function(entryRef) { var xref = this.xref; var res = this.res; + var shadingRes = xref.fetchIfRef(res.get("Shading")); if (!shadingRes) error("No shading resource found"); @@ -3468,6 +3474,7 @@ var ColorSpace = (function() { break; case "ICCBased": var dict = stream.dict; + this.stream = stream; this.dict = dict; this.numComps = dict.get("N"); @@ -3574,6 +3581,7 @@ var PDFFunction = (function() { v = encode[i2] + ((v - domain[i2]) * (encode[i2 + 1] - encode[i2]) / (domain[i2 + 1] - domain[i2])); + // clip to the size args[i] = clip(v, 0, size[i] - 1); } @@ -3601,6 +3609,7 @@ var PDFFunction = (function() { // decode v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) / ((1 << bps) - 1)); + // clip to the domain output.push(clip(v, range[i2], range[i2 + 1])); } diff --git a/viewer_worker.html b/viewer_worker.html new file mode 100644 index 000000000..f9e1f0b32 --- /dev/null +++ b/viewer_worker.html @@ -0,0 +1,110 @@ + + + Simple pdf.js page viewer worker + + + + + +
+ + + + + + -- + +
+ +
+ + + +
+ + + diff --git a/worker.js b/worker.js new file mode 100644 index 000000000..fdc762afd --- /dev/null +++ b/worker.js @@ -0,0 +1,113 @@ +"use strict"; + +function log() { + var args = Array.prototype.slice.call(arguments); + postMessage("log"); + postMessage(JSON.stringify(args)) +} + +var console = { + log: log +} + +importScripts("canvas_proxy.js"); +importScripts("pdf.js"); +importScripts("fonts.js"); +importScripts("glyphlist.js") + +// var array = new Uint8Array(2); +// array[0] = 1; +// array[1] = 300; +// postMessage(array); + +var timer = null; +function tic() { + timer = Date.now(); +} + +function toc(msg) { + log("Took ", (Date.now() - timer)); + timer = null; +} + + +var canvas = new CanvasProxy(1224, 1584); +// canvas.moveTo(0, 10); +// canvas.lineTo(0, 20); +// canvas.lineTo(500, 500); +// canvas.flush(); +// canvas.stroke(); +// canvas.flush(); +log("test"); + +onmessage = function(event) { + var data = event.data; + var pdfDocument = new PDFDoc(new Stream(data)); + var numPages = pdfDocument.numPages; + + tic(); + // Let's try to render the first page... + var page = pdfDocument.getPage(1); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + + var gfx = new CanvasGraphics(canvas); + page.compile(gfx, fonts); + toc("compiled page"); + + // + var fontsReady = true; + // Inspect fonts and translate the missing one + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + fontsReady = false; + } + + function delayLoadFont() { + for (var i = 0; i < count; i++) { + if (Fonts[font.name].loading) + return; + } + clearInterval(pageInterval); + page.display(gfx); + + canvas.flush(); + }; + + if (fontsReady) { + delayLoadFont(); + } else { + pageInterval = setInterval(delayLoadFont, 10); + } + postMessage(page.code.src); +} + +// function open(url) { +// var req = new XMLHttpRequest(); +// req.open("GET", url); +// // req.responseType = "arraybuffer"; +// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200; +// req.onreadystatechange = function() { +// postMessage("loaded"); +// if (req.readyState == 4 && req.status == req.expected) { +// var data = req.mozResponseArrayBuffer || req.mozResponse || +// req.responseArrayBuffer || req.response; +// pdfDocument = new PDFDoc(new Stream(data)); +// numPages = pdfDocument.numPages; +// // document.getElementById("numPages").innerHTML = numPages.toString(); +// // goToPage(pageNum); +// } +// }; +// req.send(null); +// } +// +// open("compressed.tracemonkey-pldi-09.pdf") \ No newline at end of file From a8dcb0dcd68635a41875617d33b700d4a9467e1e Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 01:28:17 +0200 Subject: [PATCH 241/439] Most working, but once you add the font-css file to the web page, there is no font drawn at all --- canvas_proxy.js | 12 +++- fonts.js | 146 +++++++++++++++++++++++++-------------------- pdf.js | 34 +++++++++-- viewer_worker.html | 95 +++++++++++++++++++++++++---- worker.js | 56 +++++++++-------- 5 files changed, 235 insertions(+), 108 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 1b100beae..433166aac 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -42,11 +42,17 @@ function CanvasProxy(width, height) { "stroke", "clip", "measureText", - "isPointInPath" + "isPointInPath", + + "$setCurrentX", + "$addCurrentX", + "$saveCurrentX", + "$restoreCurrentX", + "$showText" ]; function buildFuncCall(name) { return function() { - console.log("funcCall", name) + // console.log("funcCall", name) stack.push([name, Array.prototype.slice.call(arguments)]); } } @@ -103,6 +109,8 @@ function CanvasProxy(width, height) { } CanvasProxy.prototype.flush = function() { + // postMessage("log"); + // postMessage(JSON.stringify([this.$stack.length])); postMessage("canvas_proxy_stack"); postMessage(JSON.stringify(this.$stack)); this.$stack.length = 0; diff --git a/fonts.js b/fonts.js index d5943b7a3..8c0abbcec 100644 --- a/fonts.js +++ b/fonts.js @@ -759,91 +759,109 @@ var Font = (function () { var data = this.font; var fontName = this.name; + var isWorker = (typeof window == "undefined"); /** Hack begin */ + if (!isWorker) { - // Actually there is not event when a font has finished downloading so - // the following code are a dirty hack to 'guess' when a font is ready - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); + // Actually there is not event when a font has finished downloading so + // the following code are a dirty hack to 'guess' when a font is ready + var canvas = document.createElement("canvas"); + var style = "border: 1px solid black; position:absolute; top: " + + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; + canvas.setAttribute("style", style); + canvas.setAttribute("width", 340); + canvas.setAttribute("heigth", 100); + document.body.appendChild(canvas); - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var testString = " "; + // Get the font size canvas think it will be for 'spaces' + var ctx = canvas.getContext("2d"); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); + // When debugging use the characters provided by the charsets to visually + // see what's happening instead of 'spaces' + var debug = false; + if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; + // Retrieve font charset + var charset = Fonts[fontName].properties.charset || []; - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } + for (var i = 0; i < charset.length; i++) { + var unicode = GlyphsUnicode[charset[i]]; + if (!unicode) + continue; + testString += String.fromCharCode(unicode); + } - ctx.fillText(testString, 20, 20); - } + ctx.fillText(testString, 20, 20); + } - // Periodicaly check for the width of the testString, it will be - // different once the real font has loaded - var textWidth = ctx.measureText(testString).width; + // Periodicaly check for the width of the testString, it will be + // different once the real font has loaded + var textWidth = ctx.measureText(testString).width; - var interval = window.setInterval(function canvasInterval(self) { - this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var interval = window.setInterval(function canvasInterval(self) { + this.start = this.start || Date.now(); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - // For some reasons the font has not loaded, so mark it loaded for the - // page to proceed but cry - if ((Date.now() - this.start) >= kMaxWaitForFontFace) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); - this.start = 0; - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - this.start = 0; - } + // For some reasons the font has not loaded, so mark it loaded for the + // page to proceed but cry + if ((Date.now() - this.start) >= kMaxWaitForFontFace) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + warn("Is " + fontName + " for charset: " + charset + " loaded?"); + this.start = 0; + } else if (textWidth != ctx.measureText(testString).width) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + this.start = 0; + } - if (debug) - ctx.fillText(testString, 20, 50); - }, 30, this); + if (debug) + ctx.fillText(testString, 20, 50); + }, 30, this); + } /** Hack end */ - + // // Get the base64 encoding of the binary font data var str = ""; var length = data.length; for (var i = 0; i < length; ++i) str += String.fromCharCode(data[i]); - var base64 = window.btoa(str); + if (isWorker) { + postMessage("font"); + postMessage(JSON.stringify({ + str: str, + mimetype: this.mimetype, + fontName: fontName, + })); - // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; - var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); + setTimeout(function() { + Fonts[fontName].loading = false; + }, kMaxWaitForFontFace); + } else { + var base64 = window.btoa(str); + + // Add the @font-face rule to the document + var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + console.log("added font", fontName); + console.log(rule); + } } }; diff --git a/pdf.js b/pdf.js index 09d1c874e..80e9c1930 100644 --- a/pdf.js +++ b/pdf.js @@ -2674,12 +2674,18 @@ var CanvasGraphics = (function() { }, save: function() { this.ctx.save(); + if (this.ctx.$saveCurrentX) { + this.ctx.$saveCurrentX(); + } this.stateStack.push(this.current); this.current = new CanvasExtraState(); }, restore: function() { var prev = this.stateStack.pop(); if (prev) { + if (this.ctx.$restoreCurrentX) { + this.ctx.$restoreCurrentX(); + } this.current = prev; this.ctx.restore(); } @@ -2760,6 +2766,9 @@ var CanvasGraphics = (function() { // Text beginText: function() { this.current.textMatrix = IDENTITY_MATRIX; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2814,6 +2823,9 @@ var CanvasGraphics = (function() { moveText: function (x, y) { this.current.x = this.current.lineX += x; this.current.y = this.current.lineY += y; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(this.current.x) + } }, setLeadingMoveText: function(x, y) { this.setLeading(-y); @@ -2821,6 +2833,10 @@ var CanvasGraphics = (function() { }, setTextMatrix: function(a, b, c, d, e, f) { this.current.textMatrix = [ a, b, c, d, e, f ]; + + if (this.ctx.$setCurrentX) { + this.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2831,11 +2847,15 @@ var CanvasGraphics = (function() { this.ctx.save(); this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); - this.ctx.translate(0, -2 * this.current.y); - text = Fonts.charsToUnicode(text); - this.ctx.fillText(text, this.current.x, this.current.y); - this.current.x += this.ctx.measureText(text).width; + if (this.ctx.$showText) { + this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); + } else { + console.log(text, this.current.x); + text = Fonts.charsToUnicode(text); + this.ctx.fillText(text, 0, 0); + this.current.x += this.ctx.measureText(text).width; + } this.ctx.restore(); }, @@ -2843,7 +2863,11 @@ var CanvasGraphics = (function() { for (var i = 0; i < arr.length; ++i) { var e = arr[i]; if (IsNum(e)) { - this.current.x -= e * 0.001 * this.current.fontSize; + if (this.ctx.$addCurrentX) { + this.ctx.$addCurrentX(-e * 0.001 * this.current.fontSize) + } else { + this.current.x -= e * 0.001 * this.current.fontSize; + } } else if (IsString(e)) { this.showText(e); } else { diff --git a/viewer_worker.html b/viewer_worker.html index f9e1f0b32..dde249e55 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -11,11 +11,63 @@ var myWorker = new Worker('worker.js'); const WAIT = 0; const CANVAS_PROXY_STACK = 1; const LOG = 2; +const FONT = 3; + +var currentX = 0; +var currentXStack = []; +var special = { + "$setCurrentX": function(value) { + currentX = value; + }, + + "$addCurrentX": function(value) { + currentX += value; + }, + + "$saveCurrentX": function() { + currentXStack.push(currentX); + }, + + "$restoreCurrentX": function() { + currentX = currentXStack.pop(); + }, + + "$showText": function(y, text) { + console.log(text, currentX, y, this.measureText(text).width); + + this.translate(currentX, -1 * y); + this.fillText(text, 0, 0); + currentX += this.measureText(text).width; + } +} + +function renderProxyCanvas(stack) { + // for (var i = 0; i < stack.length; i++) { + for (var i = 0; i < 1000; i++) { + var opp = stack[i]; + if (opp[0] == "$") { + // console.log("set property", opp[1], opp[2]); + if (opp[1] == "font") { + ctx[opp[1]] = opp[2]; + // console.log("font", opp[2]); + } else { + ctx[opp[1]] = opp[2]; + } + + } else if (opp[0] in special) { + // console.log("sepcial", opp[0], opp[1]) + special[opp[0]].apply(ctx, opp[1]); + } else { + // console.log("execute", opp[0], opp[1]); + ctx[opp[0]].apply(ctx, opp[1]); + } + } +} var onMessageState = WAIT; myWorker.onmessage = function(event) { var data = event.data; - console.log("onMessageRaw", data); + // console.log("onMessageRaw", data); switch (onMessageState) { case WAIT: if (typeof data != "string") { @@ -28,11 +80,31 @@ myWorker.onmessage = function(event) { case "canvas_proxy_stack": onMessageState = CANVAS_PROXY_STACK; return; + case "font": + onMessageState = FONT; + return; default: throw "unkown state: " + data } break; + case FONT: + data = JSON.parse(data); + var base64 = window.btoa(data.str); + + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + + // ONCE you uncomment this, there is no font painted at all :( + // styleSheet.insertRule(rule, styleSheet.length); + + console.log("added font", data.fontName); + // console.log(rule); + onMessageState = WAIT; + break; + case LOG: console.log.apply(console, JSON.parse(data)); onMessageState = WAIT; @@ -40,17 +112,14 @@ myWorker.onmessage = function(event) { case CANVAS_PROXY_STACK: var stack = JSON.parse(data); - for (var i = 0; i < stack.length; i++) { - var opp = stack[i]; - if (opp[0] == "$") { - console.log("set property", opp[1], opp[2]); - ctx[opp[1]] = opp[2]; - } else { - console.log("execute", opp[0], opp[1]); - ctx[opp[0]].apply(ctx, opp[1]); - } - } + console.log("canvas stack", stack.length) + // console.log(stack.length); onMessageState = WAIT; + // return; + + setTimeout(function() { + renderProxyCanvas(stack); + }, 2000); break; } } @@ -75,6 +144,10 @@ function open(url) { window.onload = function() { var ctx = window.ctx = document.getElementById("canvas").getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); // for (var name in ctx) { // if (!(ctx[name] instanceof Function)) { // console.log('"' + name + '": "' + ctx[name] + '",'); diff --git a/worker.js b/worker.js index fdc762afd..9ee9409bd 100644 --- a/worker.js +++ b/worker.js @@ -40,6 +40,7 @@ var canvas = new CanvasProxy(1224, 1584); // canvas.flush(); log("test"); +var pageInterval; onmessage = function(event) { var data = event.data; var pdfDocument = new PDFDoc(new Stream(data)); @@ -59,36 +60,39 @@ onmessage = function(event) { // var fontsReady = true; - // Inspect fonts and translate the missing one - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } + // Inspect fonts and translate the missing one + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } + new Font(font.name, font.file, font.properties); + fontsReady = false; + } - function delayLoadFont() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) - return; - } - clearInterval(pageInterval); - page.display(gfx); + // function delayLoadFont() { + // for (var i = 0; i < count; i++) { + // if (Fonts[font.name].loading) + // return; + // } + // clearInterval(pageInterval); + // page.display(gfx); + // + // log("flush"); + // canvas.flush(); + // }; - canvas.flush(); - }; + // if (fontsReady) { + // delayLoadFont(); + // } else { + // pageInterval = setInterval(delayLoadFont, 10); + // } - if (fontsReady) { - delayLoadFont(); - } else { - pageInterval = setInterval(delayLoadFont, 10); - } - postMessage(page.code.src); + page.display(gfx); + canvas.flush(); } // function open(url) { From e15328800aad995b1a2957ba4f98f9a618a6208f Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 01:28:17 +0200 Subject: [PATCH 242/439] Most working, but once you add the font-css file to the web page, there is no font drawn at all --- canvas_proxy.js | 12 +++- fonts.js | 146 +++++++++++++++++++++++++-------------------- pdf.js | 34 +++++++++-- viewer_worker.html | 95 +++++++++++++++++++++++++---- worker.js | 56 +++++++++-------- 5 files changed, 235 insertions(+), 108 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 1b100beae..433166aac 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -42,11 +42,17 @@ function CanvasProxy(width, height) { "stroke", "clip", "measureText", - "isPointInPath" + "isPointInPath", + + "$setCurrentX", + "$addCurrentX", + "$saveCurrentX", + "$restoreCurrentX", + "$showText" ]; function buildFuncCall(name) { return function() { - console.log("funcCall", name) + // console.log("funcCall", name) stack.push([name, Array.prototype.slice.call(arguments)]); } } @@ -103,6 +109,8 @@ function CanvasProxy(width, height) { } CanvasProxy.prototype.flush = function() { + // postMessage("log"); + // postMessage(JSON.stringify([this.$stack.length])); postMessage("canvas_proxy_stack"); postMessage(JSON.stringify(this.$stack)); this.$stack.length = 0; diff --git a/fonts.js b/fonts.js index d5943b7a3..8c0abbcec 100644 --- a/fonts.js +++ b/fonts.js @@ -759,91 +759,109 @@ var Font = (function () { var data = this.font; var fontName = this.name; + var isWorker = (typeof window == "undefined"); /** Hack begin */ + if (!isWorker) { - // Actually there is not event when a font has finished downloading so - // the following code are a dirty hack to 'guess' when a font is ready - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); + // Actually there is not event when a font has finished downloading so + // the following code are a dirty hack to 'guess' when a font is ready + var canvas = document.createElement("canvas"); + var style = "border: 1px solid black; position:absolute; top: " + + (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; + canvas.setAttribute("style", style); + canvas.setAttribute("width", 340); + canvas.setAttribute("heigth", 100); + document.body.appendChild(canvas); - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var testString = " "; + // Get the font size canvas think it will be for 'spaces' + var ctx = canvas.getContext("2d"); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); + // When debugging use the characters provided by the charsets to visually + // see what's happening instead of 'spaces' + var debug = false; + if (debug) { + var name = document.createElement("font"); + name.setAttribute("style", "position: absolute; left: 20px; top: " + + (100 * fontCount + 60) + "px"); + name.innerHTML = fontName; + document.body.appendChild(name); - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; + // Retrieve font charset + var charset = Fonts[fontName].properties.charset || []; - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); + // if the charset is too small make it repeat a few times + var count = 30; + while (count-- && charset.length <= 30) + charset = charset.concat(charset.slice()); - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } + for (var i = 0; i < charset.length; i++) { + var unicode = GlyphsUnicode[charset[i]]; + if (!unicode) + continue; + testString += String.fromCharCode(unicode); + } - ctx.fillText(testString, 20, 20); - } + ctx.fillText(testString, 20, 20); + } - // Periodicaly check for the width of the testString, it will be - // different once the real font has loaded - var textWidth = ctx.measureText(testString).width; + // Periodicaly check for the width of the testString, it will be + // different once the real font has loaded + var textWidth = ctx.measureText(testString).width; - var interval = window.setInterval(function canvasInterval(self) { - this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + var interval = window.setInterval(function canvasInterval(self) { + this.start = this.start || Date.now(); + ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - // For some reasons the font has not loaded, so mark it loaded for the - // page to proceed but cry - if ((Date.now() - this.start) >= kMaxWaitForFontFace) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); - this.start = 0; - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - this.start = 0; - } + // For some reasons the font has not loaded, so mark it loaded for the + // page to proceed but cry + if ((Date.now() - this.start) >= kMaxWaitForFontFace) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + warn("Is " + fontName + " for charset: " + charset + " loaded?"); + this.start = 0; + } else if (textWidth != ctx.measureText(testString).width) { + window.clearInterval(interval); + Fonts[fontName].loading = false; + this.start = 0; + } - if (debug) - ctx.fillText(testString, 20, 50); - }, 30, this); + if (debug) + ctx.fillText(testString, 20, 50); + }, 30, this); + } /** Hack end */ - + // // Get the base64 encoding of the binary font data var str = ""; var length = data.length; for (var i = 0; i < length; ++i) str += String.fromCharCode(data[i]); - var base64 = window.btoa(str); + if (isWorker) { + postMessage("font"); + postMessage(JSON.stringify({ + str: str, + mimetype: this.mimetype, + fontName: fontName, + })); - // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; - var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); + setTimeout(function() { + Fonts[fontName].loading = false; + }, kMaxWaitForFontFace); + } else { + var base64 = window.btoa(str); + + // Add the @font-face rule to the document + var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + console.log("added font", fontName); + console.log(rule); + } } }; diff --git a/pdf.js b/pdf.js index 09d1c874e..80e9c1930 100644 --- a/pdf.js +++ b/pdf.js @@ -2674,12 +2674,18 @@ var CanvasGraphics = (function() { }, save: function() { this.ctx.save(); + if (this.ctx.$saveCurrentX) { + this.ctx.$saveCurrentX(); + } this.stateStack.push(this.current); this.current = new CanvasExtraState(); }, restore: function() { var prev = this.stateStack.pop(); if (prev) { + if (this.ctx.$restoreCurrentX) { + this.ctx.$restoreCurrentX(); + } this.current = prev; this.ctx.restore(); } @@ -2760,6 +2766,9 @@ var CanvasGraphics = (function() { // Text beginText: function() { this.current.textMatrix = IDENTITY_MATRIX; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2814,6 +2823,9 @@ var CanvasGraphics = (function() { moveText: function (x, y) { this.current.x = this.current.lineX += x; this.current.y = this.current.lineY += y; + if (this.ctx.$setCurrentX) { + this.ctx.$setCurrentX(this.current.x) + } }, setLeadingMoveText: function(x, y) { this.setLeading(-y); @@ -2821,6 +2833,10 @@ var CanvasGraphics = (function() { }, setTextMatrix: function(a, b, c, d, e, f) { this.current.textMatrix = [ a, b, c, d, e, f ]; + + if (this.ctx.$setCurrentX) { + this.$setCurrentX(0) + } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; }, @@ -2831,11 +2847,15 @@ var CanvasGraphics = (function() { this.ctx.save(); this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.scale(1, -1); - this.ctx.translate(0, -2 * this.current.y); - text = Fonts.charsToUnicode(text); - this.ctx.fillText(text, this.current.x, this.current.y); - this.current.x += this.ctx.measureText(text).width; + if (this.ctx.$showText) { + this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); + } else { + console.log(text, this.current.x); + text = Fonts.charsToUnicode(text); + this.ctx.fillText(text, 0, 0); + this.current.x += this.ctx.measureText(text).width; + } this.ctx.restore(); }, @@ -2843,7 +2863,11 @@ var CanvasGraphics = (function() { for (var i = 0; i < arr.length; ++i) { var e = arr[i]; if (IsNum(e)) { - this.current.x -= e * 0.001 * this.current.fontSize; + if (this.ctx.$addCurrentX) { + this.ctx.$addCurrentX(-e * 0.001 * this.current.fontSize) + } else { + this.current.x -= e * 0.001 * this.current.fontSize; + } } else if (IsString(e)) { this.showText(e); } else { diff --git a/viewer_worker.html b/viewer_worker.html index f9e1f0b32..dde249e55 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -11,11 +11,63 @@ var myWorker = new Worker('worker.js'); const WAIT = 0; const CANVAS_PROXY_STACK = 1; const LOG = 2; +const FONT = 3; + +var currentX = 0; +var currentXStack = []; +var special = { + "$setCurrentX": function(value) { + currentX = value; + }, + + "$addCurrentX": function(value) { + currentX += value; + }, + + "$saveCurrentX": function() { + currentXStack.push(currentX); + }, + + "$restoreCurrentX": function() { + currentX = currentXStack.pop(); + }, + + "$showText": function(y, text) { + console.log(text, currentX, y, this.measureText(text).width); + + this.translate(currentX, -1 * y); + this.fillText(text, 0, 0); + currentX += this.measureText(text).width; + } +} + +function renderProxyCanvas(stack) { + // for (var i = 0; i < stack.length; i++) { + for (var i = 0; i < 1000; i++) { + var opp = stack[i]; + if (opp[0] == "$") { + // console.log("set property", opp[1], opp[2]); + if (opp[1] == "font") { + ctx[opp[1]] = opp[2]; + // console.log("font", opp[2]); + } else { + ctx[opp[1]] = opp[2]; + } + + } else if (opp[0] in special) { + // console.log("sepcial", opp[0], opp[1]) + special[opp[0]].apply(ctx, opp[1]); + } else { + // console.log("execute", opp[0], opp[1]); + ctx[opp[0]].apply(ctx, opp[1]); + } + } +} var onMessageState = WAIT; myWorker.onmessage = function(event) { var data = event.data; - console.log("onMessageRaw", data); + // console.log("onMessageRaw", data); switch (onMessageState) { case WAIT: if (typeof data != "string") { @@ -28,11 +80,31 @@ myWorker.onmessage = function(event) { case "canvas_proxy_stack": onMessageState = CANVAS_PROXY_STACK; return; + case "font": + onMessageState = FONT; + return; default: throw "unkown state: " + data } break; + case FONT: + data = JSON.parse(data); + var base64 = window.btoa(data.str); + + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + + // ONCE you uncomment this, there is no font painted at all :( + // styleSheet.insertRule(rule, styleSheet.length); + + console.log("added font", data.fontName); + // console.log(rule); + onMessageState = WAIT; + break; + case LOG: console.log.apply(console, JSON.parse(data)); onMessageState = WAIT; @@ -40,17 +112,14 @@ myWorker.onmessage = function(event) { case CANVAS_PROXY_STACK: var stack = JSON.parse(data); - for (var i = 0; i < stack.length; i++) { - var opp = stack[i]; - if (opp[0] == "$") { - console.log("set property", opp[1], opp[2]); - ctx[opp[1]] = opp[2]; - } else { - console.log("execute", opp[0], opp[1]); - ctx[opp[0]].apply(ctx, opp[1]); - } - } + console.log("canvas stack", stack.length) + // console.log(stack.length); onMessageState = WAIT; + // return; + + setTimeout(function() { + renderProxyCanvas(stack); + }, 2000); break; } } @@ -75,6 +144,10 @@ function open(url) { window.onload = function() { var ctx = window.ctx = document.getElementById("canvas").getContext("2d"); + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); // for (var name in ctx) { // if (!(ctx[name] instanceof Function)) { // console.log('"' + name + '": "' + ctx[name] + '",'); diff --git a/worker.js b/worker.js index fdc762afd..9ee9409bd 100644 --- a/worker.js +++ b/worker.js @@ -40,6 +40,7 @@ var canvas = new CanvasProxy(1224, 1584); // canvas.flush(); log("test"); +var pageInterval; onmessage = function(event) { var data = event.data; var pdfDocument = new PDFDoc(new Stream(data)); @@ -59,36 +60,39 @@ onmessage = function(event) { // var fontsReady = true; - // Inspect fonts and translate the missing one - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } + // Inspect fonts and translate the missing one + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } + new Font(font.name, font.file, font.properties); + fontsReady = false; + } - function delayLoadFont() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) - return; - } - clearInterval(pageInterval); - page.display(gfx); + // function delayLoadFont() { + // for (var i = 0; i < count; i++) { + // if (Fonts[font.name].loading) + // return; + // } + // clearInterval(pageInterval); + // page.display(gfx); + // + // log("flush"); + // canvas.flush(); + // }; - canvas.flush(); - }; + // if (fontsReady) { + // delayLoadFont(); + // } else { + // pageInterval = setInterval(delayLoadFont, 10); + // } - if (fontsReady) { - delayLoadFont(); - } else { - pageInterval = setInterval(delayLoadFont, 10); - } - postMessage(page.code.src); + page.display(gfx); + canvas.flush(); } // function open(url) { From d9424a7135820fd902d50cadfd2150c6b6a1bdd7 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 09:15:55 +0200 Subject: [PATCH 243/439] Make fonts getting loaded by a very nasty hack --- fonts.js | 6 +----- pdf.js | 6 +++--- viewer_worker.html | 43 ++++++++++++++++++++++++++++--------------- worker.js | 2 +- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/fonts.js b/fonts.js index 8c0abbcec..c7f54edf9 100644 --- a/fonts.js +++ b/fonts.js @@ -844,13 +844,9 @@ var Font = (function () { postMessage("font"); postMessage(JSON.stringify({ str: str, - mimetype: this.mimetype, fontName: fontName, + mimetype: this.mimetype })); - - setTimeout(function() { - Fonts[fontName].loading = false; - }, kMaxWaitForFontFace); } else { var base64 = window.btoa(str); diff --git a/pdf.js b/pdf.js index 80e9c1930..64b99a33e 100644 --- a/pdf.js +++ b/pdf.js @@ -2835,7 +2835,7 @@ var CanvasGraphics = (function() { this.current.textMatrix = [ a, b, c, d, e, f ]; if (this.ctx.$setCurrentX) { - this.$setCurrentX(0) + this.ctx.$setCurrentX(0) } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; @@ -2851,9 +2851,9 @@ var CanvasGraphics = (function() { if (this.ctx.$showText) { this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); } else { - console.log(text, this.current.x); text = Fonts.charsToUnicode(text); - this.ctx.fillText(text, 0, 0); + this.ctx.translate(this.current.x, -1 * this.current.y); + this.ctx.fillText(Fonts.charsToUnicode(text), 0, 0); this.current.x += this.ctx.measureText(text).width; } diff --git a/viewer_worker.html b/viewer_worker.html index dde249e55..930fb6cd5 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -8,10 +8,6 @@ var myWorker = new Worker('worker.js'); // array[0] = 1; // array[1] = 300; // -const WAIT = 0; -const CANVAS_PROXY_STACK = 1; -const LOG = 2; -const FONT = 3; var currentX = 0; var currentXStack = []; @@ -33,7 +29,7 @@ var special = { }, "$showText": function(y, text) { - console.log(text, currentX, y, this.measureText(text).width); + // console.log(text, currentX, y, this.measureText(text).width); this.translate(currentX, -1 * y); this.fillText(text, 0, 0); @@ -41,14 +37,16 @@ var special = { } } +var gStack; function renderProxyCanvas(stack) { - // for (var i = 0; i < stack.length; i++) { - for (var i = 0; i < 1000; i++) { + for (var i = 0; i < stack.length; i++) { + // for (var i = 0; i < 1000; i++) { var opp = stack[i]; if (opp[0] == "$") { // console.log("set property", opp[1], opp[2]); if (opp[1] == "font") { ctx[opp[1]] = opp[2]; + // ctx.font = "10px 'Verdana Bold Italic'"; // console.log("font", opp[2]); } else { ctx[opp[1]] = opp[2]; @@ -64,7 +62,15 @@ function renderProxyCanvas(stack) { } } +const WAIT = 0; +const CANVAS_PROXY_STACK = 1; +const LOG = 2; +const FONT = 3; + var onMessageState = WAIT; +var fontStr = null; +var first = true; +var intervals = []; myWorker.onmessage = function(event) { var data = event.data; // console.log("onMessageRaw", data); @@ -96,12 +102,15 @@ myWorker.onmessage = function(event) { var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); - // ONCE you uncomment this, there is no font painted at all :( - // styleSheet.insertRule(rule, styleSheet.length); + // *HACK*: this makes the font get loaded on the page. WTF? We + // really have to set the fonts a few time... + var interval = setInterval(function() { + ctx.font = "bold italic 20px " + data.fontName + ", Symbol, Arial"; + }, 10); + intervals.push(interval); - console.log("added font", data.fontName); - // console.log(rule); onMessageState = WAIT; break; @@ -112,14 +121,18 @@ myWorker.onmessage = function(event) { case CANVAS_PROXY_STACK: var stack = JSON.parse(data); + gStack = stack; console.log("canvas stack", stack.length) - // console.log(stack.length); - onMessageState = WAIT; - // return; + // Shedule a timeout. Hoping the fonts are loaded after 100ms. setTimeout(function() { + // Remove all setIntervals to make the font load. + intervals.forEach(function(inter) { + clearInterval(inter); + }); renderProxyCanvas(stack); - }, 2000); + }, 100); + onMessageState = WAIT; break; } } diff --git a/worker.js b/worker.js index 9ee9409bd..6d34a9d62 100644 --- a/worker.js +++ b/worker.js @@ -48,7 +48,7 @@ onmessage = function(event) { tic(); // Let's try to render the first page... - var page = pdfDocument.getPage(1); + var page = pdfDocument.getPage(8); // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display From 61b76c7e87307b5d192712e240fe9b3c8ecfaf46 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 09:15:55 +0200 Subject: [PATCH 244/439] Make fonts getting loaded by a very nasty hack --- fonts.js | 6 +----- pdf.js | 6 +++--- viewer_worker.html | 43 ++++++++++++++++++++++++++++--------------- worker.js | 2 +- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/fonts.js b/fonts.js index 8c0abbcec..c7f54edf9 100644 --- a/fonts.js +++ b/fonts.js @@ -844,13 +844,9 @@ var Font = (function () { postMessage("font"); postMessage(JSON.stringify({ str: str, - mimetype: this.mimetype, fontName: fontName, + mimetype: this.mimetype })); - - setTimeout(function() { - Fonts[fontName].loading = false; - }, kMaxWaitForFontFace); } else { var base64 = window.btoa(str); diff --git a/pdf.js b/pdf.js index 80e9c1930..64b99a33e 100644 --- a/pdf.js +++ b/pdf.js @@ -2835,7 +2835,7 @@ var CanvasGraphics = (function() { this.current.textMatrix = [ a, b, c, d, e, f ]; if (this.ctx.$setCurrentX) { - this.$setCurrentX(0) + this.ctx.$setCurrentX(0) } this.current.x = this.current.lineX = 0; this.current.y = this.current.lineY = 0; @@ -2851,9 +2851,9 @@ var CanvasGraphics = (function() { if (this.ctx.$showText) { this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); } else { - console.log(text, this.current.x); text = Fonts.charsToUnicode(text); - this.ctx.fillText(text, 0, 0); + this.ctx.translate(this.current.x, -1 * this.current.y); + this.ctx.fillText(Fonts.charsToUnicode(text), 0, 0); this.current.x += this.ctx.measureText(text).width; } diff --git a/viewer_worker.html b/viewer_worker.html index dde249e55..930fb6cd5 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -8,10 +8,6 @@ var myWorker = new Worker('worker.js'); // array[0] = 1; // array[1] = 300; // -const WAIT = 0; -const CANVAS_PROXY_STACK = 1; -const LOG = 2; -const FONT = 3; var currentX = 0; var currentXStack = []; @@ -33,7 +29,7 @@ var special = { }, "$showText": function(y, text) { - console.log(text, currentX, y, this.measureText(text).width); + // console.log(text, currentX, y, this.measureText(text).width); this.translate(currentX, -1 * y); this.fillText(text, 0, 0); @@ -41,14 +37,16 @@ var special = { } } +var gStack; function renderProxyCanvas(stack) { - // for (var i = 0; i < stack.length; i++) { - for (var i = 0; i < 1000; i++) { + for (var i = 0; i < stack.length; i++) { + // for (var i = 0; i < 1000; i++) { var opp = stack[i]; if (opp[0] == "$") { // console.log("set property", opp[1], opp[2]); if (opp[1] == "font") { ctx[opp[1]] = opp[2]; + // ctx.font = "10px 'Verdana Bold Italic'"; // console.log("font", opp[2]); } else { ctx[opp[1]] = opp[2]; @@ -64,7 +62,15 @@ function renderProxyCanvas(stack) { } } +const WAIT = 0; +const CANVAS_PROXY_STACK = 1; +const LOG = 2; +const FONT = 3; + var onMessageState = WAIT; +var fontStr = null; +var first = true; +var intervals = []; myWorker.onmessage = function(event) { var data = event.data; // console.log("onMessageRaw", data); @@ -96,12 +102,15 @@ myWorker.onmessage = function(event) { var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); - // ONCE you uncomment this, there is no font painted at all :( - // styleSheet.insertRule(rule, styleSheet.length); + // *HACK*: this makes the font get loaded on the page. WTF? We + // really have to set the fonts a few time... + var interval = setInterval(function() { + ctx.font = "bold italic 20px " + data.fontName + ", Symbol, Arial"; + }, 10); + intervals.push(interval); - console.log("added font", data.fontName); - // console.log(rule); onMessageState = WAIT; break; @@ -112,14 +121,18 @@ myWorker.onmessage = function(event) { case CANVAS_PROXY_STACK: var stack = JSON.parse(data); + gStack = stack; console.log("canvas stack", stack.length) - // console.log(stack.length); - onMessageState = WAIT; - // return; + // Shedule a timeout. Hoping the fonts are loaded after 100ms. setTimeout(function() { + // Remove all setIntervals to make the font load. + intervals.forEach(function(inter) { + clearInterval(inter); + }); renderProxyCanvas(stack); - }, 2000); + }, 100); + onMessageState = WAIT; break; } } diff --git a/worker.js b/worker.js index 9ee9409bd..6d34a9d62 100644 --- a/worker.js +++ b/worker.js @@ -48,7 +48,7 @@ onmessage = function(event) { tic(); // Let's try to render the first page... - var page = pdfDocument.getPage(1); + var page = pdfDocument.getPage(8); // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display From b151516416cf2bc84013cb39eeb1e361701e9892 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 09:46:11 +0200 Subject: [PATCH 245/439] Introduce ImageCanvas to handle canvas rendering in WebWorker --- canvas_proxy.js | 7 ++++--- fonts.js | 2 -- pdf.js | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 433166aac..ccc95c74a 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -14,9 +14,9 @@ function CanvasProxy(width, height) { "arc", "fillText", "strokeText", - "drawImage", - "getImageData", - "putImageData", + // "drawImage", + // "getImageData", + // "putImageData", "createImageData", "drawWindow", "save", @@ -50,6 +50,7 @@ function CanvasProxy(width, height) { "$restoreCurrentX", "$showText" ]; + function buildFuncCall(name) { return function() { // console.log("funcCall", name) diff --git a/fonts.js b/fonts.js index c7f54edf9..9c9201b72 100644 --- a/fonts.js +++ b/fonts.js @@ -855,8 +855,6 @@ var Font = (function () { var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); - console.log("added font", fontName); - console.log(rule); } } }; diff --git a/pdf.js b/pdf.js index 64b99a33e..273550084 100644 --- a/pdf.js +++ b/pdf.js @@ -2269,14 +2269,32 @@ var Encodings = { } }; +function ImageCanvas(width, height) { + var tmpCanvas = this.canvas = document.createElement("canvas"); + tmpCanvas.width = width; + tmpCanvas.height = height; + + this.ctx = tmpCanvas.getContext("2d"); + this.imgData = this.ctx.getImageData(0, 0, width, height); +} + +ImageCanvas.prototype.putImageData = function(imgData) { + this.ctx.putImageData(imgData, 0, 0); +} + +ImageCanvas.prototype.getCanvas = function() { + return this.canvas; +} + var CanvasGraphics = (function() { - function constructor(canvasCtx) { + function constructor(canvasCtx, imageCanvas) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); this.stateStack = [ ]; this.pendingClip = null; this.res = null; this.xobjs = null; + this.ImageCanvas = imageCanvas || ImageCanvas; } constructor.prototype = { @@ -3009,6 +3027,7 @@ var CanvasGraphics = (function() { var tmpCanvas = document.createElement("canvas"); tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]); + console.log("tilingFill", tmpCanvas.width, tmpCanvas.height); // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext("2d"); @@ -3249,6 +3268,7 @@ var CanvasGraphics = (function() { ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, -h, w, h); this.restore(); + console.log("drawImage"); return; } @@ -3328,11 +3348,15 @@ var CanvasGraphics = (function() { // handle matte object } - var tmpCanvas = document.createElement("canvas"); - tmpCanvas.width = w; - tmpCanvas.height = h; - var tmpCtx = tmpCanvas.getContext("2d"); - var imgData = tmpCtx.getImageData(0, 0, w, h); + var tmpCanvas = new this.ImageCanvas(w, h); + // var tmpCanvas = document.createElement("canvas"); + // tmpCanvas.width = w; + // tmpCanvas.height = h; + // + // var tmpCtx = tmpCanvas.getContext("2d"); + // var imgData = tmpCtx.getImageData(0, 0, w, h); + // var pixels = imgData.data; + var imgData = tmpCanvas.imgData; var pixels = imgData.data; if (bitsPerComponent != 8) @@ -3399,8 +3423,9 @@ var CanvasGraphics = (function() { TODO("Images with "+ numComps + " components per pixel"); } } - tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, -h); + console.log("paintImageXObject", w, h); + tmpCanvas.putImageData(imgData, 0, 0); + ctx.drawImage(tmpCanvas.getCanvas(), 0, -h); this.restore(); }, From fc007b99d0edf3086445cf5d0751f6b0f003073f Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 09:46:11 +0200 Subject: [PATCH 246/439] Introduce ImageCanvas to handle canvas rendering in WebWorker --- canvas_proxy.js | 7 ++++--- fonts.js | 2 -- pdf.js | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 433166aac..ccc95c74a 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -14,9 +14,9 @@ function CanvasProxy(width, height) { "arc", "fillText", "strokeText", - "drawImage", - "getImageData", - "putImageData", + // "drawImage", + // "getImageData", + // "putImageData", "createImageData", "drawWindow", "save", @@ -50,6 +50,7 @@ function CanvasProxy(width, height) { "$restoreCurrentX", "$showText" ]; + function buildFuncCall(name) { return function() { // console.log("funcCall", name) diff --git a/fonts.js b/fonts.js index c7f54edf9..9c9201b72 100644 --- a/fonts.js +++ b/fonts.js @@ -855,8 +855,6 @@ var Font = (function () { var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); - console.log("added font", fontName); - console.log(rule); } } }; diff --git a/pdf.js b/pdf.js index 64b99a33e..273550084 100644 --- a/pdf.js +++ b/pdf.js @@ -2269,14 +2269,32 @@ var Encodings = { } }; +function ImageCanvas(width, height) { + var tmpCanvas = this.canvas = document.createElement("canvas"); + tmpCanvas.width = width; + tmpCanvas.height = height; + + this.ctx = tmpCanvas.getContext("2d"); + this.imgData = this.ctx.getImageData(0, 0, width, height); +} + +ImageCanvas.prototype.putImageData = function(imgData) { + this.ctx.putImageData(imgData, 0, 0); +} + +ImageCanvas.prototype.getCanvas = function() { + return this.canvas; +} + var CanvasGraphics = (function() { - function constructor(canvasCtx) { + function constructor(canvasCtx, imageCanvas) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); this.stateStack = [ ]; this.pendingClip = null; this.res = null; this.xobjs = null; + this.ImageCanvas = imageCanvas || ImageCanvas; } constructor.prototype = { @@ -3009,6 +3027,7 @@ var CanvasGraphics = (function() { var tmpCanvas = document.createElement("canvas"); tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]); + console.log("tilingFill", tmpCanvas.width, tmpCanvas.height); // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext("2d"); @@ -3249,6 +3268,7 @@ var CanvasGraphics = (function() { ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, -h, w, h); this.restore(); + console.log("drawImage"); return; } @@ -3328,11 +3348,15 @@ var CanvasGraphics = (function() { // handle matte object } - var tmpCanvas = document.createElement("canvas"); - tmpCanvas.width = w; - tmpCanvas.height = h; - var tmpCtx = tmpCanvas.getContext("2d"); - var imgData = tmpCtx.getImageData(0, 0, w, h); + var tmpCanvas = new this.ImageCanvas(w, h); + // var tmpCanvas = document.createElement("canvas"); + // tmpCanvas.width = w; + // tmpCanvas.height = h; + // + // var tmpCtx = tmpCanvas.getContext("2d"); + // var imgData = tmpCtx.getImageData(0, 0, w, h); + // var pixels = imgData.data; + var imgData = tmpCanvas.imgData; var pixels = imgData.data; if (bitsPerComponent != 8) @@ -3399,8 +3423,9 @@ var CanvasGraphics = (function() { TODO("Images with "+ numComps + " components per pixel"); } } - tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, -h); + console.log("paintImageXObject", w, h); + tmpCanvas.putImageData(imgData, 0, 0); + ctx.drawImage(tmpCanvas.getCanvas(), 0, -h); this.restore(); }, From d99dc718c5fd5e22a88c1c98c8cc6f02c51cfd63 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 10:40:51 +0200 Subject: [PATCH 247/439] Get working for not real images --- canvas_proxy.js | 29 +++++++++++++++++++++++++++++ viewer_worker.html | 15 ++++++++++----- worker.js | 37 +++---------------------------------- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index ccc95c74a..610cdcdba 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -1,3 +1,24 @@ +var ImageCanvasProxyCounter = 0; +function ImageCanvasProxy(width, height) { + this.id = ImageCanvasProxyCounter++; + this.width = width; + this.height = height; + + // Using `Uint8ClampedArray` seems to be the type of ImageData - at least + // Firebug tells me so. + this.imgData = { + data: Uint8ClampedArray(width * height * 4) + }; +} + +ImageCanvasProxy.prototype.putImageData = function(imgData) { + // this.ctx.putImageData(imgData, 0, 0); +} + +ImageCanvasProxy.prototype.getCanvas = function() { + return this; +} + function CanvasProxy(width, height) { var stack = this.$stack = []; @@ -51,6 +72,14 @@ function CanvasProxy(width, height) { "$showText" ]; + this.drawImage = function(canvas, x, y) { + if (canvas instanceof ImageCanvasProxy) { + stack.push(["$drawCanvas", [canvas.imgData, x, y, canvas.width, canvas.height]]); + } else { + throw "unkown type to drawImage"; + } + } + function buildFuncCall(name) { return function() { // console.log("funcCall", name) diff --git a/viewer_worker.html b/viewer_worker.html index 930fb6cd5..07623c50c 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -4,11 +4,6 @@ @@ -184,7 +214,7 @@ window.onload = function() { -- Can we use JSONP to overcome the same-origin restrictions? --> - -- diff --git a/worker.js b/worker.js index 33b34f350..dcb87a811 100644 --- a/worker.js +++ b/worker.js @@ -26,7 +26,7 @@ function tic() { } function toc(msg) { - log("Took ", (Date.now() - timer)); + log(msg + ": " + (Date.now() - timer) + "ms"); timer = null; } @@ -41,46 +41,41 @@ var canvas = new CanvasProxy(1224, 1584); log("test"); var pageInterval; - +var pdfDocument = null; onmessage = function(event) { var data = event.data; - var pdfDocument = new PDFDoc(new Stream(data)); - var numPages = pdfDocument.numPages; + if (!pdfDocument) { + pdfDocument = new PDFDoc(new Stream(data)); + postMessage("pdf_num_page"); + postMessage(pdfDocument.numPages) + return; + } else { + tic(); - tic(); - // Let's try to render the first page... - var page = pdfDocument.getPage(2); + // Let's try to render the first page... + var page = pdfDocument.getPage(parseInt(data)); - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + var gfx = new CanvasGraphics(canvas, ImageCanvasProxy); + page.compile(gfx, fonts); - var gfx = new CanvasGraphics(canvas, ImageCanvasProxy); - page.compile(gfx, fonts); - toc("compiled page"); + // Inspect fonts and translate the missing one. + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + // This "builds" the font and sents it over to the main thread. + new Font(font.name, font.file, font.properties); + } + toc("compiled page"); - page.display(gfx); - canvas.flush(); + page.display(gfx); + canvas.flush(); + } } - -// function open(url) { -// var req = new XMLHttpRequest(); -// req.open("GET", url); -// // req.responseType = "arraybuffer"; -// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200; -// req.onreadystatechange = function() { -// postMessage("loaded"); -// if (req.readyState == 4 && req.status == req.expected) { -// var data = req.mozResponseArrayBuffer || req.mozResponse || -// req.responseArrayBuffer || req.response; -// pdfDocument = new PDFDoc(new Stream(data)); -// numPages = pdfDocument.numPages; -// // document.getElementById("numPages").innerHTML = numPages.toString(); -// // goToPage(pageNum); -// } -// }; -// req.send(null); -// } -// -// open("compressed.tracemonkey-pldi-09.pdf") \ No newline at end of file From 52a117d32a1ff11f9e6810053a2988af90f62e58 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 11:08:30 +0200 Subject: [PATCH 250/439] Fixing some smaller bugs & do some cleanup. viewer_worker.html UI is now --- pdf.js | 3 +- viewer_worker.html | 84 +++++++++++++++++++++++++++++++--------------- worker.js | 67 +++++++++++++++++------------------- 3 files changed, 89 insertions(+), 65 deletions(-) diff --git a/pdf.js b/pdf.js index 273550084..61ceb602a 100644 --- a/pdf.js +++ b/pdf.js @@ -2867,7 +2867,7 @@ var CanvasGraphics = (function() { this.ctx.scale(1, -1); if (this.ctx.$showText) { - this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text)); + this.ctx.$showText(this.current.y, text, Fonts.charsToUnicode(text)); } else { text = Fonts.charsToUnicode(text); this.ctx.translate(this.current.x, -1 * this.current.y); @@ -3423,7 +3423,6 @@ var CanvasGraphics = (function() { TODO("Images with "+ numComps + " components per pixel"); } } - console.log("paintImageXObject", w, h); tmpCanvas.putImageData(imgData, 0, 0); ctx.drawImage(tmpCanvas.getCanvas(), 0, -h); this.restore(); diff --git a/viewer_worker.html b/viewer_worker.html index 07623c50c..bba694f21 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -2,6 +2,16 @@ Simple pdf.js page viewer worker @@ -184,7 +214,7 @@ window.onload = function() { -- Can we use JSONP to overcome the same-origin restrictions? --> - -- diff --git a/worker.js b/worker.js index 33b34f350..dcb87a811 100644 --- a/worker.js +++ b/worker.js @@ -26,7 +26,7 @@ function tic() { } function toc(msg) { - log("Took ", (Date.now() - timer)); + log(msg + ": " + (Date.now() - timer) + "ms"); timer = null; } @@ -41,46 +41,41 @@ var canvas = new CanvasProxy(1224, 1584); log("test"); var pageInterval; - +var pdfDocument = null; onmessage = function(event) { var data = event.data; - var pdfDocument = new PDFDoc(new Stream(data)); - var numPages = pdfDocument.numPages; + if (!pdfDocument) { + pdfDocument = new PDFDoc(new Stream(data)); + postMessage("pdf_num_page"); + postMessage(pdfDocument.numPages) + return; + } else { + tic(); - tic(); - // Let's try to render the first page... - var page = pdfDocument.getPage(2); + // Let's try to render the first page... + var page = pdfDocument.getPage(parseInt(data)); - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + var gfx = new CanvasGraphics(canvas, ImageCanvasProxy); + page.compile(gfx, fonts); - var gfx = new CanvasGraphics(canvas, ImageCanvasProxy); - page.compile(gfx, fonts); - toc("compiled page"); + // Inspect fonts and translate the missing one. + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } + // This "builds" the font and sents it over to the main thread. + new Font(font.name, font.file, font.properties); + } + toc("compiled page"); - page.display(gfx); - canvas.flush(); + page.display(gfx); + canvas.flush(); + } } - -// function open(url) { -// var req = new XMLHttpRequest(); -// req.open("GET", url); -// // req.responseType = "arraybuffer"; -// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200; -// req.onreadystatechange = function() { -// postMessage("loaded"); -// if (req.readyState == 4 && req.status == req.expected) { -// var data = req.mozResponseArrayBuffer || req.mozResponse || -// req.responseArrayBuffer || req.response; -// pdfDocument = new PDFDoc(new Stream(data)); -// numPages = pdfDocument.numPages; -// // document.getElementById("numPages").innerHTML = numPages.toString(); -// // goToPage(pageNum); -// } -// }; -// req.send(null); -// } -// -// open("compressed.tracemonkey-pldi-09.pdf") \ No newline at end of file From ddd8aeffb9483b8ccc1f236052e55714a93b69bb Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 13:19:25 +0200 Subject: [PATCH 251/439] Fix font loading issue by using a hidden DOM font node --- viewer_worker.html | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/viewer_worker.html b/viewer_worker.html index bba694f21..ced71679e 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -118,12 +118,10 @@ myWorker.onmessage = function(event) { var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); - // *HACK*: this makes the font get loaded on the page. WTF? We - // really have to set the fonts a few time... - var interval = setInterval(function() { - ctx.font = "bold italic 20px " + data.fontName + ", Symbol, Arial"; - }, 10); - intervals.push(interval); + // Just adding the font-face to the DOM doesn't make it load. It + // seems it's loaded once Gecko notices it's used. Therefore, + // add a div on the page using the loaded font. + document.getElementById("fonts").innerHTML += "
j
"; console.log("setup font", data.fontName); onMessageState = WAIT; @@ -139,16 +137,13 @@ myWorker.onmessage = function(event) { gStack = stack; console.log("canvas stack size", stack.length) - // Shedule a timeout. Hoping the fonts are loaded after 100ms. + // There might be fonts that need to get loaded. Shedule the + // rendering at the end of the event queue ensures this. setTimeout(function() { - // Remove all setIntervals to make the font load. - intervals.forEach(function(inter) { - clearInterval(inter); - }); tic(); renderProxyCanvas(stack); toc("canvas rendering") - }, 100); + }, 0); onMessageState = WAIT; break; } @@ -208,6 +203,7 @@ window.onload = function() { +
- - - Previous + + -- diff --git a/worker.js b/worker.js index e59e37155..09e2b8145 100644 --- a/worker.js +++ b/worker.js @@ -1,15 +1,26 @@ "use strict"; +var timer = null; +function tic() { + timer = Date.now(); +} + +function toc(msg) { + log(msg + ": " + (Date.now() - timer) + "ms"); + timer = null; +} + function log() { - var args = Array.prototype.slice.call(arguments); - postMessage("log"); - postMessage(JSON.stringify(args)) + var args = Array.prototype.slice.call(arguments); + postMessage("log"); + postMessage(JSON.stringify(args)) } var console = { - log: log + log: log } +// importScripts("canvas_proxy.js"); importScripts("pdf.js"); importScripts("fonts.js"); @@ -18,55 +29,50 @@ importScripts("glyphlist.js") // Use the JpegStreamProxy proxy. JpegStream = JpegStreamProxy; -var timer = null; -function tic() { - timer = Date.now(); -} - -function toc(msg) { - log(msg + ": " + (Date.now() - timer) + "ms"); - timer = null; -} - // Create the WebWorkerProxyCanvas. var canvas = new CanvasProxy(1224, 1584); -var pageInterval; +// Listen for messages from the main thread. var pdfDocument = null; onmessage = function(event) { - var data = event.data; - if (!pdfDocument) { - pdfDocument = new PDFDoc(new Stream(data)); - postMessage("pdf_num_page"); - postMessage(pdfDocument.numPages) - return; - } else { - tic(); + var data = event.data; + // If there is no pdfDocument yet, then the sent data is the PDFDocument. + if (!pdfDocument) { + pdfDocument = new PDFDoc(new Stream(data)); + postMessage("pdf_num_page"); + postMessage(pdfDocument.numPages) + return; + } + // User requested to render a certain page. + else { + tic(); - // Let's try to render the first page... - var page = pdfDocument.getPage(parseInt(data)); + // Let's try to render the first page... + var page = pdfDocument.getPage(parseInt(data)); - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; - var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); - page.compile(gfx, fonts); + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); + page.compile(gfx, fonts); - // Inspect fonts and translate the missing one. - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } + // Inspect fonts and translate the missing one. + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } - // This "builds" the font and sents it over to the main thread. - new Font(font.name, font.file, font.properties); - } - toc("compiled page"); - - page.display(gfx); - canvas.flush(); + // This "builds" the font and sents it over to the main thread. + new Font(font.name, font.file, font.properties); } + toc("compiled page"); + + tic() + page.display(gfx); + canvas.flush(); + toc("displayed page"); + } } diff --git a/worker_client.js b/worker_client.js new file mode 100644 index 000000000..316ef1fc0 --- /dev/null +++ b/worker_client.js @@ -0,0 +1,294 @@ +"use strict"; + +function WorkerPDFDoc(canvas) { + var timer = null + function tic() { + timer = Date.now(); + } + + function toc(msg) { + console.log(msg + ": " + (Date.now() - timer) + "ms"); + } + + this.ctx = canvas.getContext("2d"); + this.canvas = canvas; + this.worker = new Worker('worker.js'); + + this.numPage = 1; + this.numPages = null; + + var imagesList = {}; + var canvasList = { + 0: canvas + }; + var patternList = {}; + var gradient; + + var currentX = 0; + var currentXStack = []; + + var ctxSpecial = { + "$setCurrentX": function(value) { + currentX = value; + }, + + "$addCurrentX": function(value) { + currentX += value; + }, + + "$saveCurrentX": function() { + currentXStack.push(currentX); + }, + + "$restoreCurrentX": function() { + currentX = currentXStack.pop(); + }, + + "$showText": function(y, text, uniText) { + this.translate(currentX, -1 * y); + this.fillText(uniText, 0, 0); + currentX += this.measureText(text).width; + }, + + "$putImageData": function(imageData, x, y) { + var imgData = this.getImageData(0, 0, imageData.width, imageData.height); + + // Store the .data property to avaid property lookups. + var imageRealData = imageData.data; + var imgRealData = imgData.data; + + // Copy over the imageData. + var len = imageRealData.length; + while (len--) + imgRealData[len] = imageRealData[len] + + this.putImageData(imgData, x, y); + }, + + "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { + var image = imagesList[id]; + if (!image) { + throw "Image not found"; + } + this.drawImage(image, x, y, image.width, image.height, + sx, sy, swidth, sheight); + }, + + "$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) { + var canvas = canvasList[id]; + if (!canvas) { + throw "Canvas not found"; + } + if (sheight != null) { + this.drawImage(canvas, x, y, canvas.width, canvas.height, + sx, sy, swidth, sheight); + } else { + this.drawImage(canvas, x, y, canvas.width, canvas.height); + } + }, + + "$createLinearGradient": function(x0, y0, x1, y1) { + gradient = this.createLinearGradient(x0, y0, x1, y1); + }, + + "$createPatternFromCanvas": function(patternId, canvasId, kind) { + var canvas = canvasList[canvasId]; + if (!canvas) { + throw "Canvas not found"; + } + patternList[patternId] = this.createPattern(canvas, kind); + }, + + "$addColorStop": function(i, rgba) { + gradient.addColorStop(i, rgba); + }, + + "$fillStyleGradient": function() { + this.fillStyle = gradient; + }, + + "$fillStylePattern": function(id) { + var pattern = patternList[id]; + if (!pattern) { + throw "Pattern not found"; + } + this.fillStyle = pattern; + }, + + "$strokeStyleGradient": function() { + this.strokeStyle = gradient; + }, + + "$strokeStylePattern": function(id) { + var pattern = patternList[id]; + if (!pattern) { + throw "Pattern not found"; + } + this.strokeStyle = pattern; + } + } + + function renderProxyCanvas(canvas, stack) { + var ctx = canvas.getContext("2d"); + for (var i = 0; i < stack.length; i++) { + var opp = stack[i]; + if (opp[0] == "$") { + ctx[opp[1]] = opp[2]; + } else if (opp[0] in ctxSpecial) { + ctxSpecial[opp[0]].apply(ctx, opp[1]); + } else { + ctx[opp[0]].apply(ctx, opp[1]); + } + } + } + + /** + * onMessage state machine. + */ + const WAIT = 0; + const CANVAS_PROXY_STACK = 1; + const LOG = 2; + const FONT = 3; + const PDF_NUM_PAGE = 4; + const JPEG_STREAM = 5; + + var onMessageState = WAIT; + this.worker.onmessage = function(event) { + var data = event.data; + // console.log("onMessageRaw", data); + switch (onMessageState) { + case WAIT: + if (typeof data != "string") { + throw "expecting to get an string"; + } + switch (data) { + case "pdf_num_page": + onMessageState = PDF_NUM_PAGE; + return; + + case "log": + onMessageState = LOG; + return; + + case "canvas_proxy_stack": + onMessageState = CANVAS_PROXY_STACK; + return; + + case "font": + onMessageState = FONT; + return; + + case "jpeg_stream": + onMessageState = JPEG_STREAM; + return; + + default: + throw "unkown state: " + data + } + break; + + case JPEG_STREAM: + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(data.str); + imagesList[data.id] = img; + console.log("got image", data.id) + break; + + case PDF_NUM_PAGE: + this.numPages = parseInt(data); + if (this.loadCallback) { + this.loadCallback(); + } + onMessageState = WAIT; + break; + + case FONT: + data = JSON.parse(data); + var base64 = window.btoa(data.str); + + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + + // Just adding the font-face to the DOM doesn't make it load. It + // seems it's loaded once Gecko notices it's used. Therefore, + // add a div on the page using the loaded font. + document.getElementById("fonts").innerHTML += "
j
"; + + onMessageState = WAIT; + break; + + case LOG: + console.log.apply(console, JSON.parse(data)); + onMessageState = WAIT; + break; + + case CANVAS_PROXY_STACK: + var id = data.id; + var stack = data.stack; + + // Check if there is already a canvas with the given id. If not, + // create a new canvas. + if (!canvasList[id]) { + var newCanvas = document.createElement("canvas"); + newCanvas.width = data.width; + newCanvas.height = data.height; + canvasList[id] = newCanvas; + } + + // There might be fonts that need to get loaded. Shedule the + // rendering at the end of the event queue ensures this. + setTimeout(function() { + if (id == 0) tic(); + renderProxyCanvas(canvasList[id], stack); + if (id == 0) toc("canvas rendering") + }, 0); + onMessageState = WAIT; + break; + } + }.bind(this); +} + + WorkerPDFDoc.prototype.open = function(url, callback) { + var req = new XMLHttpRequest(); + req.open("GET", url); + req.mozResponseType = req.responseType = "arraybuffer"; + req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState == 4 && req.status == req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || + req.responseArrayBuffer || req.response; + + this.loadCallback = callback; + this.worker.postMessage(data); + this.showPage(this.numPage); + } + }.bind(this); + req.send(null); +} + +WorkerPDFDoc.prototype.showPage = function(numPage) { + var ctx = this.ctx; + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + this.numPage = parseInt(numPage); + this.worker.postMessage(numPage); + if (this.onChangePage) { + this.onChangePage(numPage); + } +} + +WorkerPDFDoc.prototype.nextPage = function() { + if (this.numPage == this.numPages) return; + this.showPage(++this.numPage); +} + +WorkerPDFDoc.prototype.prevPage = function() { + if (this.numPage == 1) return; + this.showPage(--this.numPage); +} From 4281f799e5926d7087da69809d48ebe2ecfc7425 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 22 Jun 2011 22:54:16 +0200 Subject: [PATCH 268/439] Move client code into worker_client.js. Cleanup + comments + 2-space-indention --- canvas_proxy.js | 399 +++++++++++++++++++++------------------------ viewer_worker.html | 299 ++------------------------------- worker.js | 96 ++++++----- worker_client.js | 294 +++++++++++++++++++++++++++++++++ 4 files changed, 547 insertions(+), 541 deletions(-) create mode 100644 worker_client.js diff --git a/canvas_proxy.js b/canvas_proxy.js index 07ae31a63..83b57682f 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -1,260 +1,239 @@ -// var ImageCanvasProxyCounter = 0; -// function ImageCanvasProxy(width, height) { -// this.id = ImageCanvasProxyCounter++; -// this.width = width; -// this.height = height; -// -// // Using `Uint8ClampedArray` seems to be the type of ImageData - at least -// // Firebug tells me so. -// this.imgData = { -// data: Uint8ClampedArray(width * height * 4) -// }; -// } -// -// ImageCanvasProxy.prototype.putImageData = function(imgData) { -// // this.ctx.putImageData(imgData, 0, 0); -// } -// -// ImageCanvasProxy.prototype.getCanvas = function() { -// return this; -// } var JpegStreamProxyCounter = 0; // WebWorker Proxy for JpegStream. var JpegStreamProxy = (function() { - function constructor(bytes, dict) { - this.id = JpegStreamProxyCounter++; - this.dict = dict; + function constructor(bytes, dict) { + this.id = JpegStreamProxyCounter++; + this.dict = dict; - // create DOM image. - postMessage("jpeg_stream"); - postMessage({ - id: this.id, - str: bytesToString(bytes) - }); + // Tell the main thread to create an image. + postMessage("jpeg_stream"); + postMessage({ + id: this.id, + str: bytesToString(bytes) + }); + } - // var img = new Image(); - // img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); - // this.domImage = img; + constructor.prototype = { + getImage: function() { + return this; + }, + getChar: function() { + error("internal error: getChar is not valid on JpegStream"); } + }; - constructor.prototype = { - getImage: function() { - return this; - // return this.domImage; - }, - getChar: function() { - error("internal error: getChar is not valid on JpegStream"); - } - }; - - return constructor; + return constructor; })(); // Really simple GradientProxy. There is currently only one active gradient at // the time, meaning you can't create a gradient, create a second one and then // use the first one again. As this isn't used in pdf.js right now, it's okay. function GradientProxy(stack, x0, y0, x1, y1) { - stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); - this.addColorStop = function(i, rgba) { - stack.push(["$addColorStop", [i, rgba]]); - } + stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); + this.addColorStop = function(i, rgba) { + stack.push(["$addColorStop", [i, rgba]]); + } } +// Really simple PatternProxy. var patternProxyCounter = 0; function PatternProxy(stack, object, kind) { - this.id = patternProxyCounter++; + this.id = patternProxyCounter++; - if (!(object instanceof CanvasProxy) ) { - throw "unkown type to createPattern"; - } - // Flush the object here to ensure it's available on the main thread. - // TODO: Make some kind of dependency management, such that the object - // gets flushed only if needed. - object.flush(); - stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); + if (!(object instanceof CanvasProxy) ) { + throw "unkown type to createPattern"; + } + + // Flush the object here to ensure it's available on the main thread. + // TODO: Make some kind of dependency management, such that the object + // gets flushed only if needed. + object.flush(); + stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); } var canvasProxyCounter = 0; function CanvasProxy(width, height) { - this.id = canvasProxyCounter++; + this.id = canvasProxyCounter++; - var stack = this.$stack = []; + // The `stack` holds the rendering calls and gets flushed to the main thead. + var stack = this.$stack = []; - // Dummy context exposed. - var ctx = {}; - this.getContext = function(type) { - if (type != "2d") { - throw "CanvasProxy can only provide a 2d context."; - } - return ctx; + // Dummy context that gets exposed. + var ctx = {}; + this.getContext = function(type) { + if (type != "2d") { + throw "CanvasProxy can only provide a 2d context."; } + return ctx; + } - // Expose only the minimum of the canvas object - there is no dom to do - // more here. - this.width = width; - this.height = height; - ctx.canvas = this; + // Expose only the minimum of the canvas object - there is no dom to do + // more here. + this.width = width; + this.height = height; + ctx.canvas = this; - var ctxFunc = [ - "createRadialGradient", - "arcTo", - "arc", - "fillText", - "strokeText", - // "drawImage", - // "getImageData", - // "putImageData", - "createImageData", - "drawWindow", - "save", - "restore", - "scale", - "rotate", - "translate", - "transform", - "setTransform", - // "createLinearGradient", - // "createPattern", - "clearRect", - "fillRect", - "strokeRect", - "beginPath", - "closePath", - "moveTo", - "lineTo", - "quadraticCurveTo", - "bezierCurveTo", - "rect", - "fill", - "stroke", - "clip", - "measureText", - "isPointInPath", + // Setup function calls to `ctx`. + var ctxFunc = [ + "createRadialGradient", + "arcTo", + "arc", + "fillText", + "strokeText", + "createImageData", + "drawWindow", + "save", + "restore", + "scale", + "rotate", + "translate", + "transform", + "setTransform", + "clearRect", + "fillRect", + "strokeRect", + "beginPath", + "closePath", + "moveTo", + "lineTo", + "quadraticCurveTo", + "bezierCurveTo", + "rect", + "fill", + "stroke", + "clip", + "measureText", + "isPointInPath", - "$setCurrentX", - "$addCurrentX", - "$saveCurrentX", - "$restoreCurrentX", - "$showText" - ]; + // These functions are necessary to track the rendering currentX state. + // The exact values can be computed on the main thread only, as the + // worker has no idea about text width. + "$setCurrentX", + "$addCurrentX", + "$saveCurrentX", + "$restoreCurrentX", + "$showText" + ]; - ctx.createPattern = function(object, kind) { - return new PatternProxy(stack, object, kind); + function buildFuncCall(name) { + return function() { + // console.log("funcCall", name) + stack.push([name, Array.prototype.slice.call(arguments)]); } + } + var name; + for (var i = 0; i < ctxFunc.length; i++) { + name = ctxFunc[i]; + ctx[name] = buildFuncCall(name); + } - ctx.createLinearGradient = function(x0, y0, x1, y1) { - return new GradientProxy(stack, x0, y0, x1, y1); - } + // Some function calls that need more work. - ctx.getImageData = function(x, y, w, h) { - return { - width: w, - height: h, - data: Uint8ClampedArray(w * h * 4) - }; - } + ctx.createPattern = function(object, kind) { + return new PatternProxy(stack, object, kind); + } - ctx.putImageData = function(data, x, y, width, height) { - stack.push(["$putImageData", [data, x, y, width, height]]); - } + ctx.createLinearGradient = function(x0, y0, x1, y1) { + return new GradientProxy(stack, x0, y0, x1, y1); + } - ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { - if (image instanceof CanvasProxy) { - // Send the image/CanvasProxy to the main thread. - image.flush(); - stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); - } else if(image instanceof JpegStreamProxy) { - stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) - } else { - throw "unkown type to drawImage"; - } - } + ctx.getImageData = function(x, y, w, h) { + return { + width: w, + height: h, + data: Uint8ClampedArray(w * h * 4) + }; + } - function buildFuncCall(name) { - return function() { - // console.log("funcCall", name) - stack.push([name, Array.prototype.slice.call(arguments)]); - } - } - var name; - for (var i = 0; i < ctxFunc.length; i++) { - name = ctxFunc[i]; - ctx[name] = buildFuncCall(name); - } + ctx.putImageData = function(data, x, y, width, height) { + stack.push(["$putImageData", [data, x, y, width, height]]); + } - var ctxProp = { - // "canvas" - "globalAlpha": "1", - "globalCompositeOperation": "source-over", - "strokeStyle": "#000000", - "fillStyle": "#000000", - "lineWidth": "1", - "lineCap": "butt", - "lineJoin": "miter", - "miterLimit": "10", - "shadowOffsetX": "0", - "shadowOffsetY": "0", - "shadowBlur": "0", - "shadowColor": "rgba(0, 0, 0, 0)", - "font": "10px sans-serif", - "textAlign": "start", - "textBaseline": "alphabetic", - "mozTextStyle": "10px sans-serif", - "mozImageSmoothingEnabled": "true", - "DRAWWINDOW_DRAW_CARET": "1", - "DRAWWINDOW_DO_NOT_FLUSH": "2", - "DRAWWINDOW_DRAW_VIEW": "4", - "DRAWWINDOW_USE_WIDGET_LAYERS": "8", - "DRAWWINDOW_ASYNC_DECODE_IMAGES": "16", + ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { + if (image instanceof CanvasProxy) { + // Send the image/CanvasProxy to the main thread. + image.flush(); + stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); + } else if(image instanceof JpegStreamProxy) { + stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) + } else { + throw "unkown type to drawImage"; } + } - function buildGetter(name) { - return function() { - return ctx["$" + name]; - } + // Setup property access to `ctx`. + var ctxProp = { + // "canvas" + "globalAlpha": "1", + "globalCompositeOperation": "source-over", + "strokeStyle": "#000000", + "fillStyle": "#000000", + "lineWidth": "1", + "lineCap": "butt", + "lineJoin": "miter", + "miterLimit": "10", + "shadowOffsetX": "0", + "shadowOffsetY": "0", + "shadowBlur": "0", + "shadowColor": "rgba(0, 0, 0, 0)", + "font": "10px sans-serif", + "textAlign": "start", + "textBaseline": "alphabetic", + "mozTextStyle": "10px sans-serif", + "mozImageSmoothingEnabled": "true" + } + + function buildGetter(name) { + return function() { + return ctx["$" + name]; } + } - function buildSetter(name) { + function buildSetter(name) { + return function(value) { + stack.push(["$", name, value]); + return ctx["$" + name] = value; + } + } + + for (var name in ctxProp) { + ctx["$" + name] = ctxProp[name]; + ctx.__defineGetter__(name, buildGetter(name)); + + // Special treatment for `fillStyle` and `strokeStyle`: The passed style + // might be a gradient. Need to check for that. + if (name == "fillStyle" || name == "strokeStyle") { + function buildSetterStyle(name) { return function(value) { + if (value instanceof GradientProxy) { + stack.push(["$" + name + "Gradient"]); + } else if (value instanceof PatternProxy) { + stack.push(["$" + name + "Pattern", [value.id]]); + } else { stack.push(["$", name, value]); return ctx["$" + name] = value; + } } + } + ctx.__defineSetter__(name, buildSetterStyle(name)); + } else { + ctx.__defineSetter__(name, buildSetter(name)); } - - for (var name in ctxProp) { - ctx["$" + name] = ctxProp[name]; - ctx.__defineGetter__(name, buildGetter(name)); - - // Special treatment for `fillStyle` and `strokeStyle`: The passed style - // might be a gradient. Need to check for that. - if (name == "fillStyle" || name == "strokeStyle") { - function buildSetterStyle(name) { - return function(value) { - if (value instanceof GradientProxy) { - stack.push(["$" + name + "Gradient"]); - } else if (value instanceof PatternProxy) { - stack.push(["$" + name + "Pattern", [value.id]]); - } else { - stack.push(["$", name, value]); - return ctx["$" + name] = value; - } - } - } - ctx.__defineSetter__(name, buildSetterStyle(name)); - } else { - ctx.__defineSetter__(name, buildSetter(name)); - } - } + } } +/** +* Sends the current stack of the CanvasProxy over to the main thread and +* resets the stack. +*/ CanvasProxy.prototype.flush = function() { - postMessage("canvas_proxy_stack"); - postMessage({ - id: this.id, - stack: this.$stack, - width: this.width, - height: this.height - }); - this.$stack.length = 0; + postMessage("canvas_proxy_stack"); + postMessage({ + id: this.id, + stack: this.$stack, + width: this.width, + height: this.height + }); + this.$stack.length = 0; } diff --git a/viewer_worker.html b/viewer_worker.html index 92806bc99..a9f08388f 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -1,295 +1,22 @@ Simple pdf.js page viewer worker + @@ -301,9 +28,9 @@ window.onload = function() { - - - Previous + + -- diff --git a/worker.js b/worker.js index e59e37155..09e2b8145 100644 --- a/worker.js +++ b/worker.js @@ -1,15 +1,26 @@ "use strict"; +var timer = null; +function tic() { + timer = Date.now(); +} + +function toc(msg) { + log(msg + ": " + (Date.now() - timer) + "ms"); + timer = null; +} + function log() { - var args = Array.prototype.slice.call(arguments); - postMessage("log"); - postMessage(JSON.stringify(args)) + var args = Array.prototype.slice.call(arguments); + postMessage("log"); + postMessage(JSON.stringify(args)) } var console = { - log: log + log: log } +// importScripts("canvas_proxy.js"); importScripts("pdf.js"); importScripts("fonts.js"); @@ -18,55 +29,50 @@ importScripts("glyphlist.js") // Use the JpegStreamProxy proxy. JpegStream = JpegStreamProxy; -var timer = null; -function tic() { - timer = Date.now(); -} - -function toc(msg) { - log(msg + ": " + (Date.now() - timer) + "ms"); - timer = null; -} - // Create the WebWorkerProxyCanvas. var canvas = new CanvasProxy(1224, 1584); -var pageInterval; +// Listen for messages from the main thread. var pdfDocument = null; onmessage = function(event) { - var data = event.data; - if (!pdfDocument) { - pdfDocument = new PDFDoc(new Stream(data)); - postMessage("pdf_num_page"); - postMessage(pdfDocument.numPages) - return; - } else { - tic(); + var data = event.data; + // If there is no pdfDocument yet, then the sent data is the PDFDocument. + if (!pdfDocument) { + pdfDocument = new PDFDoc(new Stream(data)); + postMessage("pdf_num_page"); + postMessage(pdfDocument.numPages) + return; + } + // User requested to render a certain page. + else { + tic(); - // Let's try to render the first page... - var page = pdfDocument.getPage(parseInt(data)); + // Let's try to render the first page... + var page = pdfDocument.getPage(parseInt(data)); - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - var fonts = []; - var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); - page.compile(gfx, fonts); + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); + page.compile(gfx, fonts); - // Inspect fonts and translate the missing one. - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } + // Inspect fonts and translate the missing one. + var count = fonts.length; + for (var i = 0; i < count; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + fontsReady = fontsReady && !Fonts[font.name].loading; + continue; + } - // This "builds" the font and sents it over to the main thread. - new Font(font.name, font.file, font.properties); - } - toc("compiled page"); - - page.display(gfx); - canvas.flush(); + // This "builds" the font and sents it over to the main thread. + new Font(font.name, font.file, font.properties); } + toc("compiled page"); + + tic() + page.display(gfx); + canvas.flush(); + toc("displayed page"); + } } diff --git a/worker_client.js b/worker_client.js new file mode 100644 index 000000000..316ef1fc0 --- /dev/null +++ b/worker_client.js @@ -0,0 +1,294 @@ +"use strict"; + +function WorkerPDFDoc(canvas) { + var timer = null + function tic() { + timer = Date.now(); + } + + function toc(msg) { + console.log(msg + ": " + (Date.now() - timer) + "ms"); + } + + this.ctx = canvas.getContext("2d"); + this.canvas = canvas; + this.worker = new Worker('worker.js'); + + this.numPage = 1; + this.numPages = null; + + var imagesList = {}; + var canvasList = { + 0: canvas + }; + var patternList = {}; + var gradient; + + var currentX = 0; + var currentXStack = []; + + var ctxSpecial = { + "$setCurrentX": function(value) { + currentX = value; + }, + + "$addCurrentX": function(value) { + currentX += value; + }, + + "$saveCurrentX": function() { + currentXStack.push(currentX); + }, + + "$restoreCurrentX": function() { + currentX = currentXStack.pop(); + }, + + "$showText": function(y, text, uniText) { + this.translate(currentX, -1 * y); + this.fillText(uniText, 0, 0); + currentX += this.measureText(text).width; + }, + + "$putImageData": function(imageData, x, y) { + var imgData = this.getImageData(0, 0, imageData.width, imageData.height); + + // Store the .data property to avaid property lookups. + var imageRealData = imageData.data; + var imgRealData = imgData.data; + + // Copy over the imageData. + var len = imageRealData.length; + while (len--) + imgRealData[len] = imageRealData[len] + + this.putImageData(imgData, x, y); + }, + + "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { + var image = imagesList[id]; + if (!image) { + throw "Image not found"; + } + this.drawImage(image, x, y, image.width, image.height, + sx, sy, swidth, sheight); + }, + + "$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) { + var canvas = canvasList[id]; + if (!canvas) { + throw "Canvas not found"; + } + if (sheight != null) { + this.drawImage(canvas, x, y, canvas.width, canvas.height, + sx, sy, swidth, sheight); + } else { + this.drawImage(canvas, x, y, canvas.width, canvas.height); + } + }, + + "$createLinearGradient": function(x0, y0, x1, y1) { + gradient = this.createLinearGradient(x0, y0, x1, y1); + }, + + "$createPatternFromCanvas": function(patternId, canvasId, kind) { + var canvas = canvasList[canvasId]; + if (!canvas) { + throw "Canvas not found"; + } + patternList[patternId] = this.createPattern(canvas, kind); + }, + + "$addColorStop": function(i, rgba) { + gradient.addColorStop(i, rgba); + }, + + "$fillStyleGradient": function() { + this.fillStyle = gradient; + }, + + "$fillStylePattern": function(id) { + var pattern = patternList[id]; + if (!pattern) { + throw "Pattern not found"; + } + this.fillStyle = pattern; + }, + + "$strokeStyleGradient": function() { + this.strokeStyle = gradient; + }, + + "$strokeStylePattern": function(id) { + var pattern = patternList[id]; + if (!pattern) { + throw "Pattern not found"; + } + this.strokeStyle = pattern; + } + } + + function renderProxyCanvas(canvas, stack) { + var ctx = canvas.getContext("2d"); + for (var i = 0; i < stack.length; i++) { + var opp = stack[i]; + if (opp[0] == "$") { + ctx[opp[1]] = opp[2]; + } else if (opp[0] in ctxSpecial) { + ctxSpecial[opp[0]].apply(ctx, opp[1]); + } else { + ctx[opp[0]].apply(ctx, opp[1]); + } + } + } + + /** + * onMessage state machine. + */ + const WAIT = 0; + const CANVAS_PROXY_STACK = 1; + const LOG = 2; + const FONT = 3; + const PDF_NUM_PAGE = 4; + const JPEG_STREAM = 5; + + var onMessageState = WAIT; + this.worker.onmessage = function(event) { + var data = event.data; + // console.log("onMessageRaw", data); + switch (onMessageState) { + case WAIT: + if (typeof data != "string") { + throw "expecting to get an string"; + } + switch (data) { + case "pdf_num_page": + onMessageState = PDF_NUM_PAGE; + return; + + case "log": + onMessageState = LOG; + return; + + case "canvas_proxy_stack": + onMessageState = CANVAS_PROXY_STACK; + return; + + case "font": + onMessageState = FONT; + return; + + case "jpeg_stream": + onMessageState = JPEG_STREAM; + return; + + default: + throw "unkown state: " + data + } + break; + + case JPEG_STREAM: + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(data.str); + imagesList[data.id] = img; + console.log("got image", data.id) + break; + + case PDF_NUM_PAGE: + this.numPages = parseInt(data); + if (this.loadCallback) { + this.loadCallback(); + } + onMessageState = WAIT; + break; + + case FONT: + data = JSON.parse(data); + var base64 = window.btoa(data.str); + + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); + + // Just adding the font-face to the DOM doesn't make it load. It + // seems it's loaded once Gecko notices it's used. Therefore, + // add a div on the page using the loaded font. + document.getElementById("fonts").innerHTML += "
j
"; + + onMessageState = WAIT; + break; + + case LOG: + console.log.apply(console, JSON.parse(data)); + onMessageState = WAIT; + break; + + case CANVAS_PROXY_STACK: + var id = data.id; + var stack = data.stack; + + // Check if there is already a canvas with the given id. If not, + // create a new canvas. + if (!canvasList[id]) { + var newCanvas = document.createElement("canvas"); + newCanvas.width = data.width; + newCanvas.height = data.height; + canvasList[id] = newCanvas; + } + + // There might be fonts that need to get loaded. Shedule the + // rendering at the end of the event queue ensures this. + setTimeout(function() { + if (id == 0) tic(); + renderProxyCanvas(canvasList[id], stack); + if (id == 0) toc("canvas rendering") + }, 0); + onMessageState = WAIT; + break; + } + }.bind(this); +} + + WorkerPDFDoc.prototype.open = function(url, callback) { + var req = new XMLHttpRequest(); + req.open("GET", url); + req.mozResponseType = req.responseType = "arraybuffer"; + req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState == 4 && req.status == req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || + req.responseArrayBuffer || req.response; + + this.loadCallback = callback; + this.worker.postMessage(data); + this.showPage(this.numPage); + } + }.bind(this); + req.send(null); +} + +WorkerPDFDoc.prototype.showPage = function(numPage) { + var ctx = this.ctx; + ctx.save(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + this.numPage = parseInt(numPage); + this.worker.postMessage(numPage); + if (this.onChangePage) { + this.onChangePage(numPage); + } +} + +WorkerPDFDoc.prototype.nextPage = function() { + if (this.numPage == this.numPages) return; + this.showPage(++this.numPage); +} + +WorkerPDFDoc.prototype.prevPage = function() { + if (this.numPage == 1) return; + this.showPage(--this.numPage); +} From 229edf24d4586f39bb25b65a947aceb06b8a72ad Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 13:09:36 +0200 Subject: [PATCH 269/439] First pass on review: worker.js -> pdf_worker.js, Font.bind cleanup + other stuff --- canvas_proxy.js | 73 ++++++++++++++++-------------- fonts.js | 92 +++++++------------------------------- pdf.js | 8 ++-- worker.js => pdf_worker.js | 3 ++ viewer_worker.html | 1 + worker_client.js | 23 ++++++---- 6 files changed, 77 insertions(+), 123 deletions(-) rename worker.js => pdf_worker.js (92%) diff --git a/canvas_proxy.js b/canvas_proxy.js index 83b57682f..0b7681bfe 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -1,3 +1,7 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; var JpegStreamProxyCounter = 0; // WebWorker Proxy for JpegStream. @@ -29,16 +33,16 @@ var JpegStreamProxy = (function() { // Really simple GradientProxy. There is currently only one active gradient at // the time, meaning you can't create a gradient, create a second one and then // use the first one again. As this isn't used in pdf.js right now, it's okay. -function GradientProxy(stack, x0, y0, x1, y1) { - stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); +function GradientProxy(cmdQueue, x0, y0, x1, y1) { + cmdQueue.push(["$createLinearGradient", [x0, y0, x1, y1]]); this.addColorStop = function(i, rgba) { - stack.push(["$addColorStop", [i, rgba]]); + cmdQueue.push(["$addColorStop", [i, rgba]]); } } // Really simple PatternProxy. var patternProxyCounter = 0; -function PatternProxy(stack, object, kind) { +function PatternProxy(cmdQueue, object, kind) { this.id = patternProxyCounter++; if (!(object instanceof CanvasProxy) ) { @@ -49,7 +53,7 @@ function PatternProxy(stack, object, kind) { // TODO: Make some kind of dependency management, such that the object // gets flushed only if needed. object.flush(); - stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); + cmdQueue.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); } var canvasProxyCounter = 0; @@ -57,7 +61,7 @@ function CanvasProxy(width, height) { this.id = canvasProxyCounter++; // The `stack` holds the rendering calls and gets flushed to the main thead. - var stack = this.$stack = []; + var cmdQueue = this.cmdQueue = []; // Dummy context that gets exposed. var ctx = {}; @@ -119,7 +123,7 @@ function CanvasProxy(width, height) { function buildFuncCall(name) { return function() { // console.log("funcCall", name) - stack.push([name, Array.prototype.slice.call(arguments)]); + cmdQueue.push([name, Array.prototype.slice.call(arguments)]); } } var name; @@ -131,11 +135,11 @@ function CanvasProxy(width, height) { // Some function calls that need more work. ctx.createPattern = function(object, kind) { - return new PatternProxy(stack, object, kind); + return new PatternProxy(cmdQueue, object, kind); } ctx.createLinearGradient = function(x0, y0, x1, y1) { - return new GradientProxy(stack, x0, y0, x1, y1); + return new GradientProxy(cmdQueue, x0, y0, x1, y1); } ctx.getImageData = function(x, y, w, h) { @@ -147,16 +151,16 @@ function CanvasProxy(width, height) { } ctx.putImageData = function(data, x, y, width, height) { - stack.push(["$putImageData", [data, x, y, width, height]]); + cmdQueue.push(["$putImageData", [data, x, y, width, height]]); } ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { if (image instanceof CanvasProxy) { // Send the image/CanvasProxy to the main thread. image.flush(); - stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); + cmdQueue.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); } else if(image instanceof JpegStreamProxy) { - stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) + cmdQueue.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) } else { throw "unkown type to drawImage"; } @@ -192,11 +196,26 @@ function CanvasProxy(width, height) { function buildSetter(name) { return function(value) { - stack.push(["$", name, value]); + cmdQueue.push(["$", name, value]); return ctx["$" + name] = value; } } + // Setting the value to `stroke|fillStyle` needs special handling, as it + // might gets an gradient/pattern. + function buildSetterStyle(name) { + return function(value) { + if (value instanceof GradientProxy) { + cmdQueue.push(["$" + name + "Gradient"]); + } else if (value instanceof PatternProxy) { + cmdQueue.push(["$" + name + "Pattern", [value.id]]); + } else { + cmdQueue.push(["$", name, value]); + return ctx["$" + name] = value; + } + } + } + for (var name in ctxProp) { ctx["$" + name] = ctxProp[name]; ctx.__defineGetter__(name, buildGetter(name)); @@ -204,18 +223,6 @@ function CanvasProxy(width, height) { // Special treatment for `fillStyle` and `strokeStyle`: The passed style // might be a gradient. Need to check for that. if (name == "fillStyle" || name == "strokeStyle") { - function buildSetterStyle(name) { - return function(value) { - if (value instanceof GradientProxy) { - stack.push(["$" + name + "Gradient"]); - } else if (value instanceof PatternProxy) { - stack.push(["$" + name + "Pattern", [value.id]]); - } else { - stack.push(["$", name, value]); - return ctx["$" + name] = value; - } - } - } ctx.__defineSetter__(name, buildSetterStyle(name)); } else { ctx.__defineSetter__(name, buildSetter(name)); @@ -224,16 +231,16 @@ function CanvasProxy(width, height) { } /** -* Sends the current stack of the CanvasProxy over to the main thread and -* resets the stack. +* Sends the current cmdQueue of the CanvasProxy over to the main thread and +* resets the cmdQueue. */ CanvasProxy.prototype.flush = function() { - postMessage("canvas_proxy_stack"); + postMessage("canvas_proxy_cmd_queue"); postMessage({ - id: this.id, - stack: this.$stack, - width: this.width, - height: this.height + id: this.id, + cmdQueue: this.cmdQueue, + width: this.width, + height: this.height }); - this.$stack.length = 0; + this.cmdQueue.length = 0; } diff --git a/fonts.js b/fonts.js index 9c9201b72..a3604c6b9 100644 --- a/fonts.js +++ b/fonts.js @@ -759,88 +759,15 @@ var Font = (function () { var data = this.font; var fontName = this.name; - var isWorker = (typeof window == "undefined"); - /** Hack begin */ - if (!isWorker) { - - // Actually there is not event when a font has finished downloading so - // the following code are a dirty hack to 'guess' when a font is ready - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); - - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var testString = " "; - - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); - - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; - - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); - - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } - - ctx.fillText(testString, 20, 20); - } - - // Periodicaly check for the width of the testString, it will be - // different once the real font has loaded - var textWidth = ctx.measureText(testString).width; - - var interval = window.setInterval(function canvasInterval(self) { - this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - - // For some reasons the font has not loaded, so mark it loaded for the - // page to proceed but cry - if ((Date.now() - this.start) >= kMaxWaitForFontFace) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); - this.start = 0; - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - this.start = 0; - } - - if (debug) - ctx.fillText(testString, 20, 50); - }, 30, this); - } - - /** Hack end */ - // // Get the base64 encoding of the binary font data var str = ""; var length = data.length; for (var i = 0; i < length; ++i) str += String.fromCharCode(data[i]); - if (isWorker) { + // Insert the font-face css on the page. In a web worker, this needs to + // be forwareded on the main thread. + if (typeof window == "undefined") { postMessage("font"); postMessage(JSON.stringify({ str: str, @@ -855,6 +782,19 @@ var Font = (function () { var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); + + var div = document.createElement("div"); + div.innerHTML += "
j
"; + document.body.appendChild(div); + + Fonts[fontName].loading = true; + window.setTimeout(function() { + Fonts[fontName].loading = false; + // Timeout of just `0`, `10` doesn't work here, but for me all values + // above work. Setting value to 50ms. + }, 50); } } }; diff --git a/pdf.js b/pdf.js index 1223a2bb6..847067946 100644 --- a/pdf.js +++ b/pdf.js @@ -2645,9 +2645,7 @@ var CanvasGraphics = (function() { } var fn = Function("objpool", src); - var ret = function (gfx) { fn.call(gfx, objpool); }; - ret.src = src; - return ret; + return function (gfx) { fn.call(gfx, objpool); }; }, endDrawing: function() { @@ -3015,8 +3013,8 @@ var CanvasGraphics = (function() { var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix); var tmpCanvas = new this.ScratchCanvas( - Math.ceil(botRight[0] - topLeft[0]), // WIDTH - Math.ceil(botRight[1] - topLeft[1]) // HEIGHT + Math.ceil(botRight[0] - topLeft[0]), // width + Math.ceil(botRight[1] - topLeft[1]) // height ); // set the new canvas element context as the graphics context diff --git a/worker.js b/pdf_worker.js similarity index 92% rename from worker.js rename to pdf_worker.js index 09e2b8145..91245aedb 100644 --- a/worker.js +++ b/pdf_worker.js @@ -1,3 +1,6 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + "use strict"; var timer = null; diff --git a/viewer_worker.html b/viewer_worker.html index a9f08388f..a5ffc6a6e 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -14,6 +14,7 @@ window.onload = function() { pdfDoc.onChangePage = function(numPage) { document.getElementById("pageNumber").value = numPage; } + // pdfDoc.open("canvas.pdf", function() { pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() { document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages; }) diff --git a/worker_client.js b/worker_client.js index 316ef1fc0..f69f4f682 100644 --- a/worker_client.js +++ b/worker_client.js @@ -1,3 +1,6 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + "use strict"; function WorkerPDFDoc(canvas) { @@ -128,10 +131,11 @@ function WorkerPDFDoc(canvas) { } } - function renderProxyCanvas(canvas, stack) { + function renderProxyCanvas(canvas, cmdQueue) { var ctx = canvas.getContext("2d"); - for (var i = 0; i < stack.length; i++) { - var opp = stack[i]; + var cmdQueueLength = cmdQueue.length; + for (var i = 0; i < cmdQueueLength; i++) { + var opp = cmdQueue[i]; if (opp[0] == "$") { ctx[opp[1]] = opp[2]; } else if (opp[0] in ctxSpecial) { @@ -146,7 +150,7 @@ function WorkerPDFDoc(canvas) { * onMessage state machine. */ const WAIT = 0; - const CANVAS_PROXY_STACK = 1; + const CANVAS_PROXY_CMD_QUEUE = 1; const LOG = 2; const FONT = 3; const PDF_NUM_PAGE = 4; @@ -170,8 +174,8 @@ function WorkerPDFDoc(canvas) { onMessageState = LOG; return; - case "canvas_proxy_stack": - onMessageState = CANVAS_PROXY_STACK; + case "canvas_proxy_cmd_queue": + onMessageState = CANVAS_PROXY_CMD_QUEUE; return; case "font": @@ -215,6 +219,7 @@ function WorkerPDFDoc(canvas) { // Just adding the font-face to the DOM doesn't make it load. It // 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"); document.getElementById("fonts").innerHTML += "
j
"; onMessageState = WAIT; @@ -225,9 +230,9 @@ function WorkerPDFDoc(canvas) { onMessageState = WAIT; break; - case CANVAS_PROXY_STACK: + case CANVAS_PROXY_CMD_QUEUE: var id = data.id; - var stack = data.stack; + var cmdQueue = data.cmdQueue; // Check if there is already a canvas with the given id. If not, // create a new canvas. @@ -242,7 +247,7 @@ function WorkerPDFDoc(canvas) { // rendering at the end of the event queue ensures this. setTimeout(function() { if (id == 0) tic(); - renderProxyCanvas(canvasList[id], stack); + renderProxyCanvas(canvasList[id], cmdQueue); if (id == 0) toc("canvas rendering") }, 0); onMessageState = WAIT; From a3d815074dd9d186c26fb6ecf9eed9cd0fb6a60d Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 13:09:36 +0200 Subject: [PATCH 270/439] First pass on review: worker.js -> pdf_worker.js, Font.bind cleanup + other stuff --- canvas_proxy.js | 73 ++++++++++++++++-------------- fonts.js | 92 +++++++------------------------------- pdf.js | 8 ++-- worker.js => pdf_worker.js | 3 ++ viewer_worker.html | 1 + worker_client.js | 23 ++++++---- 6 files changed, 77 insertions(+), 123 deletions(-) rename worker.js => pdf_worker.js (92%) diff --git a/canvas_proxy.js b/canvas_proxy.js index 83b57682f..0b7681bfe 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -1,3 +1,7 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +"use strict"; var JpegStreamProxyCounter = 0; // WebWorker Proxy for JpegStream. @@ -29,16 +33,16 @@ var JpegStreamProxy = (function() { // Really simple GradientProxy. There is currently only one active gradient at // the time, meaning you can't create a gradient, create a second one and then // use the first one again. As this isn't used in pdf.js right now, it's okay. -function GradientProxy(stack, x0, y0, x1, y1) { - stack.push(["$createLinearGradient", [x0, y0, x1, y1]]); +function GradientProxy(cmdQueue, x0, y0, x1, y1) { + cmdQueue.push(["$createLinearGradient", [x0, y0, x1, y1]]); this.addColorStop = function(i, rgba) { - stack.push(["$addColorStop", [i, rgba]]); + cmdQueue.push(["$addColorStop", [i, rgba]]); } } // Really simple PatternProxy. var patternProxyCounter = 0; -function PatternProxy(stack, object, kind) { +function PatternProxy(cmdQueue, object, kind) { this.id = patternProxyCounter++; if (!(object instanceof CanvasProxy) ) { @@ -49,7 +53,7 @@ function PatternProxy(stack, object, kind) { // TODO: Make some kind of dependency management, such that the object // gets flushed only if needed. object.flush(); - stack.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); + cmdQueue.push(["$createPatternFromCanvas", [this.id, object.id, kind]]); } var canvasProxyCounter = 0; @@ -57,7 +61,7 @@ function CanvasProxy(width, height) { this.id = canvasProxyCounter++; // The `stack` holds the rendering calls and gets flushed to the main thead. - var stack = this.$stack = []; + var cmdQueue = this.cmdQueue = []; // Dummy context that gets exposed. var ctx = {}; @@ -119,7 +123,7 @@ function CanvasProxy(width, height) { function buildFuncCall(name) { return function() { // console.log("funcCall", name) - stack.push([name, Array.prototype.slice.call(arguments)]); + cmdQueue.push([name, Array.prototype.slice.call(arguments)]); } } var name; @@ -131,11 +135,11 @@ function CanvasProxy(width, height) { // Some function calls that need more work. ctx.createPattern = function(object, kind) { - return new PatternProxy(stack, object, kind); + return new PatternProxy(cmdQueue, object, kind); } ctx.createLinearGradient = function(x0, y0, x1, y1) { - return new GradientProxy(stack, x0, y0, x1, y1); + return new GradientProxy(cmdQueue, x0, y0, x1, y1); } ctx.getImageData = function(x, y, w, h) { @@ -147,16 +151,16 @@ function CanvasProxy(width, height) { } ctx.putImageData = function(data, x, y, width, height) { - stack.push(["$putImageData", [data, x, y, width, height]]); + cmdQueue.push(["$putImageData", [data, x, y, width, height]]); } ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { if (image instanceof CanvasProxy) { // Send the image/CanvasProxy to the main thread. image.flush(); - stack.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); + cmdQueue.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]); } else if(image instanceof JpegStreamProxy) { - stack.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) + cmdQueue.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]]) } else { throw "unkown type to drawImage"; } @@ -192,11 +196,26 @@ function CanvasProxy(width, height) { function buildSetter(name) { return function(value) { - stack.push(["$", name, value]); + cmdQueue.push(["$", name, value]); return ctx["$" + name] = value; } } + // Setting the value to `stroke|fillStyle` needs special handling, as it + // might gets an gradient/pattern. + function buildSetterStyle(name) { + return function(value) { + if (value instanceof GradientProxy) { + cmdQueue.push(["$" + name + "Gradient"]); + } else if (value instanceof PatternProxy) { + cmdQueue.push(["$" + name + "Pattern", [value.id]]); + } else { + cmdQueue.push(["$", name, value]); + return ctx["$" + name] = value; + } + } + } + for (var name in ctxProp) { ctx["$" + name] = ctxProp[name]; ctx.__defineGetter__(name, buildGetter(name)); @@ -204,18 +223,6 @@ function CanvasProxy(width, height) { // Special treatment for `fillStyle` and `strokeStyle`: The passed style // might be a gradient. Need to check for that. if (name == "fillStyle" || name == "strokeStyle") { - function buildSetterStyle(name) { - return function(value) { - if (value instanceof GradientProxy) { - stack.push(["$" + name + "Gradient"]); - } else if (value instanceof PatternProxy) { - stack.push(["$" + name + "Pattern", [value.id]]); - } else { - stack.push(["$", name, value]); - return ctx["$" + name] = value; - } - } - } ctx.__defineSetter__(name, buildSetterStyle(name)); } else { ctx.__defineSetter__(name, buildSetter(name)); @@ -224,16 +231,16 @@ function CanvasProxy(width, height) { } /** -* Sends the current stack of the CanvasProxy over to the main thread and -* resets the stack. +* Sends the current cmdQueue of the CanvasProxy over to the main thread and +* resets the cmdQueue. */ CanvasProxy.prototype.flush = function() { - postMessage("canvas_proxy_stack"); + postMessage("canvas_proxy_cmd_queue"); postMessage({ - id: this.id, - stack: this.$stack, - width: this.width, - height: this.height + id: this.id, + cmdQueue: this.cmdQueue, + width: this.width, + height: this.height }); - this.$stack.length = 0; + this.cmdQueue.length = 0; } diff --git a/fonts.js b/fonts.js index 9c9201b72..a3604c6b9 100644 --- a/fonts.js +++ b/fonts.js @@ -759,88 +759,15 @@ var Font = (function () { var data = this.font; var fontName = this.name; - var isWorker = (typeof window == "undefined"); - /** Hack begin */ - if (!isWorker) { - - // Actually there is not event when a font has finished downloading so - // the following code are a dirty hack to 'guess' when a font is ready - var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); - - // Get the font size canvas think it will be for 'spaces' - var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - var testString = " "; - - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); - - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; - - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); - - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } - - ctx.fillText(testString, 20, 20); - } - - // Periodicaly check for the width of the testString, it will be - // different once the real font has loaded - var textWidth = ctx.measureText(testString).width; - - var interval = window.setInterval(function canvasInterval(self) { - this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; - - // For some reasons the font has not loaded, so mark it loaded for the - // page to proceed but cry - if ((Date.now() - this.start) >= kMaxWaitForFontFace) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); - this.start = 0; - } else if (textWidth != ctx.measureText(testString).width) { - window.clearInterval(interval); - Fonts[fontName].loading = false; - this.start = 0; - } - - if (debug) - ctx.fillText(testString, 20, 50); - }, 30, this); - } - - /** Hack end */ - // // Get the base64 encoding of the binary font data var str = ""; var length = data.length; for (var i = 0; i < length; ++i) str += String.fromCharCode(data[i]); - if (isWorker) { + // Insert the font-face css on the page. In a web worker, this needs to + // be forwareded on the main thread. + if (typeof window == "undefined") { postMessage("font"); postMessage(JSON.stringify({ str: str, @@ -855,6 +782,19 @@ var Font = (function () { var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); + + var div = document.createElement("div"); + div.innerHTML += "
j
"; + document.body.appendChild(div); + + Fonts[fontName].loading = true; + window.setTimeout(function() { + Fonts[fontName].loading = false; + // Timeout of just `0`, `10` doesn't work here, but for me all values + // above work. Setting value to 50ms. + }, 50); } } }; diff --git a/pdf.js b/pdf.js index 1223a2bb6..847067946 100644 --- a/pdf.js +++ b/pdf.js @@ -2645,9 +2645,7 @@ var CanvasGraphics = (function() { } var fn = Function("objpool", src); - var ret = function (gfx) { fn.call(gfx, objpool); }; - ret.src = src; - return ret; + return function (gfx) { fn.call(gfx, objpool); }; }, endDrawing: function() { @@ -3015,8 +3013,8 @@ var CanvasGraphics = (function() { var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix); var tmpCanvas = new this.ScratchCanvas( - Math.ceil(botRight[0] - topLeft[0]), // WIDTH - Math.ceil(botRight[1] - topLeft[1]) // HEIGHT + Math.ceil(botRight[0] - topLeft[0]), // width + Math.ceil(botRight[1] - topLeft[1]) // height ); // set the new canvas element context as the graphics context diff --git a/worker.js b/pdf_worker.js similarity index 92% rename from worker.js rename to pdf_worker.js index 09e2b8145..91245aedb 100644 --- a/worker.js +++ b/pdf_worker.js @@ -1,3 +1,6 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + "use strict"; var timer = null; diff --git a/viewer_worker.html b/viewer_worker.html index a9f08388f..a5ffc6a6e 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -14,6 +14,7 @@ window.onload = function() { pdfDoc.onChangePage = function(numPage) { document.getElementById("pageNumber").value = numPage; } + // pdfDoc.open("canvas.pdf", function() { pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() { document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages; }) diff --git a/worker_client.js b/worker_client.js index 316ef1fc0..f69f4f682 100644 --- a/worker_client.js +++ b/worker_client.js @@ -1,3 +1,6 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + "use strict"; function WorkerPDFDoc(canvas) { @@ -128,10 +131,11 @@ function WorkerPDFDoc(canvas) { } } - function renderProxyCanvas(canvas, stack) { + function renderProxyCanvas(canvas, cmdQueue) { var ctx = canvas.getContext("2d"); - for (var i = 0; i < stack.length; i++) { - var opp = stack[i]; + var cmdQueueLength = cmdQueue.length; + for (var i = 0; i < cmdQueueLength; i++) { + var opp = cmdQueue[i]; if (opp[0] == "$") { ctx[opp[1]] = opp[2]; } else if (opp[0] in ctxSpecial) { @@ -146,7 +150,7 @@ function WorkerPDFDoc(canvas) { * onMessage state machine. */ const WAIT = 0; - const CANVAS_PROXY_STACK = 1; + const CANVAS_PROXY_CMD_QUEUE = 1; const LOG = 2; const FONT = 3; const PDF_NUM_PAGE = 4; @@ -170,8 +174,8 @@ function WorkerPDFDoc(canvas) { onMessageState = LOG; return; - case "canvas_proxy_stack": - onMessageState = CANVAS_PROXY_STACK; + case "canvas_proxy_cmd_queue": + onMessageState = CANVAS_PROXY_CMD_QUEUE; return; case "font": @@ -215,6 +219,7 @@ function WorkerPDFDoc(canvas) { // Just adding the font-face to the DOM doesn't make it load. It // 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"); document.getElementById("fonts").innerHTML += "
j
"; onMessageState = WAIT; @@ -225,9 +230,9 @@ function WorkerPDFDoc(canvas) { onMessageState = WAIT; break; - case CANVAS_PROXY_STACK: + case CANVAS_PROXY_CMD_QUEUE: var id = data.id; - var stack = data.stack; + var cmdQueue = data.cmdQueue; // Check if there is already a canvas with the given id. If not, // create a new canvas. @@ -242,7 +247,7 @@ function WorkerPDFDoc(canvas) { // rendering at the end of the event queue ensures this. setTimeout(function() { if (id == 0) tic(); - renderProxyCanvas(canvasList[id], stack); + renderProxyCanvas(canvasList[id], cmdQueue); if (id == 0) toc("canvas rendering") }, 0); onMessageState = WAIT; From 78129970c6b70992e7d8316a1978f0be79a86604 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 13:25:59 +0200 Subject: [PATCH 271/439] Change postMessage to send only one object that holds the action and data. --- canvas_proxy.js | 17 +++--- fonts.js | 10 ++-- pdf_worker.js | 12 +++-- worker_client.js | 132 +++++++++++++++++------------------------------ 4 files changed, 70 insertions(+), 101 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 0b7681bfe..e2795bd00 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -11,10 +11,9 @@ var JpegStreamProxy = (function() { this.dict = dict; // Tell the main thread to create an image. - postMessage("jpeg_stream"); postMessage({ - id: this.id, - str: bytesToString(bytes) + action: jpeg_stream, + data: bytesToString(bytes) }); } @@ -235,12 +234,14 @@ function CanvasProxy(width, height) { * resets the cmdQueue. */ CanvasProxy.prototype.flush = function() { - postMessage("canvas_proxy_cmd_queue"); postMessage({ - id: this.id, - cmdQueue: this.cmdQueue, - width: this.width, - height: this.height + action: "canvas_proxy_cmd_queue", + data: { + id: this.id, + cmdQueue: this.cmdQueue, + width: this.width, + height: this.height + } }); this.cmdQueue.length = 0; } diff --git a/fonts.js b/fonts.js index a3604c6b9..7f4958caf 100644 --- a/fonts.js +++ b/fonts.js @@ -768,12 +768,14 @@ var Font = (function () { // Insert the font-face css on the page. In a web worker, this needs to // be forwareded on the main thread. if (typeof window == "undefined") { - postMessage("font"); - postMessage(JSON.stringify({ - str: str, + postMessage({ + action: "font", + data: { + raw: str, fontName: fontName, mimetype: this.mimetype - })); + } + }); } else { var base64 = window.btoa(str); diff --git a/pdf_worker.js b/pdf_worker.js index 91245aedb..13a1f3f28 100644 --- a/pdf_worker.js +++ b/pdf_worker.js @@ -15,8 +15,10 @@ function toc(msg) { function log() { var args = Array.prototype.slice.call(arguments); - postMessage("log"); - postMessage(JSON.stringify(args)) + postMessage({ + action: "log", + args: args + }); } var console = { @@ -42,8 +44,10 @@ onmessage = function(event) { // If there is no pdfDocument yet, then the sent data is the PDFDocument. if (!pdfDocument) { pdfDocument = new PDFDoc(new Stream(data)); - postMessage("pdf_num_page"); - postMessage(pdfDocument.numPages) + postMessage({ + action: "pdf_num_pages", + data: pdfDocument.numPages + }); return; } // User requested to render a certain page. diff --git a/worker_client.js b/worker_client.js index f69f4f682..4af0d9764 100644 --- a/worker_client.js +++ b/worker_client.js @@ -15,7 +15,7 @@ function WorkerPDFDoc(canvas) { this.ctx = canvas.getContext("2d"); this.canvas = canvas; - this.worker = new Worker('worker.js'); + this.worker = new Worker('pdf_worker.js'); this.numPage = 1; this.numPages = null; @@ -147,90 +147,44 @@ function WorkerPDFDoc(canvas) { } /** - * onMessage state machine. + * Functions to handle data sent by the WebWorker. */ - const WAIT = 0; - const CANVAS_PROXY_CMD_QUEUE = 1; - const LOG = 2; - const FONT = 3; - const PDF_NUM_PAGE = 4; - const JPEG_STREAM = 5; + var actionHandler = { + "log": function(data) { + console.log.apply(console, data); + }, + + "pdf_num_pages": function(data) { + this.numPages = parseInt(data); + if (this.loadCallback) { + this.loadCallback(); + } + }, + + "font": function(data) { + var base64 = window.btoa(data.raw); - var onMessageState = WAIT; - this.worker.onmessage = function(event) { - var data = event.data; - // console.log("onMessageRaw", data); - switch (onMessageState) { - case WAIT: - if (typeof data != "string") { - throw "expecting to get an string"; - } - switch (data) { - case "pdf_num_page": - onMessageState = PDF_NUM_PAGE; - return; + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); - case "log": - onMessageState = LOG; - return; + // Just adding the font-face to the DOM doesn't make it load. It + // 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"); + document.getElementById("fonts").innerHTML += "
j
"; + }, - case "canvas_proxy_cmd_queue": - onMessageState = CANVAS_PROXY_CMD_QUEUE; - return; - - case "font": - onMessageState = FONT; - return; - - case "jpeg_stream": - onMessageState = JPEG_STREAM; - return; - - default: - throw "unkown state: " + data - } - break; - - case JPEG_STREAM: - var img = new Image(); - img.src = "data:image/jpeg;base64," + window.btoa(data.str); - imagesList[data.id] = img; - console.log("got image", data.id) - break; - - case PDF_NUM_PAGE: - this.numPages = parseInt(data); - if (this.loadCallback) { - this.loadCallback(); - } - onMessageState = WAIT; - break; - - case FONT: - data = JSON.parse(data); - var base64 = window.btoa(data.str); - - // Add the @font-face rule to the document - var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; - var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); - - // Just adding the font-face to the DOM doesn't make it load. It - // 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"); - document.getElementById("fonts").innerHTML += "
j
"; - - onMessageState = WAIT; - break; - - case LOG: - console.log.apply(console, JSON.parse(data)); - onMessageState = WAIT; - break; - - case CANVAS_PROXY_CMD_QUEUE: + "jpeg_stream": function(data) { + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(data); + imagesList[data.id] = img; + console.log("got image", data.id) + }, + + "canvas_proxy_cmd_queue": function(data) { var id = data.id; var cmdQueue = data.cmdQueue; @@ -250,13 +204,21 @@ function WorkerPDFDoc(canvas) { renderProxyCanvas(canvasList[id], cmdQueue); if (id == 0) toc("canvas rendering") }, 0); - onMessageState = WAIT; - break; } - }.bind(this); + } + + // List to the WebWorker for data and call actionHandler on it. + this.worker.onmessage = function(event) { + var data = event.data; + if (data.action in actionHandler) { + actionHandler[data.action].call(this, data.data); + } else { + throw "Unkown action from worker: " + data.action; + } + } } - WorkerPDFDoc.prototype.open = function(url, callback) { +WorkerPDFDoc.prototype.open = function(url, callback) { var req = new XMLHttpRequest(); req.open("GET", url); req.mozResponseType = req.responseType = "arraybuffer"; From da7f555fd7cccfb8cef331438fec7e905059373d Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 13:25:59 +0200 Subject: [PATCH 272/439] Change postMessage to send only one object that holds the action and data. --- canvas_proxy.js | 17 +++--- fonts.js | 10 ++-- pdf_worker.js | 12 +++-- worker_client.js | 132 +++++++++++++++++------------------------------ 4 files changed, 70 insertions(+), 101 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index 0b7681bfe..e2795bd00 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -11,10 +11,9 @@ var JpegStreamProxy = (function() { this.dict = dict; // Tell the main thread to create an image. - postMessage("jpeg_stream"); postMessage({ - id: this.id, - str: bytesToString(bytes) + action: jpeg_stream, + data: bytesToString(bytes) }); } @@ -235,12 +234,14 @@ function CanvasProxy(width, height) { * resets the cmdQueue. */ CanvasProxy.prototype.flush = function() { - postMessage("canvas_proxy_cmd_queue"); postMessage({ - id: this.id, - cmdQueue: this.cmdQueue, - width: this.width, - height: this.height + action: "canvas_proxy_cmd_queue", + data: { + id: this.id, + cmdQueue: this.cmdQueue, + width: this.width, + height: this.height + } }); this.cmdQueue.length = 0; } diff --git a/fonts.js b/fonts.js index a3604c6b9..7f4958caf 100644 --- a/fonts.js +++ b/fonts.js @@ -768,12 +768,14 @@ var Font = (function () { // Insert the font-face css on the page. In a web worker, this needs to // be forwareded on the main thread. if (typeof window == "undefined") { - postMessage("font"); - postMessage(JSON.stringify({ - str: str, + postMessage({ + action: "font", + data: { + raw: str, fontName: fontName, mimetype: this.mimetype - })); + } + }); } else { var base64 = window.btoa(str); diff --git a/pdf_worker.js b/pdf_worker.js index 91245aedb..13a1f3f28 100644 --- a/pdf_worker.js +++ b/pdf_worker.js @@ -15,8 +15,10 @@ function toc(msg) { function log() { var args = Array.prototype.slice.call(arguments); - postMessage("log"); - postMessage(JSON.stringify(args)) + postMessage({ + action: "log", + args: args + }); } var console = { @@ -42,8 +44,10 @@ onmessage = function(event) { // If there is no pdfDocument yet, then the sent data is the PDFDocument. if (!pdfDocument) { pdfDocument = new PDFDoc(new Stream(data)); - postMessage("pdf_num_page"); - postMessage(pdfDocument.numPages) + postMessage({ + action: "pdf_num_pages", + data: pdfDocument.numPages + }); return; } // User requested to render a certain page. diff --git a/worker_client.js b/worker_client.js index f69f4f682..4af0d9764 100644 --- a/worker_client.js +++ b/worker_client.js @@ -15,7 +15,7 @@ function WorkerPDFDoc(canvas) { this.ctx = canvas.getContext("2d"); this.canvas = canvas; - this.worker = new Worker('worker.js'); + this.worker = new Worker('pdf_worker.js'); this.numPage = 1; this.numPages = null; @@ -147,90 +147,44 @@ function WorkerPDFDoc(canvas) { } /** - * onMessage state machine. + * Functions to handle data sent by the WebWorker. */ - const WAIT = 0; - const CANVAS_PROXY_CMD_QUEUE = 1; - const LOG = 2; - const FONT = 3; - const PDF_NUM_PAGE = 4; - const JPEG_STREAM = 5; + var actionHandler = { + "log": function(data) { + console.log.apply(console, data); + }, + + "pdf_num_pages": function(data) { + this.numPages = parseInt(data); + if (this.loadCallback) { + this.loadCallback(); + } + }, + + "font": function(data) { + var base64 = window.btoa(data.raw); - var onMessageState = WAIT; - this.worker.onmessage = function(event) { - var data = event.data; - // console.log("onMessageRaw", data); - switch (onMessageState) { - case WAIT: - if (typeof data != "string") { - throw "expecting to get an string"; - } - switch (data) { - case "pdf_num_page": - onMessageState = PDF_NUM_PAGE; - return; + // Add the @font-face rule to the document + var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; + var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; + styleSheet.insertRule(rule, styleSheet.length); - case "log": - onMessageState = LOG; - return; + // Just adding the font-face to the DOM doesn't make it load. It + // 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"); + document.getElementById("fonts").innerHTML += "
j
"; + }, - case "canvas_proxy_cmd_queue": - onMessageState = CANVAS_PROXY_CMD_QUEUE; - return; - - case "font": - onMessageState = FONT; - return; - - case "jpeg_stream": - onMessageState = JPEG_STREAM; - return; - - default: - throw "unkown state: " + data - } - break; - - case JPEG_STREAM: - var img = new Image(); - img.src = "data:image/jpeg;base64," + window.btoa(data.str); - imagesList[data.id] = img; - console.log("got image", data.id) - break; - - case PDF_NUM_PAGE: - this.numPages = parseInt(data); - if (this.loadCallback) { - this.loadCallback(); - } - onMessageState = WAIT; - break; - - case FONT: - data = JSON.parse(data); - var base64 = window.btoa(data.str); - - // Add the @font-face rule to the document - var url = "url(data:" + data.mimetype + ";base64," + base64 + ");"; - var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}"; - var styleSheet = document.styleSheets[0]; - styleSheet.insertRule(rule, styleSheet.length); - - // Just adding the font-face to the DOM doesn't make it load. It - // 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"); - document.getElementById("fonts").innerHTML += "
j
"; - - onMessageState = WAIT; - break; - - case LOG: - console.log.apply(console, JSON.parse(data)); - onMessageState = WAIT; - break; - - case CANVAS_PROXY_CMD_QUEUE: + "jpeg_stream": function(data) { + var img = new Image(); + img.src = "data:image/jpeg;base64," + window.btoa(data); + imagesList[data.id] = img; + console.log("got image", data.id) + }, + + "canvas_proxy_cmd_queue": function(data) { var id = data.id; var cmdQueue = data.cmdQueue; @@ -250,13 +204,21 @@ function WorkerPDFDoc(canvas) { renderProxyCanvas(canvasList[id], cmdQueue); if (id == 0) toc("canvas rendering") }, 0); - onMessageState = WAIT; - break; } - }.bind(this); + } + + // List to the WebWorker for data and call actionHandler on it. + this.worker.onmessage = function(event) { + var data = event.data; + if (data.action in actionHandler) { + actionHandler[data.action].call(this, data.data); + } else { + throw "Unkown action from worker: " + data.action; + } + } } - WorkerPDFDoc.prototype.open = function(url, callback) { +WorkerPDFDoc.prototype.open = function(url, callback) { var req = new XMLHttpRequest(); req.open("GET", url); req.mozResponseType = req.responseType = "arraybuffer"; From 37ee56a705d88b360e67b1cb3d2e064bd6614fb6 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 14:36:45 +0200 Subject: [PATCH 273/439] Fix sending image data to main thread --- canvas_proxy.js | 7 +++++-- viewer.js | 2 +- worker_client.js | 5 ++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index e2795bd00..d6f5a0a25 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -12,8 +12,11 @@ var JpegStreamProxy = (function() { // Tell the main thread to create an image. postMessage({ - action: jpeg_stream, - data: bytesToString(bytes) + action: "jpeg_stream", + data: { + id: this.id, + raw: bytesToString(bytes) + } }); } diff --git a/viewer.js b/viewer.js index 41aaf354c..d0aeb0b2d 100644 --- a/viewer.js +++ b/viewer.js @@ -10,7 +10,7 @@ function load(userInput) { pageNum = parseInt(queryParams().page) || 1; var fileName = userInput; if (!userInput) { - fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; + fileName = "canvas.pdf"; } open(fileName); } diff --git a/worker_client.js b/worker_client.js index 4af0d9764..385103c30 100644 --- a/worker_client.js +++ b/worker_client.js @@ -71,7 +71,7 @@ function WorkerPDFDoc(canvas) { "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { var image = imagesList[id]; if (!image) { - throw "Image not found"; + throw "Image not found: " + id; } this.drawImage(image, x, y, image.width, image.height, sx, sy, swidth, sheight); @@ -179,9 +179,8 @@ function WorkerPDFDoc(canvas) { "jpeg_stream": function(data) { var img = new Image(); - img.src = "data:image/jpeg;base64," + window.btoa(data); + img.src = "data:image/jpeg;base64," + window.btoa(data.raw); imagesList[data.id] = img; - console.log("got image", data.id) }, "canvas_proxy_cmd_queue": function(data) { From f32dfa9414eef8bdaa5b5e65f0d1b1fcb02de3ce Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 14:36:45 +0200 Subject: [PATCH 274/439] Fix sending image data to main thread --- canvas_proxy.js | 7 +++++-- viewer.js | 2 +- worker_client.js | 5 ++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/canvas_proxy.js b/canvas_proxy.js index e2795bd00..d6f5a0a25 100644 --- a/canvas_proxy.js +++ b/canvas_proxy.js @@ -12,8 +12,11 @@ var JpegStreamProxy = (function() { // Tell the main thread to create an image. postMessage({ - action: jpeg_stream, - data: bytesToString(bytes) + action: "jpeg_stream", + data: { + id: this.id, + raw: bytesToString(bytes) + } }); } diff --git a/viewer.js b/viewer.js index 41aaf354c..d0aeb0b2d 100644 --- a/viewer.js +++ b/viewer.js @@ -10,7 +10,7 @@ function load(userInput) { pageNum = parseInt(queryParams().page) || 1; var fileName = userInput; if (!userInput) { - fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; + fileName = "canvas.pdf"; } open(fileName); } diff --git a/worker_client.js b/worker_client.js index 4af0d9764..385103c30 100644 --- a/worker_client.js +++ b/worker_client.js @@ -71,7 +71,7 @@ function WorkerPDFDoc(canvas) { "$drawImage": function(id, x, y, sx, sy, swidth, sheight) { var image = imagesList[id]; if (!image) { - throw "Image not found"; + throw "Image not found: " + id; } this.drawImage(image, x, y, image.width, image.height, sx, sy, swidth, sheight); @@ -179,9 +179,8 @@ function WorkerPDFDoc(canvas) { "jpeg_stream": function(data) { var img = new Image(); - img.src = "data:image/jpeg;base64," + window.btoa(data); + img.src = "data:image/jpeg;base64," + window.btoa(data.raw); imagesList[data.id] = img; - console.log("got image", data.id) }, "canvas_proxy_cmd_queue": function(data) { From c35e1e75522313faae4cfaa63dde10b903c93c07 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 15:24:55 +0200 Subject: [PATCH 275/439] Fix WebWorker logging and add separate timing for `fonts`. --- pdf_worker.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdf_worker.js b/pdf_worker.js index 13a1f3f28..86dfec2dd 100644 --- a/pdf_worker.js +++ b/pdf_worker.js @@ -17,7 +17,7 @@ function log() { var args = Array.prototype.slice.call(arguments); postMessage({ action: "log", - args: args + data: args }); } @@ -62,7 +62,9 @@ onmessage = function(event) { var fonts = []; var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); page.compile(gfx, fonts); + toc("compiled page"); + tic() // Inspect fonts and translate the missing one. var count = fonts.length; for (var i = 0; i < count; i++) { @@ -75,7 +77,7 @@ onmessage = function(event) { // This "builds" the font and sents it over to the main thread. new Font(font.name, font.file, font.properties); } - toc("compiled page"); + toc("fonts"); tic() page.display(gfx); From f256716022c86a216ec6bc15e6c12644d43d9e80 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 15:24:55 +0200 Subject: [PATCH 276/439] Fix WebWorker logging and add separate timing for `fonts`. --- pdf_worker.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdf_worker.js b/pdf_worker.js index 13a1f3f28..86dfec2dd 100644 --- a/pdf_worker.js +++ b/pdf_worker.js @@ -17,7 +17,7 @@ function log() { var args = Array.prototype.slice.call(arguments); postMessage({ action: "log", - args: args + data: args }); } @@ -62,7 +62,9 @@ onmessage = function(event) { var fonts = []; var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy); page.compile(gfx, fonts); + toc("compiled page"); + tic() // Inspect fonts and translate the missing one. var count = fonts.length; for (var i = 0; i < count; i++) { @@ -75,7 +77,7 @@ onmessage = function(event) { // This "builds" the font and sents it over to the main thread. new Font(font.name, font.file, font.properties); } - toc("compiled page"); + toc("fonts"); tic() page.display(gfx); From 171ab51c569182bf41d4f1de74d55cc81a346abf Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 23 Jun 2011 19:43:01 +0200 Subject: [PATCH 277/439] Ensure divs used to make fonts load are not visible --- fonts.js | 6 +++--- viewer.js | 2 +- viewer_worker.html | 2 -- worker_client.js | 5 ++++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fonts.js b/fonts.js index 7f4958caf..ba40ef8e1 100644 --- a/fonts.js +++ b/fonts.js @@ -786,9 +786,9 @@ var Font = (function () { styleSheet.insertRule(rule, styleSheet.length); var div = document.createElement("div"); - div.innerHTML += "
j
"; + var style = 'font-family:"' + fontName + + '";position: absolute;top:-99999;left:-99999;z-index:-99999'; + div.setAttribute("style", style); document.body.appendChild(div); Fonts[fontName].loading = true; diff --git a/viewer.js b/viewer.js index d0aeb0b2d..41aaf354c 100644 --- a/viewer.js +++ b/viewer.js @@ -10,7 +10,7 @@ function load(userInput) { pageNum = parseInt(queryParams().page) || 1; var fileName = userInput; if (!userInput) { - fileName = "canvas.pdf"; + fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; } open(fileName); } diff --git a/viewer_worker.html b/viewer_worker.html index a5ffc6a6e..d13935f13 100644 --- a/viewer_worker.html +++ b/viewer_worker.html @@ -22,9 +22,7 @@ window.onload = function() { - -
-
- - diff --git a/multi-page-viewer.js b/multi-page-viewer.js deleted file mode 100644 index baad7809e..000000000 --- a/multi-page-viewer.js +++ /dev/null @@ -1,466 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -"use strict"; - -var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } -}; - -window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; diff --git a/multi_page_viewer.css b/multi_page_viewer.css new file mode 100644 index 000000000..fce7d7b32 --- /dev/null +++ b/multi_page_viewer.css @@ -0,0 +1,197 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.control { + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > select { + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > span { + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + +#pageNumber { + text-align: right; +} + +#sidebar { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} diff --git a/multi_page_viewer.html b/multi_page_viewer.html new file mode 100644 index 000000000..47234686d --- /dev/null +++ b/multi_page_viewer.html @@ -0,0 +1,51 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + + +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ +
+ + diff --git a/multi_page_viewer.js b/multi_page_viewer.js new file mode 100644 index 000000000..ddb541175 --- /dev/null +++ b/multi_page_viewer.js @@ -0,0 +1,458 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +"use strict"; + +var PDFViewer = { + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, + + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); + } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } +}; + +window.onload = function() { + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; +}; From 791947ff748bf819636bf58cc43ca0e2051ebc64 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 20:50:01 -0400 Subject: [PATCH 300/439] Refactored the multi-page viewer to adhere to the coding style guidelines. --- multi-page-viewer.css | 197 ----------------- multi-page-viewer.html | 51 ----- multi-page-viewer.js | 466 ----------------------------------------- multi_page_viewer.css | 197 +++++++++++++++++ multi_page_viewer.html | 51 +++++ multi_page_viewer.js | 458 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 706 insertions(+), 714 deletions(-) delete mode 100644 multi-page-viewer.css delete mode 100644 multi-page-viewer.html delete mode 100644 multi-page-viewer.js create mode 100644 multi_page_viewer.css create mode 100644 multi_page_viewer.html create mode 100644 multi_page_viewer.js diff --git a/multi-page-viewer.css b/multi-page-viewer.css deleted file mode 100644 index 7f4701022..000000000 --- a/multi-page-viewer.css +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; -} - -canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; -} - -span { - font-size: 0.8em; -} - -.control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; -} - -.control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; -} - -.control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; -} - -.page { - width: 816px; - height: 1056px; - margin: 10px auto; -} - -#controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; -} - -#previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; -} - -#previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; -} - -#nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; -} - -#nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; -} - -#openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; -} - -#openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; -} - -#openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; -} - -#fileInput { - display: none; -} - -#pageNumber { - text-align: right; -} - -#sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; -} - -#sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; -} - -#sidebarContentView { - height: auto; - width: 100px; -} - -#viewer { - margin: 44px 0px 0px; - padding: 8px 0px; -} diff --git a/multi-page-viewer.html b/multi-page-viewer.html deleted file mode 100644 index ffbdfe707..000000000 --- a/multi-page-viewer.html +++ /dev/null @@ -1,51 +0,0 @@ - - - -pdf.js Multi-Page Viewer - - - - - - - - -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- -
- - diff --git a/multi-page-viewer.js b/multi-page-viewer.js deleted file mode 100644 index baad7809e..000000000 --- a/multi-page-viewer.js +++ /dev/null @@ -1,466 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -"use strict"; - -var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } -}; - -window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; diff --git a/multi_page_viewer.css b/multi_page_viewer.css new file mode 100644 index 000000000..fce7d7b32 --- /dev/null +++ b/multi_page_viewer.css @@ -0,0 +1,197 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.control { + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > select { + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > span { + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + +#pageNumber { + text-align: right; +} + +#sidebar { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} diff --git a/multi_page_viewer.html b/multi_page_viewer.html new file mode 100644 index 000000000..47234686d --- /dev/null +++ b/multi_page_viewer.html @@ -0,0 +1,51 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + + +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ +
+ + diff --git a/multi_page_viewer.js b/multi_page_viewer.js new file mode 100644 index 000000000..ddb541175 --- /dev/null +++ b/multi_page_viewer.js @@ -0,0 +1,458 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +"use strict"; + +var PDFViewer = { + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, + + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); + } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } +}; + +window.onload = function() { + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; +}; From d704bfacf418db5a891bea054218dd1021e54fc0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 02:58:17 +0200 Subject: [PATCH 301/439] Fix Windows 'hmtx' bust table --- fonts.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 1169e21c6..6f5adbeef 100644 --- a/fonts.js +++ b/fonts.js @@ -710,11 +710,15 @@ var Font = (function () { createTableEntry(otf, offsets, "hhea", hhea); /** HMTX */ - hmtx = "\x01\xF4\x00\x00"; + /* For some reasons, probably related to how the backend handle fonts, + * Linux seems to ignore this file and prefer the data from the CFF itself + * while Windows use this data. So be careful if you hack on Linux and + * have to touch the 'hmtx' table + */ + hmtx = "\x01\xF4\x00\x00"; // Fake .notdef + var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { - var charstring = charstrings[i].charstring; - var width = charstring[1]; - var lsb = charstring[0]; + width = charstrings[i].charstring[0]; hmtx += string16(width) + string16(lsb); } hmtx = stringToArray(hmtx); @@ -1314,7 +1318,7 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function flattenCharstring(glyph, charstring, subrs) { + flattenCharstring: function flattenCharstring(charstring, subrs) { var i = 0; while (true) { var obj = charstring[i]; @@ -1326,7 +1330,7 @@ CFF.prototype = { case "callsubr": var subr = subrs[charstring[i - 1]]; if (subr.length > 1) { - subr = this.flattenCharstring(glyph, subr, subrs); + subr = this.flattenCharstring(subr, subrs); subr.pop(); charstring.splice(i - 1, 2, subr); } else { @@ -1420,11 +1424,11 @@ CFF.prototype = { wrap: function wrap(name, charstrings, subrs, properties) { // Starts the conversion of the Type1 charstrings to Type2 - var glyphs = charstrings.slice(); - var glyphsCount = glyphs.length; - for (var i = 0; i < glyphs.length; i++) { - var charstring = glyphs[i]; - glyphs[i] = this.flattenCharstring(charstring.glyph, charstring.charstring, subrs); + var glyphs = []; + var glyphsCount = charstrings.length; + for (var i = 0; i < glyphsCount; i++) { + var charstring = charstrings[i].charstring; + glyphs.push(this.flattenCharstring(charstring.slice(), subrs)); } // Create a CFF font data From 5443714d341377564d7f33df17eeb923ab1a45e5 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 02:58:17 +0200 Subject: [PATCH 302/439] Fix Windows 'hmtx' bust table --- fonts.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 1169e21c6..6f5adbeef 100644 --- a/fonts.js +++ b/fonts.js @@ -710,11 +710,15 @@ var Font = (function () { createTableEntry(otf, offsets, "hhea", hhea); /** HMTX */ - hmtx = "\x01\xF4\x00\x00"; + /* For some reasons, probably related to how the backend handle fonts, + * Linux seems to ignore this file and prefer the data from the CFF itself + * while Windows use this data. So be careful if you hack on Linux and + * have to touch the 'hmtx' table + */ + hmtx = "\x01\xF4\x00\x00"; // Fake .notdef + var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { - var charstring = charstrings[i].charstring; - var width = charstring[1]; - var lsb = charstring[0]; + width = charstrings[i].charstring[0]; hmtx += string16(width) + string16(lsb); } hmtx = stringToArray(hmtx); @@ -1314,7 +1318,7 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function flattenCharstring(glyph, charstring, subrs) { + flattenCharstring: function flattenCharstring(charstring, subrs) { var i = 0; while (true) { var obj = charstring[i]; @@ -1326,7 +1330,7 @@ CFF.prototype = { case "callsubr": var subr = subrs[charstring[i - 1]]; if (subr.length > 1) { - subr = this.flattenCharstring(glyph, subr, subrs); + subr = this.flattenCharstring(subr, subrs); subr.pop(); charstring.splice(i - 1, 2, subr); } else { @@ -1420,11 +1424,11 @@ CFF.prototype = { wrap: function wrap(name, charstrings, subrs, properties) { // Starts the conversion of the Type1 charstrings to Type2 - var glyphs = charstrings.slice(); - var glyphsCount = glyphs.length; - for (var i = 0; i < glyphs.length; i++) { - var charstring = glyphs[i]; - glyphs[i] = this.flattenCharstring(charstring.glyph, charstring.charstring, subrs); + var glyphs = []; + var glyphsCount = charstrings.length; + for (var i = 0; i < glyphsCount; i++) { + var charstring = charstrings[i].charstring; + glyphs.push(this.flattenCharstring(charstring.slice(), subrs)); } // Create a CFF font data From 40006194eaa6283c22ce87ef358f5b9600e7ce85 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 03:01:41 +0200 Subject: [PATCH 303/439] Don't read the lsb instead of the width --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 6f5adbeef..a995c55eb 100644 --- a/fonts.js +++ b/fonts.js @@ -718,7 +718,7 @@ var Font = (function () { hmtx = "\x01\xF4\x00\x00"; // Fake .notdef var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { - width = charstrings[i].charstring[0]; + width = charstrings[i].charstring[1]; hmtx += string16(width) + string16(lsb); } hmtx = stringToArray(hmtx); From bc7e2b0110273454abae614b335c9ac94e73739f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 03:01:41 +0200 Subject: [PATCH 304/439] Don't read the lsb instead of the width --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 6f5adbeef..a995c55eb 100644 --- a/fonts.js +++ b/fonts.js @@ -718,7 +718,7 @@ var Font = (function () { hmtx = "\x01\xF4\x00\x00"; // Fake .notdef var width = 0, lsb = 0; for (var i = 0; i < charstrings.length; i++) { - width = charstrings[i].charstring[0]; + width = charstrings[i].charstring[1]; hmtx += string16(width) + string16(lsb); } hmtx = stringToArray(hmtx); From 0b48feb2080e2fa28b7708cfe123f834a7e1277e Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:11:50 -0400 Subject: [PATCH 305/439] Revert ae2e637044e5abe5d4c119de133e65e0aef4a9b5^..HEAD --- multi-page-viewer.css | 197 ++++++++++ multi-page-viewer.html | 51 +++ multi-page-viewer.js | 466 ++++++++++++++++++++++ multi_page_viewer.css | 234 ++++++------ multi_page_viewer.html | 76 ++-- multi_page_viewer.js | 850 +++++++++++++++++++++-------------------- pdf.js | 7 +- 7 files changed, 1300 insertions(+), 581 deletions(-) create mode 100644 multi-page-viewer.css create mode 100644 multi-page-viewer.html create mode 100644 multi-page-viewer.js diff --git a/multi-page-viewer.css b/multi-page-viewer.css new file mode 100644 index 000000000..7f4701022 --- /dev/null +++ b/multi-page-viewer.css @@ -0,0 +1,197 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.control { + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > select { + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > span { + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + +#pageNumber { + text-align: right; +} + +#sidebar { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} diff --git a/multi-page-viewer.html b/multi-page-viewer.html new file mode 100644 index 000000000..ffbdfe707 --- /dev/null +++ b/multi-page-viewer.html @@ -0,0 +1,51 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + + +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ +
+ + diff --git a/multi-page-viewer.js b/multi-page-viewer.js new file mode 100644 index 000000000..baad7809e --- /dev/null +++ b/multi-page-viewer.js @@ -0,0 +1,466 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +"use strict"; + +var PDFViewer = { + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, + + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); + } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || + req.mozResponse || + req.responseArrayBuffer || + req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } +}; + +window.onload = function() { + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; +}; diff --git a/multi_page_viewer.css b/multi_page_viewer.css index fce7d7b32..7f4701022 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -2,196 +2,196 @@ /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; } canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; } span { - font-size: 0.8em; + font-size: 0.8em; } .control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; } .control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; } .control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; } .page { - width: 816px; - height: 1056px; - margin: 10px auto; + width: 816px; + height: 1056px; + margin: 10px auto; } #controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; } #previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; + background: url('images/buttons.png') no-repeat 0px -46px; } #previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; + background: url('images/buttons.png') no-repeat 0px 0px; } #nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; + background: url('images/buttons.png') no-repeat -28px -46px; } #nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; + background: url('images/buttons.png') no-repeat -28px 0px; } #openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; } #openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; + background: url('images/buttons.png') no-repeat -56px -46px; } #openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; + background: url('images/buttons.png') no-repeat -56px 0px; } #fileInput { - display: none; + display: none; } #pageNumber { - text-align: right; + text-align: right; } #sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; } #sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; } #sidebarContentView { - height: auto; - width: 100px; + height: auto; + width: 100px; } #viewer { - margin: 44px 0px 0px; - padding: 8px 0px; + margin: 44px 0px 0px; + padding: 8px 0px; } diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 47234686d..ffbdfe707 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -3,49 +3,49 @@ pdf.js Multi-Page Viewer - + - + -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- -
+ +
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index ddb541175..baad7809e 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -4,455 +4,463 @@ "use strict"; var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, - var pages = []; + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } + lastPagesDrawn: [], - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; - new Font(font.name, font.file, font.properties); + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { return; - } } - clearInterval(pageInterval); + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } } - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } - } else { - if (option.selected) { - option.removeAttribute('selected'); + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); } - } - } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || + req.mozResponse || + req.responseArrayBuffer || + req.response; + + PDFViewer.readPDF(data); + } + }; - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } }; window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } - document.title = file.name; + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; } else { - PDFViewer.willJumpToPage = false; + document.getElementById('fileWrapper').style.display = 'none'; } - }; + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; }; diff --git a/pdf.js b/pdf.js index b2b6401fd..ffefc61a1 100644 --- a/pdf.js +++ b/pdf.js @@ -3275,11 +3275,8 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) { - TODO("Support bpc="+ bitsPerComponent); - this.restore(); - return; - } + if (bitsPerComponent !== 8) + error("Unsupported bpc"); var xref = this.xref; var colorSpaces = this.colorSpaces; From 8584daf7380bc9ef6f885a1de81dbcabd261bb5b Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:11:50 -0400 Subject: [PATCH 306/439] Revert ae2e637044e5abe5d4c119de133e65e0aef4a9b5^..HEAD --- multi-page-viewer.css | 197 ++++++++++ multi-page-viewer.html | 51 +++ multi-page-viewer.js | 466 ++++++++++++++++++++++ multi_page_viewer.css | 234 ++++++------ multi_page_viewer.html | 76 ++-- multi_page_viewer.js | 850 +++++++++++++++++++++-------------------- pdf.js | 7 +- 7 files changed, 1300 insertions(+), 581 deletions(-) create mode 100644 multi-page-viewer.css create mode 100644 multi-page-viewer.html create mode 100644 multi-page-viewer.js diff --git a/multi-page-viewer.css b/multi-page-viewer.css new file mode 100644 index 000000000..7f4701022 --- /dev/null +++ b/multi-page-viewer.css @@ -0,0 +1,197 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +body { + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; +} + +canvas { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +span { + font-size: 0.8em; +} + +.control { + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; +} + +.control > input { + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > select { + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); +} + +.control > span { + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; +} + +.control .label { + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; +} + +.page { + width: 816px; + height: 1056px; + margin: 10px auto; +} + +#controls { + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; +} + +#controls input { + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; +} + +#previousPageButton { + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#previousPageButton.down { + background: url('images/buttons.png') no-repeat 0px -46px; +} + +#previousPageButton.disabled { + background: url('images/buttons.png') no-repeat 0px 0px; +} + +#nextPageButton { + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; +} + +#nextPageButton.down { + background: url('images/buttons.png') no-repeat -28px -46px; +} + +#nextPageButton.disabled { + background: url('images/buttons.png') no-repeat -28px 0px; +} + +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + +#pageNumber { + text-align: right; +} + +#sidebar { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + +#viewer { + margin: 44px 0px 0px; + padding: 8px 0px; +} diff --git a/multi-page-viewer.html b/multi-page-viewer.html new file mode 100644 index 000000000..ffbdfe707 --- /dev/null +++ b/multi-page-viewer.html @@ -0,0 +1,51 @@ + + + +pdf.js Multi-Page Viewer + + + + + + + + +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ +
+ + diff --git a/multi-page-viewer.js b/multi-page-viewer.js new file mode 100644 index 000000000..baad7809e --- /dev/null +++ b/multi-page-viewer.js @@ -0,0 +1,466 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +"use strict"; + +var PDFViewer = { + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, + + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); + } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || + req.mozResponse || + req.responseArrayBuffer || + req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } +}; + +window.onload = function() { + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } + + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; +}; diff --git a/multi_page_viewer.css b/multi_page_viewer.css index fce7d7b32..7f4701022 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -2,196 +2,196 @@ /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; } canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; } span { - font-size: 0.8em; + font-size: 0.8em; } .control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; } .control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; } .control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; } .page { - width: 816px; - height: 1056px; - margin: 10px auto; + width: 816px; + height: 1056px; + margin: 10px auto; } #controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; } #previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; + background: url('images/buttons.png') no-repeat 0px -46px; } #previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; + background: url('images/buttons.png') no-repeat 0px 0px; } #nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; + background: url('images/buttons.png') no-repeat -28px -46px; } #nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; + background: url('images/buttons.png') no-repeat -28px 0px; } #openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; } #openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; + background: url('images/buttons.png') no-repeat -56px -46px; } #openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; + background: url('images/buttons.png') no-repeat -56px 0px; } #fileInput { - display: none; + display: none; } #pageNumber { - text-align: right; + text-align: right; } #sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; } #sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; } #sidebarContentView { - height: auto; - width: 100px; + height: auto; + width: 100px; } #viewer { - margin: 44px 0px 0px; - padding: 8px 0px; + margin: 44px 0px 0px; + padding: 8px 0px; } diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 47234686d..ffbdfe707 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -3,49 +3,49 @@ pdf.js Multi-Page Viewer - + - + -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- -
+ +
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index ddb541175..baad7809e 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -4,455 +4,463 @@ "use strict"; var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); + queryParams: {}, + + element: null, + + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, - var pages = []; + willJumpToPage: false, + + pdf: null, + + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } + lastPagesDrawn: [], - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; - new Font(font.name, font.file, font.properties); + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { return; - } } - clearInterval(pageInterval); + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } } - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } - } else { - if (option.selected) { - option.removeAttribute('selected'); + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); } - } - } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || + req.mozResponse || + req.responseArrayBuffer || + req.response; + + PDFViewer.readPDF(data); + } + }; - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; - } }; window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); + } - document.title = file.name; + return params; + }(); + + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; }; - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; } else { - PDFViewer.willJumpToPage = false; + document.getElementById('fileWrapper').style.display = 'none'; } - }; + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; }; diff --git a/pdf.js b/pdf.js index b2b6401fd..ffefc61a1 100644 --- a/pdf.js +++ b/pdf.js @@ -3275,11 +3275,8 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) { - TODO("Support bpc="+ bitsPerComponent); - this.restore(); - return; - } + if (bitsPerComponent !== 8) + error("Unsupported bpc"); var xref = this.xref; var colorSpaces = this.colorSpaces; From d256253d62120a5edc4437ed58c8cc22300afe11 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:12:39 -0400 Subject: [PATCH 307/439] Fixed file renaming issues. --- multi_page_viewer.css | 197 ----------------- multi_page_viewer.html | 51 ----- multi_page_viewer.js | 466 ----------------------------------------- 3 files changed, 714 deletions(-) delete mode 100644 multi_page_viewer.css delete mode 100644 multi_page_viewer.html delete mode 100644 multi_page_viewer.js diff --git a/multi_page_viewer.css b/multi_page_viewer.css deleted file mode 100644 index 7f4701022..000000000 --- a/multi_page_viewer.css +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; -} - -canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; -} - -span { - font-size: 0.8em; -} - -.control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; -} - -.control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; -} - -.control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; -} - -.page { - width: 816px; - height: 1056px; - margin: 10px auto; -} - -#controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; -} - -#previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; -} - -#previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; -} - -#nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; -} - -#nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; -} - -#openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; -} - -#openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; -} - -#openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; -} - -#fileInput { - display: none; -} - -#pageNumber { - text-align: right; -} - -#sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; -} - -#sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; -} - -#sidebarContentView { - height: auto; - width: 100px; -} - -#viewer { - margin: 44px 0px 0px; - padding: 8px 0px; -} diff --git a/multi_page_viewer.html b/multi_page_viewer.html deleted file mode 100644 index ffbdfe707..000000000 --- a/multi_page_viewer.html +++ /dev/null @@ -1,51 +0,0 @@ - - - -pdf.js Multi-Page Viewer - - - - - - - - -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- -
- - diff --git a/multi_page_viewer.js b/multi_page_viewer.js deleted file mode 100644 index baad7809e..000000000 --- a/multi_page_viewer.js +++ /dev/null @@ -1,466 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -"use strict"; - -var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } -}; - -window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; From f9687a1707adc61d17aff2533b8498bfbfedff82 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:12:39 -0400 Subject: [PATCH 308/439] Fixed file renaming issues. --- multi_page_viewer.css | 197 ----------------- multi_page_viewer.html | 51 ----- multi_page_viewer.js | 466 ----------------------------------------- 3 files changed, 714 deletions(-) delete mode 100644 multi_page_viewer.css delete mode 100644 multi_page_viewer.html delete mode 100644 multi_page_viewer.js diff --git a/multi_page_viewer.css b/multi_page_viewer.css deleted file mode 100644 index 7f4701022..000000000 --- a/multi_page_viewer.css +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; -} - -canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; -} - -span { - font-size: 0.8em; -} - -.control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; -} - -.control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); -} - -.control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; -} - -.control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; -} - -.page { - width: 816px; - height: 1056px; - margin: 10px auto; -} - -#controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; -} - -#controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; -} - -#previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; -} - -#previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; -} - -#nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; -} - -#nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; -} - -#nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; -} - -#openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; -} - -#openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; -} - -#openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; -} - -#fileInput { - display: none; -} - -#pageNumber { - text-align: right; -} - -#sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; -} - -#sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; -} - -#sidebarContentView { - height: auto; - width: 100px; -} - -#viewer { - margin: 44px 0px 0px; - padding: 8px 0px; -} diff --git a/multi_page_viewer.html b/multi_page_viewer.html deleted file mode 100644 index ffbdfe707..000000000 --- a/multi_page_viewer.html +++ /dev/null @@ -1,51 +0,0 @@ - - - -pdf.js Multi-Page Viewer - - - - - - - - -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - -
- -
- - diff --git a/multi_page_viewer.js b/multi_page_viewer.js deleted file mode 100644 index baad7809e..000000000 --- a/multi_page_viewer.js +++ /dev/null @@ -1,466 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ - -"use strict"; - -var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, - - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, - - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, - - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, - - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } -}; - -window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; - } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); - - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } - }; -}; From 78ce1863bb4e91f5b66e9a54432116957249327e Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:17:31 -0400 Subject: [PATCH 309/439] Fixed file renaming issues. --- multi-page-viewer.css => multi_page_viewer.css | 0 multi-page-viewer.html => multi_page_viewer.html | 0 multi-page-viewer.js => multi_page_viewer.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename multi-page-viewer.css => multi_page_viewer.css (100%) rename multi-page-viewer.html => multi_page_viewer.html (100%) rename multi-page-viewer.js => multi_page_viewer.js (100%) diff --git a/multi-page-viewer.css b/multi_page_viewer.css similarity index 100% rename from multi-page-viewer.css rename to multi_page_viewer.css diff --git a/multi-page-viewer.html b/multi_page_viewer.html similarity index 100% rename from multi-page-viewer.html rename to multi_page_viewer.html diff --git a/multi-page-viewer.js b/multi_page_viewer.js similarity index 100% rename from multi-page-viewer.js rename to multi_page_viewer.js From b18006a055b07eefc6b1495c7a581c1fa55681b5 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:17:31 -0400 Subject: [PATCH 310/439] Fixed file renaming issues. --- multi-page-viewer.css => multi_page_viewer.css | 0 multi-page-viewer.html => multi_page_viewer.html | 0 multi-page-viewer.js => multi_page_viewer.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename multi-page-viewer.css => multi_page_viewer.css (100%) rename multi-page-viewer.html => multi_page_viewer.html (100%) rename multi-page-viewer.js => multi_page_viewer.js (100%) diff --git a/multi-page-viewer.css b/multi_page_viewer.css similarity index 100% rename from multi-page-viewer.css rename to multi_page_viewer.css diff --git a/multi-page-viewer.html b/multi_page_viewer.html similarity index 100% rename from multi-page-viewer.html rename to multi_page_viewer.html diff --git a/multi-page-viewer.js b/multi_page_viewer.js similarity index 100% rename from multi-page-viewer.js rename to multi_page_viewer.js From fa045139ad1e783d85719e3b91be92073fab6bcc Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:18:07 -0400 Subject: [PATCH 311/439] Fixed vim indentation rules. --- multi_page_viewer.css | 238 +++++------ multi_page_viewer.html | 76 ++-- multi_page_viewer.js | 886 ++++++++++++++++++++--------------------- 3 files changed, 596 insertions(+), 604 deletions(-) diff --git a/multi_page_viewer.css b/multi_page_viewer.css index 7f4701022..b3eaab792 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -1,197 +1,197 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; } canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; } span { - font-size: 0.8em; + font-size: 0.8em; } .control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; } .control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; } .control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; } .page { - width: 816px; - height: 1056px; - margin: 10px auto; + width: 816px; + height: 1056px; + margin: 10px auto; } #controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; } #previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; + background: url('images/buttons.png') no-repeat 0px -46px; } #previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; + background: url('images/buttons.png') no-repeat 0px 0px; } #nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; + background: url('images/buttons.png') no-repeat -28px -46px; } #nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; + background: url('images/buttons.png') no-repeat -28px 0px; } #openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; } #openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; + background: url('images/buttons.png') no-repeat -56px -46px; } #openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; + background: url('images/buttons.png') no-repeat -56px 0px; } #fileInput { - display: none; + display: none; } #pageNumber { - text-align: right; + text-align: right; } #sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; } #sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; } #sidebarContentView { - height: auto; - width: 100px; + height: auto; + width: 100px; } #viewer { - margin: 44px 0px 0px; - padding: 8px 0px; + margin: 44px 0px 0px; + padding: 8px 0px; } diff --git a/multi_page_viewer.html b/multi_page_viewer.html index ffbdfe707..47234686d 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -3,49 +3,49 @@ pdf.js Multi-Page Viewer - + - + -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ -
+
--> +
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index baad7809e..3a02ea332 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -1,466 +1,458 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ "use strict"; var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, + queryParams: {}, - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, + element: null, - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, + willJumpToPage: false, - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + pdf: null, - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } }; window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + return params; + }(); - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; }; From b9af0da8f8bd59874b1141649b5b84dc30b7ca71 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:18:07 -0400 Subject: [PATCH 312/439] Fixed vim indentation rules. --- multi_page_viewer.css | 238 +++++------ multi_page_viewer.html | 76 ++-- multi_page_viewer.js | 886 ++++++++++++++++++++--------------------- 3 files changed, 596 insertions(+), 604 deletions(-) diff --git a/multi_page_viewer.css b/multi_page_viewer.css index 7f4701022..b3eaab792 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -1,197 +1,197 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ body { - background-color: #929292; - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; - margin: 0px; - padding: 0px; + background-color: #929292; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; + margin: 0px; + padding: 0px; } canvas { - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; } span { - font-size: 0.8em; + font-size: 0.8em; } .control { - display: inline-block; - float: left; - margin: 0px 20px 0px 0px; - padding: 0px 4px 0px 0px; + display: inline-block; + float: left; + margin: 0px 20px 0px 0px; + padding: 0px 4px 0px 0px; } .control > input { - float: left; - border: 1px solid #4d4d4d; - height: 20px; - padding: 0px; - margin: 0px 2px 0px 0px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 20px; + padding: 0px; + margin: 0px 2px 0px 0px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > select { - float: left; - border: 1px solid #4d4d4d; - height: 22px; - padding: 2px 0px 0px; - margin: 0px 0px 1px; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); - -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + float: left; + border: 1px solid #4d4d4d; + height: 22px; + padding: 2px 0px 0px; + margin: 0px 0px 1px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25); } .control > span { - cursor: default; - float: left; - height: 18px; - margin: 5px 2px 0px; - padding: 0px; - user-select: none; - -moz-user-select: none; - -webkit-user-select: none; + cursor: default; + float: left; + height: 18px; + margin: 5px 2px 0px; + padding: 0px; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; } .control .label { - clear: both; - float: left; - font-size: 0.65em; - margin: 2px 0px 0px; - position: relative; - text-align: center; - width: 100%; + clear: both; + float: left; + font-size: 0.65em; + margin: 2px 0px 0px; + position: relative; + text-align: center; + width: 100%; } .page { - width: 816px; - height: 1056px; - margin: 10px auto; + width: 816px; + height: 1056px; + margin: 10px auto; } #controls { - background-color: #eee; - border-bottom: 1px solid #666; - padding: 4px 0px 0px 8px; - position: fixed; - left: 0px; - top: 0px; - height: 40px; - width: 100%; - box-shadow: 0px 2px 8px #000; - -moz-box-shadow: 0px 2px 8px #000; - -webkit-box-shadow: 0px 2px 8px #000; + background-color: #eee; + border-bottom: 1px solid #666; + padding: 4px 0px 0px 8px; + position: fixed; + left: 0px; + top: 0px; + height: 40px; + width: 100%; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #controls input { - user-select: text; - -moz-user-select: text; - -webkit-user-select: text; + user-select: text; + -moz-user-select: text; + -webkit-user-select: text; } #previousPageButton { - background: url('images/buttons.png') no-repeat 0px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat 0px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #previousPageButton.down { - background: url('images/buttons.png') no-repeat 0px -46px; + background: url('images/buttons.png') no-repeat 0px -46px; } #previousPageButton.disabled { - background: url('images/buttons.png') no-repeat 0px 0px; + background: url('images/buttons.png') no-repeat 0px 0px; } #nextPageButton { - background: url('images/buttons.png') no-repeat -28px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px; - width: 28px; - height: 23px; + background: url('images/buttons.png') no-repeat -28px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px; + width: 28px; + height: 23px; } #nextPageButton.down { - background: url('images/buttons.png') no-repeat -28px -46px; + background: url('images/buttons.png') no-repeat -28px -46px; } #nextPageButton.disabled { - background: url('images/buttons.png') no-repeat -28px 0px; + background: url('images/buttons.png') no-repeat -28px 0px; } #openFileButton { - background: url('images/buttons.png') no-repeat -56px -23px; - cursor: default; - display: inline-block; - float: left; - margin: 0px 0px 0px 3px; - width: 29px; - height: 23px; + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; } #openFileButton.down { - background: url('images/buttons.png') no-repeat -56px -46px; + background: url('images/buttons.png') no-repeat -56px -46px; } #openFileButton.disabled { - background: url('images/buttons.png') no-repeat -56px 0px; + background: url('images/buttons.png') no-repeat -56px 0px; } #fileInput { - display: none; + display: none; } #pageNumber { - text-align: right; + text-align: right; } #sidebar { - background-color: rgba(0, 0, 0, 0.8); - position: fixed; - width: 150px; - top: 62px; - bottom: 18px; - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - -moz-border-radius-topright: 8px; - -moz-border-radius-bottomright: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-right-radius: 8px; + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; } #sidebarScrollView { - position: absolute; - overflow: hidden; - overflow-y: auto; - top: 40px; - right: 10px; - bottom: 10px; - left: 10px; + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; } #sidebarContentView { - height: auto; - width: 100px; + height: auto; + width: 100px; } #viewer { - margin: 44px 0px 0px; - padding: 8px 0px; + margin: 44px 0px 0px; + padding: 8px 0px; } diff --git a/multi_page_viewer.html b/multi_page_viewer.html index ffbdfe707..47234686d 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -3,49 +3,49 @@ pdf.js Multi-Page Viewer - + - + -
- - - - Previous/Next - - - - / - -- - Page Number - - - - Zoom - - - - - Open File - +
+ + + + Previous/Next + + + + / + -- + Page Number + + + + Zoom + + + + + Open File + +
+ -
+
--> +
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index baad7809e..3a02ea332 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -1,466 +1,458 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / -/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ "use strict"; var PDFViewer = { - queryParams: {}, - - element: null, - - previousPageButton: null, - nextPageButton: null, - pageNumberInput: null, - scaleSelect: null, - fileInput: null, - - willJumpToPage: false, - - pdf: null, - - url: 'compressed.tracemonkey-pldi-09.pdf', - pageNumber: 1, - numberOfPages: 1, - - scale: 1.0, - - pageWidth: function() { - return 816 * PDFViewer.scale; - }, - - pageHeight: function() { - return 1056 * PDFViewer.scale; - }, - - lastPagesDrawn: [], - - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. - var windowTop = window.pageYOffset; - var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); - - var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); - } - - return pages; - }, + queryParams: {}, - createPage: function(num) { - var anchor = document.createElement('a'); - anchor.name = '' + num; - - var div = document.createElement('div'); - div.id = 'pageContainer' + num; - div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; - - PDFViewer.element.appendChild(anchor); - PDFViewer.element.appendChild(div); - }, - - removePage: function(num) { - var div = document.getElementById('pageContainer' + num); - - if (div) { - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - } - }, - - drawPage: function(num) { - if (!PDFViewer.pdf) { - return; - } - - var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - - if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - - var page = PDFViewer.pdf.getPage(num); - - canvas.id = 'page' + num; - canvas.mozOpaque = true; - - // Canvas dimensions must be specified in CSS pixels. CSS pixels - // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - - var gfx = new CanvasGraphics(ctx); - var fonts = []; - - // page.compile will collect all fonts for us, once we have loaded them - // we can trigger the actual page rendering with page.display - page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; - } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; - } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); - } - }, - - changeScale: function(num) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.scale = num / 100; - - var i; - - if (PDFViewer.pdf) { - for (i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - } - - for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { - var option = PDFViewer.scaleSelect.childNodes[i]; - - if (option.value == num) { - if (!option.selected) { - option.selected = 'selected'; - } - } else { - if (option.selected) { - option.removeAttribute('selected'); - } - } - } - - PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; - }, - - goToPage: function(num) { - if (1 <= num && num <= PDFViewer.numberOfPages) { - PDFViewer.pageNumber = num; - PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; - PDFViewer.willJumpToPage = true; - - document.location.hash = PDFViewer.pageNumber; - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } - }, + element: null, - goToPreviousPage: function() { - if (PDFViewer.pageNumber > 1) { - PDFViewer.goToPage(--PDFViewer.pageNumber); - } - }, + previousPageButton: null, + nextPageButton: null, + pageNumberInput: null, + scaleSelect: null, + fileInput: null, - goToNextPage: function() { - if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { - PDFViewer.goToPage(++PDFViewer.pageNumber); - } - }, + willJumpToPage: false, - openURL: function(url) { - PDFViewer.url = url; - document.title = url; - - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; - - req.onreadystatechange = function() { - if (req.readyState === 4 && req.status === req.expected) { - var data = req.mozResponseArrayBuffer || - req.mozResponse || - req.responseArrayBuffer || - req.response; - - PDFViewer.readPDF(data); - } - }; - - req.send(null); - }, - - readPDF: function(data) { - while (PDFViewer.element.hasChildNodes()) { - PDFViewer.element.removeChild(PDFViewer.element.firstChild); - } - - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + pdf: null, - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - document.location.hash = 1; - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; + url: 'compressed.tracemonkey-pldi-09.pdf', + pageNumber: 1, + numberOfPages: 1, + + scale: 1.0, + + pageWidth: function() { + return 816 * PDFViewer.scale; + }, + + pageHeight: function() { + return 1056 * PDFViewer.scale; + }, + + lastPagesDrawn: [], + + visiblePages: function() { + var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + var windowTop = window.pageYOffset; + var windowBottom = window.pageYOffset + window.innerHeight; + var pageStartIndex = Math.floor(windowTop / pageHeight); + var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pages = []; + + for (var i = pageStartIndex; i <= pageStopIndex; i++) { + pages.push(i + 1); } + + return pages; + }, + + createPage: function(num) { + var anchor = document.createElement('a'); + anchor.name = '' + num; + + var div = document.createElement('div'); + div.id = 'pageContainer' + num; + div.className = 'page'; + div.style.width = PDFViewer.pageWidth() + 'px'; + div.style.height = PDFViewer.pageHeight() + 'px'; + + PDFViewer.element.appendChild(anchor); + PDFViewer.element.appendChild(div); + }, + + removePage: function(num) { + var div = document.getElementById('pageContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawPage: function(num) { + if (!PDFViewer.pdf) { + return; + } + + var div = document.getElementById('pageContainer' + num); + var canvas = document.createElement('canvas'); + + if (div && !div.hasChildNodes()) { + div.appendChild(canvas); + + var page = PDFViewer.pdf.getPage(num); + + canvas.id = 'page' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = PDFViewer.pageWidth(); + canvas.height = PDFViewer.pageHeight(); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + var fonts = []; + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + page.compile(gfx, fonts); + + var areFontsReady = true; + + // Inspect fonts and translate the missing one + var fontCount = fonts.length; + + for (var i = 0; i < fontCount; i++) { + var font = fonts[i]; + + if (Fonts[font.name]) { + areFontsReady = areFontsReady && !Fonts[font.name].loading; + continue; + } + + new Font(font.name, font.file, font.properties); + + areFontsReady = false; + } + + var pageInterval; + + var delayLoadFont = function() { + for (var i = 0; i < fontCount; i++) { + if (Fonts[font.name].loading) { + return; + } + } + + clearInterval(pageInterval); + + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + + PDFViewer.drawPage(num); + } + + if (!areFontsReady) { + pageInterval = setInterval(delayLoadFont, 10); + return; + } + + page.display(gfx); + } + }, + + changeScale: function(num) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.scale = num / 100; + + var i; + + if (PDFViewer.pdf) { + for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + } + } + + for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { + var option = PDFViewer.scaleSelect.childNodes[i]; + + if (option.value == num) { + if (!option.selected) { + option.selected = 'selected'; + } + } else { + if (option.selected) { + option.removeAttribute('selected'); + } + } + } + + PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + }, + + goToPage: function(num) { + if (1 <= num && num <= PDFViewer.numberOfPages) { + PDFViewer.pageNumber = num; + PDFViewer.pageNumberInput.value = PDFViewer.pageNumber; + PDFViewer.willJumpToPage = true; + + document.location.hash = PDFViewer.pageNumber; + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } + }, + + goToPreviousPage: function() { + if (PDFViewer.pageNumber > 1) { + PDFViewer.goToPage(--PDFViewer.pageNumber); + } + }, + + goToNextPage: function() { + if (PDFViewer.pageNumber < PDFViewer.numberOfPages) { + PDFViewer.goToPage(++PDFViewer.pageNumber); + } + }, + + openURL: function(url) { + PDFViewer.url = url; + document.title = url; + + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + + req.onreadystatechange = function() { + if (req.readyState === 4 && req.status === req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response; + + PDFViewer.readPDF(data); + } + }; + + req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } }; window.onload = function() { - - // Parse the URL query parameters into a cached object. - PDFViewer.queryParams = function() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = {}; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); - } - - return params; - }(); - - PDFViewer.element = document.getElementById('viewer'); - - PDFViewer.pageNumberInput = document.getElementById('pageNumber'); - PDFViewer.pageNumberInput.onkeydown = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // Up arrow key. - if (charCode === 38) { - PDFViewer.goToNextPage(); - this.select(); - } - - // Down arrow key. - else if (charCode === 40) { - PDFViewer.goToPreviousPage(); - this.select(); - } - - // All other non-numeric keys (excluding Left arrow, Right arrow, - // Backspace, and Delete keys). - else if ((charCode < 48 || charCode > 57) && - charCode !== 8 && // Backspace - charCode !== 46 && // Delete - charCode !== 37 && // Left arrow - charCode !== 39 // Right arrow - ) { - return false; - } - - return true; - }; - PDFViewer.pageNumberInput.onkeyup = function(evt) { - var charCode = evt.charCode || evt.keyCode; - - // All numeric keys, Backspace, and Delete. - if ((charCode >= 48 && charCode <= 57) || - charCode === 8 || // Backspace - charCode === 46 // Delete - ) { - PDFViewer.goToPage(this.value); - } - - this.focus(); - }; - - PDFViewer.previousPageButton = document.getElementById('previousPageButton'); - PDFViewer.previousPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToPreviousPage(); - } - }; - PDFViewer.previousPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.previousPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.previousPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; + + // Parse the URL query parameters into a cached object. + PDFViewer.queryParams = function() { + var qs = window.location.search.substring(1); + var kvs = qs.split('&'); + var params = {}; - PDFViewer.nextPageButton = document.getElementById('nextPageButton'); - PDFViewer.nextPageButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.goToNextPage(); - } - }; - PDFViewer.nextPageButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - PDFViewer.nextPageButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - PDFViewer.nextPageButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.scaleSelect = document.getElementById('scaleSelect'); - PDFViewer.scaleSelect.onchange = function(evt) { - PDFViewer.changeScale(parseInt(this.value)); - }; - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var openFileButton = document.getElementById('openFileButton'); - openFileButton.onclick = function(evt) { - if (this.className.indexOf('disabled') === -1) { - PDFViewer.fileInput.click(); - } - }; - openFileButton.onmousedown = function(evt) { - if (this.className.indexOf('disabled') === -1) { - this.className = 'down'; - } - }; - openFileButton.onmouseup = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - openFileButton.onmouseout = function(evt) { - this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; - }; - - PDFViewer.fileInput = document.getElementById('fileInput'); - PDFViewer.fileInput.onchange = function(evt) { - var files = evt.target.files; - - if (files.length > 0) { - var file = files[0]; - var fileReader = new FileReader(); - - document.title = file.name; - - // Read the local file into a Uint8Array. - fileReader.onload = function(evt) { - var data = evt.target.result; - var buffer = new ArrayBuffer(data.length); - var uint8Array = new Uint8Array(buffer); - - for (var i = 0; i < data.length; i++) { - uint8Array[i] = data.charCodeAt(i); - } - - PDFViewer.readPDF(uint8Array); - }; - - // Read as a binary string since "readAsArrayBuffer" is not yet - // implemented in Firefox. - fileReader.readAsBinaryString(file); - } - }; - PDFViewer.fileInput.value = null; - } else { - document.getElementById('fileWrapper').style.display = 'none'; + for (var i = 0; i < kvs.length; ++i) { + var kv = kvs[i].split('='); + params[unescape(kv[0])] = unescape(kv[1]); } - - PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; - PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + return params; + }(); - window.onscroll = function(evt) { - var lastPagesDrawn = PDFViewer.lastPagesDrawn; - var visiblePages = PDFViewer.visiblePages(); - - var pagesToDraw = []; - var pagesToKeep = []; - var pagesToRemove = []; - - var i; - - // Determine which visible pages were not previously drawn. - for (i = 0; i < visiblePages.length; i++) { - if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { - pagesToDraw.push(visiblePages[i]); - PDFViewer.drawPage(visiblePages[i]); - } else { - pagesToKeep.push(visiblePages[i]); - } - } - - // Determine which previously drawn pages are no longer visible. - for (i = 0; i < lastPagesDrawn.length; i++) { - if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { - pagesToRemove.push(lastPagesDrawn[i]); - PDFViewer.removePage(lastPagesDrawn[i]); - } - } - - PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); - - // Update the page number input with the current page number. - if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { - PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; - } else { - PDFViewer.willJumpToPage = false; - } + PDFViewer.element = document.getElementById('viewer'); + + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); + PDFViewer.pageNumberInput.onkeydown = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // Up arrow key. + if (charCode === 38) { + PDFViewer.goToNextPage(); + this.select(); + } + + // Down arrow key. + else if (charCode === 40) { + PDFViewer.goToPreviousPage(); + this.select(); + } + + // All other non-numeric keys (excluding Left arrow, Right arrow, + // Backspace, and Delete keys). + else if ((charCode < 48 || charCode > 57) && + charCode !== 8 && // Backspace + charCode !== 46 && // Delete + charCode !== 37 && // Left arrow + charCode !== 39 // Right arrow + ) { + return false; + } + + return true; + }; + PDFViewer.pageNumberInput.onkeyup = function(evt) { + var charCode = evt.charCode || evt.keyCode; + + // All numeric keys, Backspace, and Delete. + if ((charCode >= 48 && charCode <= 57) || + charCode === 8 || // Backspace + charCode === 46 // Delete + ) { + PDFViewer.goToPage(this.value); + } + + this.focus(); + }; + + PDFViewer.previousPageButton = document.getElementById('previousPageButton'); + PDFViewer.previousPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToPreviousPage(); + } + }; + PDFViewer.previousPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.previousPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.previousPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.nextPageButton = document.getElementById('nextPageButton'); + PDFViewer.nextPageButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.goToNextPage(); + } + }; + PDFViewer.nextPageButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + PDFViewer.nextPageButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + PDFViewer.nextPageButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.scaleSelect = document.getElementById('scaleSelect'); + PDFViewer.scaleSelect.onchange = function(evt) { + PDFViewer.changeScale(parseInt(this.value)); + }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } + + PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; + PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; + + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); + + window.onscroll = function(evt) { + var lastPagesDrawn = PDFViewer.lastPagesDrawn; + var visiblePages = PDFViewer.visiblePages(); + + var pagesToDraw = []; + var pagesToKeep = []; + var pagesToRemove = []; + + var i; + + // Determine which visible pages were not previously drawn. + for (i = 0; i < visiblePages.length; i++) { + if (lastPagesDrawn.indexOf(visiblePages[i]) === -1) { + pagesToDraw.push(visiblePages[i]); + PDFViewer.drawPage(visiblePages[i]); + } else { + pagesToKeep.push(visiblePages[i]); + } + } + + // Determine which previously drawn pages are no longer visible. + for (i = 0; i < lastPagesDrawn.length; i++) { + if (visiblePages.indexOf(lastPagesDrawn[i]) === -1) { + pagesToRemove.push(lastPagesDrawn[i]); + PDFViewer.removePage(lastPagesDrawn[i]); + } + } + + PDFViewer.lastPagesDrawn = pagesToDraw.concat(pagesToKeep); + + // Update the page number input with the current page number. + if (!PDFViewer.willJumpToPage && visiblePages.length > 0) { + PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0]; + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : ''; + } else { + PDFViewer.willJumpToPage = false; + } + }; }; From 6501c2100f5a3a9ee9d1406de6331c793a1efbde Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:37:40 -0400 Subject: [PATCH 313/439] Brought pdf.js back up to the latest revision. --- pdf.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index ffefc61a1..b2b6401fd 100644 --- a/pdf.js +++ b/pdf.js @@ -3275,8 +3275,11 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) - error("Unsupported bpc"); + if (bitsPerComponent !== 8) { + TODO("Support bpc="+ bitsPerComponent); + this.restore(); + return; + } var xref = this.xref; var colorSpaces = this.colorSpaces; From c5b889a47baad3a581cda3861c4137a1f63f8943 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Thu, 23 Jun 2011 21:37:40 -0400 Subject: [PATCH 314/439] Brought pdf.js back up to the latest revision. --- pdf.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index ffefc61a1..b2b6401fd 100644 --- a/pdf.js +++ b/pdf.js @@ -3275,8 +3275,11 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) - error("Unsupported bpc"); + if (bitsPerComponent !== 8) { + TODO("Support bpc="+ bitsPerComponent); + this.restore(); + return; + } var xref = this.xref; var colorSpaces = this.colorSpaces; From 86f197dabac95eeeff51c60f3373d6ee5565a6ab Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 11:47:22 +0200 Subject: [PATCH 315/439] Start adding a FontLoader class to isolate the font-loaded hack --- fonts.js | 53 ++++++++++++++++++++++++++++++++++------------------- viewer.js | 35 +++++++---------------------------- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/fonts.js b/fonts.js index a995c55eb..0a1974571 100644 --- a/fonts.js +++ b/fonts.js @@ -80,6 +80,35 @@ var Fonts = { } }; +var FontsLoader = { + bind: function(fonts) { + var worker = (typeof window == "undefined"); + var ready = true; + + for (var i = 0; i < fonts.length; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + ready = ready && !Fonts[font.name].loading; + continue; + } else { + ready = false; + } + + var obj = new Font(font.name, font.file, font.properties); + + var str = ""; + var data = Fonts[font.name].data; + var length = data.length; + for (var j = 0; j < length; j++) + str += String.fromCharCode(data[j]); + + worker ? obj.bindWorker(str) : obj.bindDOM(str); + } + return ready; + } +}; + + /** * 'Font' is the class the outside world should use, it encapsulate all the font * decoding logics whatever type it is (assuming the font type is supported). @@ -113,13 +142,14 @@ var Font = (function () { return; } + var data; switch (properties.type) { case "Type1": var cff = new CFF(name, file, properties); this.mimetype = "font/opentype"; // Wrap the CFF data inside an OTF font file - this.font = this.convert(name, cff, properties); + data = this.convert(name, cff, properties); break; case "TrueType": @@ -127,7 +157,7 @@ var Font = (function () { // Repair the TrueType file if it is can be damaged in the point of // view of the sanitizer - this.font = this.checkAndRepair(name, file, properties); + data = this.checkAndRepair(name, file, properties); break; default: @@ -135,28 +165,12 @@ var Font = (function () { break; } - var data = this.font; Fonts[name] = { data: data, properties: properties, loading: true, cache: Object.create(null) - } - - // Convert data to a string. - var dataStr = ""; - var length = data.length; - for (var i = 0; i < length; ++i) - dataStr += String.fromCharCode(data[i]); - - // Attach the font to the document. If this script is runnig in a worker, - // call `bindWorker`, which sends stuff over to the main thread. - if (typeof window != "undefined") { - this.bindDOM(dataStr); - } else { - this.bindWorker(dataStr); - } - + }; }; function stringToArray(str) { @@ -1420,6 +1434,7 @@ CFF.prototype = { i++; } error("failing with i = " + i + " in charstring:" + charstring + "(" + charstring.length + ")"); + return []; }, wrap: function wrap(name, charstrings, subrs, properties) { diff --git a/viewer.js b/viewer.js index 41aaf354c..2bcff50a6 100644 --- a/viewer.js +++ b/viewer.js @@ -3,7 +3,7 @@ "use strict"; -var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageInterval; +var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageTimeout; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; @@ -52,7 +52,7 @@ function gotoPage(num) { } function displayPage(num) { - window.clearInterval(pageInterval); + window.clearTimeout(pageTimeout); document.getElementById("pageNumber").value = num; @@ -75,28 +75,12 @@ function displayPage(num) { page.compile(gfx, fonts); var t2 = Date.now(); - var fontsReady = true; - - // Inspect fonts and translate the missing one - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; + function loadFont() { + if (!FontsLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } - - function delayLoadFont() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) - return; - } - window.clearInterval(pageInterval); - var t3 = Date.now(); page.display(gfx); @@ -106,12 +90,7 @@ function displayPage(num) { var infoDisplay = document.getElementById("info"); infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; }; - - if (fontsReady) { - delayLoadFont(); - } else { - pageInterval = setInterval(delayLoadFont, 10); - } + loadFont(); } function nextPage() { From 07ca9bfec54728bb9e368b60877695e6382c1555 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 11:47:22 +0200 Subject: [PATCH 316/439] Start adding a FontLoader class to isolate the font-loaded hack --- fonts.js | 53 ++++++++++++++++++++++++++++++++++------------------- viewer.js | 35 +++++++---------------------------- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/fonts.js b/fonts.js index a995c55eb..0a1974571 100644 --- a/fonts.js +++ b/fonts.js @@ -80,6 +80,35 @@ var Fonts = { } }; +var FontsLoader = { + bind: function(fonts) { + var worker = (typeof window == "undefined"); + var ready = true; + + for (var i = 0; i < fonts.length; i++) { + var font = fonts[i]; + if (Fonts[font.name]) { + ready = ready && !Fonts[font.name].loading; + continue; + } else { + ready = false; + } + + var obj = new Font(font.name, font.file, font.properties); + + var str = ""; + var data = Fonts[font.name].data; + var length = data.length; + for (var j = 0; j < length; j++) + str += String.fromCharCode(data[j]); + + worker ? obj.bindWorker(str) : obj.bindDOM(str); + } + return ready; + } +}; + + /** * 'Font' is the class the outside world should use, it encapsulate all the font * decoding logics whatever type it is (assuming the font type is supported). @@ -113,13 +142,14 @@ var Font = (function () { return; } + var data; switch (properties.type) { case "Type1": var cff = new CFF(name, file, properties); this.mimetype = "font/opentype"; // Wrap the CFF data inside an OTF font file - this.font = this.convert(name, cff, properties); + data = this.convert(name, cff, properties); break; case "TrueType": @@ -127,7 +157,7 @@ var Font = (function () { // Repair the TrueType file if it is can be damaged in the point of // view of the sanitizer - this.font = this.checkAndRepair(name, file, properties); + data = this.checkAndRepair(name, file, properties); break; default: @@ -135,28 +165,12 @@ var Font = (function () { break; } - var data = this.font; Fonts[name] = { data: data, properties: properties, loading: true, cache: Object.create(null) - } - - // Convert data to a string. - var dataStr = ""; - var length = data.length; - for (var i = 0; i < length; ++i) - dataStr += String.fromCharCode(data[i]); - - // Attach the font to the document. If this script is runnig in a worker, - // call `bindWorker`, which sends stuff over to the main thread. - if (typeof window != "undefined") { - this.bindDOM(dataStr); - } else { - this.bindWorker(dataStr); - } - + }; }; function stringToArray(str) { @@ -1420,6 +1434,7 @@ CFF.prototype = { i++; } error("failing with i = " + i + " in charstring:" + charstring + "(" + charstring.length + ")"); + return []; }, wrap: function wrap(name, charstrings, subrs, properties) { diff --git a/viewer.js b/viewer.js index 41aaf354c..2bcff50a6 100644 --- a/viewer.js +++ b/viewer.js @@ -3,7 +3,7 @@ "use strict"; -var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageInterval; +var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageTimeout; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; @@ -52,7 +52,7 @@ function gotoPage(num) { } function displayPage(num) { - window.clearInterval(pageInterval); + window.clearTimeout(pageTimeout); document.getElementById("pageNumber").value = num; @@ -75,28 +75,12 @@ function displayPage(num) { page.compile(gfx, fonts); var t2 = Date.now(); - var fontsReady = true; - - // Inspect fonts and translate the missing one - var count = fonts.length; - for (var i = 0; i < count; i++) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; + function loadFont() { + if (!FontsLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } - - function delayLoadFont() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) - return; - } - window.clearInterval(pageInterval); - var t3 = Date.now(); page.display(gfx); @@ -106,12 +90,7 @@ function displayPage(num) { var infoDisplay = document.getElementById("info"); infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms"; }; - - if (fontsReady) { - delayLoadFont(); - } else { - pageInterval = setInterval(delayLoadFont, 10); - } + loadFont(); } function nextPage() { From 3955ed1b4c6a6ee0d0643c78ab6ee4f0c5d4b440 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 11:58:05 +0200 Subject: [PATCH 317/439] Fix a bunch of warnings from Firebug strict mode --- fonts.js | 27 +++++++++++++++------------ pdf.js | 56 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/fonts.js b/fonts.js index 0a1974571..7e8aecd6d 100644 --- a/fonts.js +++ b/fonts.js @@ -599,16 +599,16 @@ var Font = (function () { return font.getBytes(); }, - convert: function font_convert(name, font, properties) { + convert: function font_convert(fontName, font, properties) { var otf = new Uint8Array(kMaxFontFileSize); function createNameTable(name) { var names = [ "See original licence", // Copyright - name, // Font family + fontName, // Font family "undefined", // Font subfamily (font weight) "uniqueID", // Unique ID - name, // Full font name + fontName, // Full font name "0.1", // Version "undefined", // Postscript name "undefined", // Trademark @@ -616,7 +616,7 @@ var Font = (function () { "undefined" // Designer ]; - var name = + var nameTable = "\x00\x00" + // format "\x00\x0A" + // Number of names Record "\x00\x7E"; // Storage @@ -633,13 +633,13 @@ var Font = (function () { "\x00\x00" + // name ID string16(str.length) + string16(strOffset); - name += nameRecord; + nameTable += nameRecord; strOffset += str.length; } - name += names.join(""); - return name; + nameTable += names.join(""); + return nameTable; } // Required Tables @@ -885,6 +885,9 @@ var FontsUtils = { bytes.set([value >> 24, value >> 16, value >> 8, value]); return [bytes[0], bytes[1], bytes[2], bytes[3]]; } + + error("This number of bytes " + bytesCount + " is not supported"); + return null; }, bytesToInteger: function fu_bytesToInteger(bytesArray) { @@ -1238,7 +1241,7 @@ var CFF = function(name, file, properties) { }; CFF.prototype = { - createCFFIndexHeader: function(objects, isByte) { + createCFFIndexHeader: function cff_createCFFIndexHeader(objects, isByte) { // First 2 bytes contains the number of objects contained into this index var count = objects.length; @@ -1275,18 +1278,18 @@ CFF.prototype = { return data; }, - encodeNumber: function(value) { + encodeNumber: function cff_encodeNumber(value) { var x = 0; if (value >= -32768 && value <= 32767) { return [ 28, value >> 8, value & 0xFF ]; } else if (value >= (-2147483647-1) && value <= 2147483647) { return [ 0xFF, value >> 24, Value >> 16, value >> 8, value & 0xFF ]; - } else { - error("Value: " + value + " is not allowed"); } + error("Value: " + value + " is not allowed"); + return null; }, - getOrderedCharStrings: function(glyphs) { + getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs) { var charstrings = []; for (var i = 0; i < glyphs.length; i++) { diff --git a/pdf.js b/pdf.js index f61250a0c..c4ebb5f24 100644 --- a/pdf.js +++ b/pdf.js @@ -71,14 +71,14 @@ var Stream = (function() { get length() { return this.end - this.start; }, - getByte: function() { + getByte: function stream_getByte() { if (this.pos >= this.end) - return; + return null; return this.bytes[this.pos++]; }, // returns subarray of original buffer // should only be read - getBytes: function(length) { + getBytes: function stream_getBytes(length) { var bytes = this.bytes; var pos = this.pos; var strEnd = this.end; @@ -93,28 +93,28 @@ var Stream = (function() { this.pos = end; return bytes.subarray(pos, end); }, - lookChar: function() { + lookChar: function stream_lookChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos]); }, - getChar: function() { + getChar: function stream_getChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos++]); }, - skip: function(n) { + skip: function stream_skip(n) { if (!n) n = 1; this.pos += n; }, - reset: function() { + reset: function stream_reset() { this.pos = this.start; }, - moveStart: function() { + moveStart: function stream_moveStart() { this.start = this.pos; }, - makeSubStream: function(start, length, dict) { + makeSubStream: function stream_makeSubstream(start, length, dict) { return new Stream(this.bytes.buffer, start, length, dict); } }; @@ -146,7 +146,7 @@ var DecodeStream = (function() { } constructor.prototype = { - ensureBuffer: function(requested) { + ensureBuffer: function decodestream_ensureBuffer(requested) { var buffer = this.buffer; var current = buffer ? buffer.byteLength : 0; if (requested < current) @@ -159,16 +159,16 @@ var DecodeStream = (function() { buffer2[i] = buffer[i]; return this.buffer = buffer2; }, - getByte: function() { + getByte: function decodestream_getByte() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return this.buffer[this.pos++]; }, - getBytes: function(length) { + getBytes: function decodestream_getBytes(length) { var pos = this.pos; if (length) { @@ -191,25 +191,25 @@ var DecodeStream = (function() { this.pos = end; return this.buffer.subarray(pos, end) }, - lookChar: function() { + lookChar: function decodestream_lookChar() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos]); }, - getChar: function() { + getChar: function decodestream_getChar() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos++]); }, - skip: function(n) { + skip: function decodestream_skip(n) { if (!n) n = 1; this.pos += n; @@ -635,6 +635,7 @@ var PredictorStream = (function() { var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3; DecodeStream.call(this); + return this; } constructor.prototype = Object.create(DecodeStream.prototype); @@ -905,7 +906,9 @@ var Dict = (function() { constructor.prototype = { get: function(key) { - return this.map[key]; + if (key in this.map) + return this.map[key]; + return null; }, get2: function(key1, key2) { return this.get(key1) || this.get(key2); @@ -1590,7 +1593,7 @@ var XRef = (function() { } constructor.prototype = { - readXRefTable: function(parser) { + readXRefTable: function readXRefTable(parser) { var obj; while (true) { if (IsCmd(obj = parser.getObj(), "trailer")) @@ -1661,7 +1664,7 @@ var XRef = (function() { return dict; }, - readXRefStream: function(stream) { + readXRefStream: function readXRefStream(stream) { var streamParameters = stream.parameters; var length = streamParameters.get("Length"); var byteWidths = streamParameters.get("W"); @@ -1713,7 +1716,7 @@ var XRef = (function() { this.readXRef(prev); return streamParameters; }, - readXRef: function(startXRef) { + readXRef: function readXref(startXRef) { var stream = this.stream; stream.pos = startXRef; var parser = new Parser(new Lexer(stream), true); @@ -1731,6 +1734,7 @@ var XRef = (function() { return this.readXRefStream(obj); } error("Invalid XRef"); + return null; }, getEntry: function(i) { var e = this.entries[i]; @@ -2396,7 +2400,7 @@ var CanvasGraphics = (function() { if (!fd) // XXX deprecated "special treatment" for standard // fonts? What do we need to do here? - return; + return null; var descriptor = xref.fetch(fd); var fontName = descriptor.get("FontName"); @@ -3037,7 +3041,7 @@ var CanvasGraphics = (function() { this.restore(); TODO("Inverse pattern is painted"); - var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); + pattern = this.ctx.createPattern(tmpCanvas, "repeat"); this.ctx.fillStyle = pattern; }, setStrokeGray: function(gray) { From 26389c083ab26499ac3f9836ff4dcee82ebaaf7d Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 11:58:05 +0200 Subject: [PATCH 318/439] Fix a bunch of warnings from Firebug strict mode --- fonts.js | 27 +++++++++++++++------------ pdf.js | 56 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/fonts.js b/fonts.js index 0a1974571..7e8aecd6d 100644 --- a/fonts.js +++ b/fonts.js @@ -599,16 +599,16 @@ var Font = (function () { return font.getBytes(); }, - convert: function font_convert(name, font, properties) { + convert: function font_convert(fontName, font, properties) { var otf = new Uint8Array(kMaxFontFileSize); function createNameTable(name) { var names = [ "See original licence", // Copyright - name, // Font family + fontName, // Font family "undefined", // Font subfamily (font weight) "uniqueID", // Unique ID - name, // Full font name + fontName, // Full font name "0.1", // Version "undefined", // Postscript name "undefined", // Trademark @@ -616,7 +616,7 @@ var Font = (function () { "undefined" // Designer ]; - var name = + var nameTable = "\x00\x00" + // format "\x00\x0A" + // Number of names Record "\x00\x7E"; // Storage @@ -633,13 +633,13 @@ var Font = (function () { "\x00\x00" + // name ID string16(str.length) + string16(strOffset); - name += nameRecord; + nameTable += nameRecord; strOffset += str.length; } - name += names.join(""); - return name; + nameTable += names.join(""); + return nameTable; } // Required Tables @@ -885,6 +885,9 @@ var FontsUtils = { bytes.set([value >> 24, value >> 16, value >> 8, value]); return [bytes[0], bytes[1], bytes[2], bytes[3]]; } + + error("This number of bytes " + bytesCount + " is not supported"); + return null; }, bytesToInteger: function fu_bytesToInteger(bytesArray) { @@ -1238,7 +1241,7 @@ var CFF = function(name, file, properties) { }; CFF.prototype = { - createCFFIndexHeader: function(objects, isByte) { + createCFFIndexHeader: function cff_createCFFIndexHeader(objects, isByte) { // First 2 bytes contains the number of objects contained into this index var count = objects.length; @@ -1275,18 +1278,18 @@ CFF.prototype = { return data; }, - encodeNumber: function(value) { + encodeNumber: function cff_encodeNumber(value) { var x = 0; if (value >= -32768 && value <= 32767) { return [ 28, value >> 8, value & 0xFF ]; } else if (value >= (-2147483647-1) && value <= 2147483647) { return [ 0xFF, value >> 24, Value >> 16, value >> 8, value & 0xFF ]; - } else { - error("Value: " + value + " is not allowed"); } + error("Value: " + value + " is not allowed"); + return null; }, - getOrderedCharStrings: function(glyphs) { + getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs) { var charstrings = []; for (var i = 0; i < glyphs.length; i++) { diff --git a/pdf.js b/pdf.js index f61250a0c..c4ebb5f24 100644 --- a/pdf.js +++ b/pdf.js @@ -71,14 +71,14 @@ var Stream = (function() { get length() { return this.end - this.start; }, - getByte: function() { + getByte: function stream_getByte() { if (this.pos >= this.end) - return; + return null; return this.bytes[this.pos++]; }, // returns subarray of original buffer // should only be read - getBytes: function(length) { + getBytes: function stream_getBytes(length) { var bytes = this.bytes; var pos = this.pos; var strEnd = this.end; @@ -93,28 +93,28 @@ var Stream = (function() { this.pos = end; return bytes.subarray(pos, end); }, - lookChar: function() { + lookChar: function stream_lookChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos]); }, - getChar: function() { + getChar: function stream_getChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos++]); }, - skip: function(n) { + skip: function stream_skip(n) { if (!n) n = 1; this.pos += n; }, - reset: function() { + reset: function stream_reset() { this.pos = this.start; }, - moveStart: function() { + moveStart: function stream_moveStart() { this.start = this.pos; }, - makeSubStream: function(start, length, dict) { + makeSubStream: function stream_makeSubstream(start, length, dict) { return new Stream(this.bytes.buffer, start, length, dict); } }; @@ -146,7 +146,7 @@ var DecodeStream = (function() { } constructor.prototype = { - ensureBuffer: function(requested) { + ensureBuffer: function decodestream_ensureBuffer(requested) { var buffer = this.buffer; var current = buffer ? buffer.byteLength : 0; if (requested < current) @@ -159,16 +159,16 @@ var DecodeStream = (function() { buffer2[i] = buffer[i]; return this.buffer = buffer2; }, - getByte: function() { + getByte: function decodestream_getByte() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return this.buffer[this.pos++]; }, - getBytes: function(length) { + getBytes: function decodestream_getBytes(length) { var pos = this.pos; if (length) { @@ -191,25 +191,25 @@ var DecodeStream = (function() { this.pos = end; return this.buffer.subarray(pos, end) }, - lookChar: function() { + lookChar: function decodestream_lookChar() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos]); }, - getChar: function() { + getChar: function decodestream_getChar() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos++]); }, - skip: function(n) { + skip: function decodestream_skip(n) { if (!n) n = 1; this.pos += n; @@ -635,6 +635,7 @@ var PredictorStream = (function() { var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3; DecodeStream.call(this); + return this; } constructor.prototype = Object.create(DecodeStream.prototype); @@ -905,7 +906,9 @@ var Dict = (function() { constructor.prototype = { get: function(key) { - return this.map[key]; + if (key in this.map) + return this.map[key]; + return null; }, get2: function(key1, key2) { return this.get(key1) || this.get(key2); @@ -1590,7 +1593,7 @@ var XRef = (function() { } constructor.prototype = { - readXRefTable: function(parser) { + readXRefTable: function readXRefTable(parser) { var obj; while (true) { if (IsCmd(obj = parser.getObj(), "trailer")) @@ -1661,7 +1664,7 @@ var XRef = (function() { return dict; }, - readXRefStream: function(stream) { + readXRefStream: function readXRefStream(stream) { var streamParameters = stream.parameters; var length = streamParameters.get("Length"); var byteWidths = streamParameters.get("W"); @@ -1713,7 +1716,7 @@ var XRef = (function() { this.readXRef(prev); return streamParameters; }, - readXRef: function(startXRef) { + readXRef: function readXref(startXRef) { var stream = this.stream; stream.pos = startXRef; var parser = new Parser(new Lexer(stream), true); @@ -1731,6 +1734,7 @@ var XRef = (function() { return this.readXRefStream(obj); } error("Invalid XRef"); + return null; }, getEntry: function(i) { var e = this.entries[i]; @@ -2396,7 +2400,7 @@ var CanvasGraphics = (function() { if (!fd) // XXX deprecated "special treatment" for standard // fonts? What do we need to do here? - return; + return null; var descriptor = xref.fetch(fd); var fontName = descriptor.get("FontName"); @@ -3037,7 +3041,7 @@ var CanvasGraphics = (function() { this.restore(); TODO("Inverse pattern is painted"); - var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); + pattern = this.ctx.createPattern(tmpCanvas, "repeat"); this.ctx.fillStyle = pattern; }, setStrokeGray: function(gray) { From 994b075470ddeb7feb02b199c29c62ed9382e2da Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 07:51:31 -0500 Subject: [PATCH 319/439] Basic DecryptStream functionality; md5 and arcfour algorithms --- pdf.js | 90 +++++++++++------- security.js | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++ viewer.html | 1 + 3 files changed, 319 insertions(+), 33 deletions(-) create mode 100644 security.js diff --git a/pdf.js b/pdf.js index 52a65f1e3..320fc6913 100644 --- a/pdf.js +++ b/pdf.js @@ -56,6 +56,14 @@ function bytesToString(bytes) { return str; } +function stringToBytes(str) { + var length = str.length; + var bytes = new Uint8Array(length); + for (var n = 0; n < length; ++n) + bytes[n] = str.charCodeAt(n) & 0xFF; + return bytes; +} + var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { this.bytes = Uint8Array(arrayBuffer); @@ -741,11 +749,34 @@ var PredictorStream = (function() { })(); var DecryptStream = (function() { - function constructor(str, fileKey, encAlgorithm, keyLength) { - TODO("decrypt stream is not implemented"); + function constructor(str, decrypt) { + this.str = str; + this.dict = str.dict; + this.decrypt = decrypt; + + DecodeStream.call(this); } - constructor.prototype = Stream.prototype; + const chunkSize = 512; + + constructor.prototype = Object.create(DecodeStream.prototype); + constructor.prototype.readBlock = function() { + var chunk = this.str.getBytes(chunkSize); + if (!chunk || chunk.length == 0) { + this.eof = true; + return; + } + var decrypt = this.decrypt; + chunk = decrypt(chunk); + + var bufferLength = this.bufferLength; + var i, n = chunk.length; + var buffer = this.ensureBuffer(bufferLength + n); + for (i = 0; i < n; i++) + buffer[bufferLength++] = chunk[i]; + this.bufferLength = n; + this.eof = n < chunkSize; + }; return constructor; })(); @@ -919,10 +950,10 @@ var Lexer = (function() { function ToHexDigit(ch) { if (ch >= "0" && ch <= "9") - return ch - "0"; - ch = ch.toLowerCase(); - if (ch >= "a" && ch <= "f") - return ch - "a"; + return ch.charCodeAt(0) - 48; + ch = ch.toUpperCase(); + if (ch >= "A" && ch <= "F") + return ch.charCodeAt(0) - 55; return -1; } @@ -1216,7 +1247,7 @@ var Parser = (function() { // don't buffer inline image data this.buf2 = (this.inlineImg > 0) ? null : this.lexer.getObj(); }, - getObj: function() { + getObj: function(cipherTransform) { // refill buffer after inline image data if (this.inlineImg == 2) this.refill(); @@ -1242,7 +1273,7 @@ var Parser = (function() { this.shift(); if (IsEOF(this.buf1)) break; - dict.set(key, this.getObj()); + dict.set(key, this.getObj(cipherTransform)); } } if (IsEOF(this.buf1)) @@ -1251,7 +1282,7 @@ var Parser = (function() { // stream objects are not allowed inside content streams or // object streams if (this.allowStreams && IsCmd(this.buf2, "stream")) { - return this.makeStream(dict); + return this.makeStream(dict, cipherTransform); } else { this.shift(); } @@ -1270,17 +1301,8 @@ var Parser = (function() { } else if (IsString(this.buf1)) { // string var str = this.buf1; this.shift(); - if (this.fileKey) { - var decrypt = new DecryptStream(new StringStream(str), - this.fileKey, - this.encAlgorithm, - this.keyLength); - var str = ""; - var pos = decrypt.pos; - var length = decrypt.length; - while (pos++ > length) - str += decrypt.getChar(); - } + if (cipherTransform) + str = cipherTransform.decryptString(str); return str; } @@ -1289,7 +1311,7 @@ var Parser = (function() { this.shift(); return obj; }, - makeStream: function(dict) { + makeStream: function(dict, cipherTransform) { var lexer = this.lexer; var stream = lexer.stream; @@ -1316,12 +1338,8 @@ var Parser = (function() { this.shift(); stream = stream.makeSubStream(pos, length, dict); - if (this.fileKey) { - stream = new DecryptStream(stream, - this.fileKey, - this.encAlgorithm, - this.keyLength); - } + if (cipherTransform) + stream = cipherTransform.createString(stream); stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; @@ -1450,12 +1468,18 @@ var XRef = (function() { this.xrefstms = {}; var trailerDict = this.readXRef(startXRef); + // prepare the XRef cache + this.cache = []; + + var encrypt = trailerDict.get("Encrypt"); + if (encrypt) { + var fileId = trailerDict.get("ID"); + this.encrypt = new CipherTransformFactory(this.fetch(encrypt), fileId[0] /*, password */); + } + // get the root dictionary (catalog) object if (!IsRef(this.root = trailerDict.get("Root"))) error("Invalid root reference"); - - // prepare the XRef cache - this.cache = []; } constructor.prototype = { @@ -1643,7 +1667,7 @@ var XRef = (function() { } error("bad XRef entry"); } - e = parser.getObj(); + e = parser.getObj(this.encrypt); // Don't cache streams since they are mutable. if (!IsStream(e)) this.cache[num] = e; @@ -2462,7 +2486,7 @@ var CanvasGraphics = (function() { } } } else if (cmd == "Tf") { // eagerly collect all fonts - var fontRes = resources.get("Font"); + var fontRes; // = resources.get("Font"); if (fontRes) { fontRes = xref.fetchIfRef(fontRes); var font = xref.fetchIfRef(fontRes.get(args[0].name)); diff --git a/security.js b/security.js new file mode 100644 index 000000000..d6aa8d3b2 --- /dev/null +++ b/security.js @@ -0,0 +1,261 @@ +/* -*- Mode: Java; tab-width: s; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=s tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + +var ARCFourCipher = (function() { + function constructor(key) { + var key = this.key; + this.a = 0; + this.b = 0; + var s = new Uint8Array(256); + var i, j = 0, tmp, keyLength = key.length; + for (i = 0; i < 256; ++i) + s[i] = i; + for (i = 0; i < 256; ++i) { + tmp = s[i]; + j = (j + tmp + key[i % keyLength]) & 0xFF; + s[i] = s[j]; + s[j] = tmp; + } + this.s = s; + } + + constructor.prototype = { + encryptBlock: function(data) { + var i, n = data.length, tmp, tmp2; + var a = this.a, b = this.b, s = this.s; + var output = new Uint8Array(n); + for (i = 0; i < n; ++i) { + var tmp; + a = (a + 1) & 0xFF; + tmp = s[a]; + b = (b + tmp) & 0xFF; + tmp2 = s[b] + s[a] = tmp2; + s[b] = tmp; + output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF]; + } + this.a = a; + this.b = b; + return output; + } + }; + + return constructor; +})(); + +var md5 = (function() { + const r = new Uint8Array([ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); + const k = new Int32Array([ + -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, + -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, + 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, + 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, + -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, + -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, + 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, + 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, + -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, + 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, + 718787259, -343485551]); + + function hash(data, offset, length) { + var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878; + // pre-processing + var paddedLength = (length + 72) & ~63; // data + 9 extra bytes + var padded = new Uint8Array(paddedLength); + var i, j, n; + for (i = 0; i < length; ++i) + padded[i] = data[offset++]; + padded[i++] = 0x80; + n = paddedLength - 8; + for (; i < n; ++i) + padded[i] = 0; + padded[i++] = (length << 3) & 0xFF; + padded[i++] = (length >> 5) & 0xFF; + padded[i++] = (length >> 13) & 0xFF; + padded[i++] = (length >> 21) & 0xFF; + padded[i++] = (length >>> 29) & 0xFF; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + // chunking + // TODO ArrayBuffer ? + var w = new Int32Array(16); + for (i = 0; i < paddedLength;) { + for (j = 0; j < 16; ++j, i += 4) + w[j] = padded[i] | (padded[i + 1] << 8) | (padded[i + 2] << 16) | (padded[i + 3] << 24); + var a = h0, b = h1, c = h2, d = h3, f, g; + for (j = 0; j < 64; ++j) { + if (j < 16) { + f = (b & c) | ((~b) & d); + g = j; + } else if (j < 32) { + f = (d & b) | ((~d) & c); + g = (5 * j + 1) & 15; + } else if (j < 48) { + f = b ^ c ^ d; + g = (3 * j + 5) & 15; + } else { + f = c ^ (b | (~d)); + g = (7 * j) & 15; + } + var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j]; + d = c; + c = b; + b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0; + a = tmp; + } + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + } + return new Uint8Array([ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF + ]); + } + return hash; +})(); + +var CipherTransform = (function() { + function constructor(stringCipherConstructor, streamCipherConstructor) { + this.stringCipherConstructor = stringCipherConstructor; + this.streamCipherConstructor = streamCipherConstructor; + } + constructor.prototype = { + createStream: function (stream) { + var cipher = new streamCipherConstructor(); + return new DecryptStream(stream, function(data) { + return cipher.encryptBlock(data); + }); + }, + decryptString: function(s) { + var cipher = new stringCipherConstructor(); + var data = string2bytes(s); + data = cipher.encryptBlock(data); + return bytes2string(data); + } + }; + return constructor; +})(); + +var CipherTransformFactory = (function() { + function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength) { + const defaultPasswordBytes = new Uint8Array([ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); + var hashData = new Uint8Array(88), i = 0, j, n; + if (password) { + n = Math.min(32, password.length); + for (; i < n; ++i) + hashData[i] = password[i]; + } + j = 0; + while (i < 32) { + hashData[i++] = defaultPasswordBytes[j++]; + } + // as now the padded password in the hashData[0..i] + for (j = 0, n = ownerPassword.length; j < n; ++j) + hashData[i++] = ownerPassword[j]; + hashData[i++] = flags & 0xFF; + hashData[i++] = (flags >> 8) & 0xFF; + hashData[i++] = (flags >> 16) & 0xFF; + hashData[i++] = (flags >>> 24) & 0xFF; + for (j = 0, n = fileId.length; j < n; ++j) + hashData[i++] = fileId[j]; + // TODO rev 4, if metadata is not encrypted pass 0xFFFFFF also + var hash = md5(hashData, 0, i); + var keyLengthInBytes = keyLength >> 3; + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = md5(hash, 0, keyLengthInBytes); + } + } + var encryptionKey = hash.subarray(0, keyLengthInBytes); + var cipher, checkData; + + if (revision >= 3) { + // padded password in hashData, we can use this array for user password check + i = 32; + for(j = 0, n = fileId.length; j < n; ++j) + hashData[i++] = fileId[j]; + cipher = new ARCFourCipher(encryptionKey); + var checkData = cipher.encryptBlock(md5(hashData, 0, i)); + n = encryptionKey.length; + var derrivedKey = new Uint8Array(n), k; + for (j = 1; j <= 19; ++j) { + for (k = 0; k < n; ++k) + derrivedKey[k] = encryptionKey[k] ^ j; + cipher = new ARCFourCipher(derrivedKey); + checkData = cipher.encryptBlock(checkData); + } + } else { + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(hashData.subarray(0, 32)); + } + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] != checkData[j]) + error("incorrect password"); + } + return encryptionKey; + } + + function constructor(dict, fileId, password) { + var filter = dict.get("Filter"); + if (!IsName(filter) || filter.name != "Standard") + error("unknown encryption method"); + this.dict = dict; + var algorithm = dict.get("V"); + if (!IsInt(algorithm) || + (algorithm != 1 && algorithm != 2)) + error("unsupported encryption algorithm"); + // TODO support algorithm 4 + var keyLength = dict.get("Length") || 40; + if (!IsInt(keyLength) || + keyLength < 40 || (keyLength % 8) != 0) + error("invalid key length"); + // prepare keys + var ownerPassword = stringToBytes(dict.get("O")); + var userPassword = stringToBytes(dict.get("U")); + var flags = dict.get("P"); + var revision = dict.get("R"); + var fileIdBytes = stringToBytes(fileId); + var passwordBytes; + if (password) + passwordBytes = stringToBytes(password); + + this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, + ownerPassword, userPassword, flags, revision, keyLength); + } + + constructor.prototype = { + createCipherTransform: function(num, gen) { + var encryptionKey = this.encryptionKey; + var key = new Uint8Array(encryptionKey.length + 5), i, j, n; + for (j = 0, n = encryptionKey.length; j < n; ++j) + key[j] = encryptionKey[j]; + key[i++] = num & 0xFF; + key[i++] = (num >> 8) & 0xFF; + key[i++] = (num >> 16) & 0xFF; + key[i++] = gen & 0xFF; + key[i++] = (gen >> 8) & 0xFF; + var hash = md5(key, 0, i); + key = hash.subarray(0, Math.min(key.length, 16)); + var cipherConstructor = function() { + return new ARCFourCipher(key); + }; + return new CipherTransform(cipherConstructor, cipherConstructor); + } + }; + + return constructor; +})(); diff --git a/viewer.html b/viewer.html index 6e733319e..4b9dd3cbd 100644 --- a/viewer.html +++ b/viewer.html @@ -6,6 +6,7 @@ + From c78c209eb52d9ccdd5daeb43fb19813a8393fc06 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 07:51:31 -0500 Subject: [PATCH 320/439] Basic DecryptStream functionality; md5 and arcfour algorithms --- pdf.js | 90 +++++++++++------- security.js | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++ viewer.html | 1 + 3 files changed, 319 insertions(+), 33 deletions(-) create mode 100644 security.js diff --git a/pdf.js b/pdf.js index 52a65f1e3..320fc6913 100644 --- a/pdf.js +++ b/pdf.js @@ -56,6 +56,14 @@ function bytesToString(bytes) { return str; } +function stringToBytes(str) { + var length = str.length; + var bytes = new Uint8Array(length); + for (var n = 0; n < length; ++n) + bytes[n] = str.charCodeAt(n) & 0xFF; + return bytes; +} + var Stream = (function() { function constructor(arrayBuffer, start, length, dict) { this.bytes = Uint8Array(arrayBuffer); @@ -741,11 +749,34 @@ var PredictorStream = (function() { })(); var DecryptStream = (function() { - function constructor(str, fileKey, encAlgorithm, keyLength) { - TODO("decrypt stream is not implemented"); + function constructor(str, decrypt) { + this.str = str; + this.dict = str.dict; + this.decrypt = decrypt; + + DecodeStream.call(this); } - constructor.prototype = Stream.prototype; + const chunkSize = 512; + + constructor.prototype = Object.create(DecodeStream.prototype); + constructor.prototype.readBlock = function() { + var chunk = this.str.getBytes(chunkSize); + if (!chunk || chunk.length == 0) { + this.eof = true; + return; + } + var decrypt = this.decrypt; + chunk = decrypt(chunk); + + var bufferLength = this.bufferLength; + var i, n = chunk.length; + var buffer = this.ensureBuffer(bufferLength + n); + for (i = 0; i < n; i++) + buffer[bufferLength++] = chunk[i]; + this.bufferLength = n; + this.eof = n < chunkSize; + }; return constructor; })(); @@ -919,10 +950,10 @@ var Lexer = (function() { function ToHexDigit(ch) { if (ch >= "0" && ch <= "9") - return ch - "0"; - ch = ch.toLowerCase(); - if (ch >= "a" && ch <= "f") - return ch - "a"; + return ch.charCodeAt(0) - 48; + ch = ch.toUpperCase(); + if (ch >= "A" && ch <= "F") + return ch.charCodeAt(0) - 55; return -1; } @@ -1216,7 +1247,7 @@ var Parser = (function() { // don't buffer inline image data this.buf2 = (this.inlineImg > 0) ? null : this.lexer.getObj(); }, - getObj: function() { + getObj: function(cipherTransform) { // refill buffer after inline image data if (this.inlineImg == 2) this.refill(); @@ -1242,7 +1273,7 @@ var Parser = (function() { this.shift(); if (IsEOF(this.buf1)) break; - dict.set(key, this.getObj()); + dict.set(key, this.getObj(cipherTransform)); } } if (IsEOF(this.buf1)) @@ -1251,7 +1282,7 @@ var Parser = (function() { // stream objects are not allowed inside content streams or // object streams if (this.allowStreams && IsCmd(this.buf2, "stream")) { - return this.makeStream(dict); + return this.makeStream(dict, cipherTransform); } else { this.shift(); } @@ -1270,17 +1301,8 @@ var Parser = (function() { } else if (IsString(this.buf1)) { // string var str = this.buf1; this.shift(); - if (this.fileKey) { - var decrypt = new DecryptStream(new StringStream(str), - this.fileKey, - this.encAlgorithm, - this.keyLength); - var str = ""; - var pos = decrypt.pos; - var length = decrypt.length; - while (pos++ > length) - str += decrypt.getChar(); - } + if (cipherTransform) + str = cipherTransform.decryptString(str); return str; } @@ -1289,7 +1311,7 @@ var Parser = (function() { this.shift(); return obj; }, - makeStream: function(dict) { + makeStream: function(dict, cipherTransform) { var lexer = this.lexer; var stream = lexer.stream; @@ -1316,12 +1338,8 @@ var Parser = (function() { this.shift(); stream = stream.makeSubStream(pos, length, dict); - if (this.fileKey) { - stream = new DecryptStream(stream, - this.fileKey, - this.encAlgorithm, - this.keyLength); - } + if (cipherTransform) + stream = cipherTransform.createString(stream); stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; @@ -1450,12 +1468,18 @@ var XRef = (function() { this.xrefstms = {}; var trailerDict = this.readXRef(startXRef); + // prepare the XRef cache + this.cache = []; + + var encrypt = trailerDict.get("Encrypt"); + if (encrypt) { + var fileId = trailerDict.get("ID"); + this.encrypt = new CipherTransformFactory(this.fetch(encrypt), fileId[0] /*, password */); + } + // get the root dictionary (catalog) object if (!IsRef(this.root = trailerDict.get("Root"))) error("Invalid root reference"); - - // prepare the XRef cache - this.cache = []; } constructor.prototype = { @@ -1643,7 +1667,7 @@ var XRef = (function() { } error("bad XRef entry"); } - e = parser.getObj(); + e = parser.getObj(this.encrypt); // Don't cache streams since they are mutable. if (!IsStream(e)) this.cache[num] = e; @@ -2462,7 +2486,7 @@ var CanvasGraphics = (function() { } } } else if (cmd == "Tf") { // eagerly collect all fonts - var fontRes = resources.get("Font"); + var fontRes; // = resources.get("Font"); if (fontRes) { fontRes = xref.fetchIfRef(fontRes); var font = xref.fetchIfRef(fontRes.get(args[0].name)); diff --git a/security.js b/security.js new file mode 100644 index 000000000..d6aa8d3b2 --- /dev/null +++ b/security.js @@ -0,0 +1,261 @@ +/* -*- Mode: Java; tab-width: s; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* vim: set shiftwidth=s tabstop=2 autoindent cindent expandtab: */ + +"use strict"; + +var ARCFourCipher = (function() { + function constructor(key) { + var key = this.key; + this.a = 0; + this.b = 0; + var s = new Uint8Array(256); + var i, j = 0, tmp, keyLength = key.length; + for (i = 0; i < 256; ++i) + s[i] = i; + for (i = 0; i < 256; ++i) { + tmp = s[i]; + j = (j + tmp + key[i % keyLength]) & 0xFF; + s[i] = s[j]; + s[j] = tmp; + } + this.s = s; + } + + constructor.prototype = { + encryptBlock: function(data) { + var i, n = data.length, tmp, tmp2; + var a = this.a, b = this.b, s = this.s; + var output = new Uint8Array(n); + for (i = 0; i < n; ++i) { + var tmp; + a = (a + 1) & 0xFF; + tmp = s[a]; + b = (b + tmp) & 0xFF; + tmp2 = s[b] + s[a] = tmp2; + s[b] = tmp; + output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF]; + } + this.a = a; + this.b = b; + return output; + } + }; + + return constructor; +})(); + +var md5 = (function() { + const r = new Uint8Array([ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); + const k = new Int32Array([ + -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, + -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, + 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, + 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, + -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, + -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, + 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, + 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, + -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, + 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, + 718787259, -343485551]); + + function hash(data, offset, length) { + var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878; + // pre-processing + var paddedLength = (length + 72) & ~63; // data + 9 extra bytes + var padded = new Uint8Array(paddedLength); + var i, j, n; + for (i = 0; i < length; ++i) + padded[i] = data[offset++]; + padded[i++] = 0x80; + n = paddedLength - 8; + for (; i < n; ++i) + padded[i] = 0; + padded[i++] = (length << 3) & 0xFF; + padded[i++] = (length >> 5) & 0xFF; + padded[i++] = (length >> 13) & 0xFF; + padded[i++] = (length >> 21) & 0xFF; + padded[i++] = (length >>> 29) & 0xFF; + padded[i++] = 0; + padded[i++] = 0; + padded[i++] = 0; + // chunking + // TODO ArrayBuffer ? + var w = new Int32Array(16); + for (i = 0; i < paddedLength;) { + for (j = 0; j < 16; ++j, i += 4) + w[j] = padded[i] | (padded[i + 1] << 8) | (padded[i + 2] << 16) | (padded[i + 3] << 24); + var a = h0, b = h1, c = h2, d = h3, f, g; + for (j = 0; j < 64; ++j) { + if (j < 16) { + f = (b & c) | ((~b) & d); + g = j; + } else if (j < 32) { + f = (d & b) | ((~d) & c); + g = (5 * j + 1) & 15; + } else if (j < 48) { + f = b ^ c ^ d; + g = (3 * j + 5) & 15; + } else { + f = c ^ (b | (~d)); + g = (7 * j) & 15; + } + var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j]; + d = c; + c = b; + b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0; + a = tmp; + } + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + } + return new Uint8Array([ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF + ]); + } + return hash; +})(); + +var CipherTransform = (function() { + function constructor(stringCipherConstructor, streamCipherConstructor) { + this.stringCipherConstructor = stringCipherConstructor; + this.streamCipherConstructor = streamCipherConstructor; + } + constructor.prototype = { + createStream: function (stream) { + var cipher = new streamCipherConstructor(); + return new DecryptStream(stream, function(data) { + return cipher.encryptBlock(data); + }); + }, + decryptString: function(s) { + var cipher = new stringCipherConstructor(); + var data = string2bytes(s); + data = cipher.encryptBlock(data); + return bytes2string(data); + } + }; + return constructor; +})(); + +var CipherTransformFactory = (function() { + function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength) { + const defaultPasswordBytes = new Uint8Array([ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); + var hashData = new Uint8Array(88), i = 0, j, n; + if (password) { + n = Math.min(32, password.length); + for (; i < n; ++i) + hashData[i] = password[i]; + } + j = 0; + while (i < 32) { + hashData[i++] = defaultPasswordBytes[j++]; + } + // as now the padded password in the hashData[0..i] + for (j = 0, n = ownerPassword.length; j < n; ++j) + hashData[i++] = ownerPassword[j]; + hashData[i++] = flags & 0xFF; + hashData[i++] = (flags >> 8) & 0xFF; + hashData[i++] = (flags >> 16) & 0xFF; + hashData[i++] = (flags >>> 24) & 0xFF; + for (j = 0, n = fileId.length; j < n; ++j) + hashData[i++] = fileId[j]; + // TODO rev 4, if metadata is not encrypted pass 0xFFFFFF also + var hash = md5(hashData, 0, i); + var keyLengthInBytes = keyLength >> 3; + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = md5(hash, 0, keyLengthInBytes); + } + } + var encryptionKey = hash.subarray(0, keyLengthInBytes); + var cipher, checkData; + + if (revision >= 3) { + // padded password in hashData, we can use this array for user password check + i = 32; + for(j = 0, n = fileId.length; j < n; ++j) + hashData[i++] = fileId[j]; + cipher = new ARCFourCipher(encryptionKey); + var checkData = cipher.encryptBlock(md5(hashData, 0, i)); + n = encryptionKey.length; + var derrivedKey = new Uint8Array(n), k; + for (j = 1; j <= 19; ++j) { + for (k = 0; k < n; ++k) + derrivedKey[k] = encryptionKey[k] ^ j; + cipher = new ARCFourCipher(derrivedKey); + checkData = cipher.encryptBlock(checkData); + } + } else { + cipher = new ARCFourCipher(encryptionKey); + checkData = cipher.encryptBlock(hashData.subarray(0, 32)); + } + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] != checkData[j]) + error("incorrect password"); + } + return encryptionKey; + } + + function constructor(dict, fileId, password) { + var filter = dict.get("Filter"); + if (!IsName(filter) || filter.name != "Standard") + error("unknown encryption method"); + this.dict = dict; + var algorithm = dict.get("V"); + if (!IsInt(algorithm) || + (algorithm != 1 && algorithm != 2)) + error("unsupported encryption algorithm"); + // TODO support algorithm 4 + var keyLength = dict.get("Length") || 40; + if (!IsInt(keyLength) || + keyLength < 40 || (keyLength % 8) != 0) + error("invalid key length"); + // prepare keys + var ownerPassword = stringToBytes(dict.get("O")); + var userPassword = stringToBytes(dict.get("U")); + var flags = dict.get("P"); + var revision = dict.get("R"); + var fileIdBytes = stringToBytes(fileId); + var passwordBytes; + if (password) + passwordBytes = stringToBytes(password); + + this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, + ownerPassword, userPassword, flags, revision, keyLength); + } + + constructor.prototype = { + createCipherTransform: function(num, gen) { + var encryptionKey = this.encryptionKey; + var key = new Uint8Array(encryptionKey.length + 5), i, j, n; + for (j = 0, n = encryptionKey.length; j < n; ++j) + key[j] = encryptionKey[j]; + key[i++] = num & 0xFF; + key[i++] = (num >> 8) & 0xFF; + key[i++] = (num >> 16) & 0xFF; + key[i++] = gen & 0xFF; + key[i++] = (gen >> 8) & 0xFF; + var hash = md5(key, 0, i); + key = hash.subarray(0, Math.min(key.length, 16)); + var cipherConstructor = function() { + return new ARCFourCipher(key); + }; + return new CipherTransform(cipherConstructor, cipherConstructor); + } + }; + + return constructor; +})(); diff --git a/viewer.html b/viewer.html index 6e733319e..4b9dd3cbd 100644 --- a/viewer.html +++ b/viewer.html @@ -6,6 +6,7 @@ + From 46a17a2deb4e9e73f20e3fd30c70492482106441 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 07:51:59 -0700 Subject: [PATCH 321/439] Still fixing faxstream --- pdf.js | 310 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 188 insertions(+), 122 deletions(-) diff --git a/pdf.js b/pdf.js index 37bdc5a6f..00d07df6f 100644 --- a/pdf.js +++ b/pdf.js @@ -1324,6 +1324,7 @@ var CCITTFaxStream = (function() { this.inputBuf; this.outputBits = 0; this.buf = EOF; + this.err = false; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1356,33 +1357,42 @@ var CCITTFaxStream = (function() { var codingPos = this.codingPos; if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) - error("row is wrong length"); + if (a1 > this.columns) { + warn("row is wrong length"); + this.err = true; + a1 = this.columns; + } if ((codingPos & 1) ^ blackPixels) { ++codingPos; - this.codingPos = codingPos; } codingLine[codingPos] = a1; } + this.codingPos = codingPos; }; constructor.prototype.addPixelsNeg = function(a1, blackPixels) { var codingLine = this.codingLine; var codingPos = this.codingPos; if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) - error("row is wrong length"); + if (a1 > this.columns) { + warn("row is wrong length"); + this.err = true; + a1 = this.columns; + } if ((codingPos & 1) ^ blackPixels) ++codingPos; codingLine[codingPos] = a1; } else if (a1 < codingLine[codingPos]) { - if (a1 < 0) - error("invalid code"); + if (a1 < 0) { + warn("invalid code"); + this.err = true; + a1 = 0; + } while (codingPos > 0 && a1 < codingLine[codingPos - 1]) --codingPos; - this.codingLine[codingPos] = a1; + codingLine[codingPos] = a1; } this.codingPos = codingPos; @@ -1392,15 +1402,14 @@ var CCITTFaxStream = (function() { var codingLine = this.codingLine; var columns = this.columns; - var outputBits = this.outputBits; - var codingPos = this.codingPos; - var refPos, blackPixels, bits; if (this.buf != EOF) return buf; - if (outputBits == 0) { + this.err = false; + + if (this.outputBits == 0) { if (this.eof) return; @@ -1411,16 +1420,15 @@ var CCITTFaxStream = (function() { refLine[i++] = columns; refLine[i] = columns; codingLine[0] = 0; - codingPos = 0; + this.codingPos = 0; refPos = 0; blackPixels = 0; - while (codingLine[codingPos] < columns) { + while (codingLine[this.codingPos] < columns) { var code1 = this.getTwoDumCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); - codingPos = this.codingPos; if (refLine[refPos + 1] < columns) refPos += 2; break; @@ -1443,36 +1451,32 @@ var CCITTFaxStream = (function() { code2 += (code3 = this.getBlackCode()); } while (code3 >= 64); } - this.addPixels(codingLine[codingPos] + code1, blackPixels); - codingPos = this.codingPos; - if (codingLine[codingPos] < columns) { - this.addPixels(codeLine[codingPos] + code2, + this.addPixels(codingLine[this.codingPos] + code1, blackPixels); + if (codingLine[this.codingPos] < columns) { + this.addPixels(codingLine[this.codingPos] + code2, blackPixels ^ 1); - codingPos = this.codingPos; } - while (refLine[refPos] <= codingLine[codingPos] + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { refPos += 2; } break; case twoDimVertR3: this.addPixels(refLine[refPos] + 3, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertR2: this.addPixels(refLine[refPos] + 2, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { refPos += 2; } @@ -1480,94 +1484,92 @@ var CCITTFaxStream = (function() { break; case twoDimVertR1: this.addPixels(refLine[refPos] + 1, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] < codingLine[codingPos] && + while (refLine[refPos] < codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVert0: this.addPixels(refLine[refPos], blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertL3: this.addPixelsNeg(refLine[refPos] - 3, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codeLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertL2: this.addPixelsNeg(refLine[refPos] - 2, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && - refLine[b11] < columns) + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[redPos] < columns) refPos += 2; } break; -///////// STOPPED HERE case twoDimVertL1: this.addPixelsNeg(refLine[refPos] - 1, blackPixels); - this.blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codeLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case EOF: - addPixels(columns, 0); + this.addPixels(columns, 0); this.eof = true; break; default: - error("bad 2d code"); + warn("bad 2d code"); + addPixels(columns, 0); + this.err = true; + break; } } } else { codingLine[0] = 0; - codingPos = 0; + this.codingPos = 0; blackPixels = 0; - while(codeLine[codingPos] < columns) { + while(codingLine[this.codingPos] < columns) { code1 = 0; if (blackPixels) { do { - code1 += (code3 = getBlackCode()); + code1 += (code3 = this.getBlackCode()); } while (code3 >= 64); } else { do { - code1 += (code3 = getWhiteCode()); + code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); } - this.addPixels(codingLine[codingPos] + code1, blackPixels); + this.addPixels(codingLine[this.codingPos] + code1, blackPixels); blackPixels ^= 1; } } @@ -1575,98 +1577,117 @@ var CCITTFaxStream = (function() { if (this.byteAlign) inputBits &= ~7; - getEol = false; - if (eob && row == rows - 1) { - eof = true; + var gotEOL = false; + + if (this.eoblock && this.row == this.rows - 1) { + this.eof = true; } else { - code1 = lookBits(12); + code1 = this.lookBits(12); while (code1 == 0) { - eatBits(1); + this.eatBits(1); code1 = this.lookBits(12); } - if (code1 = 1) { - eatBits(12); - gotEol = true; - } else if (code1 = EOF) { - eof = true; + if (code1 == 1) { + this.eatBits(12); + gotEOL = true; + } else if (code1 == EOF) { + this.eof = true; } } - if (!oef && encoding > 0) { - nextLine2D = !this.lookBits(1); - eatBits(1); + if (!this.eof && this.encoding > 0) { + this.nextLine2D = !this.lookBits(1); + this.eatBits(1); } - if (eob && gotEol) { + if (this.eoblock && gotEOL) { code1 = this.lookBits(12); if (code1 == 1) { eatBits(12); - if (encoding > 0) { + if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); } - if (encoding >= 0) { - for (i = 0; i < 4; ++i) { + if (this.encoding >= 0) { + for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) error("bad rtc code"); - eatBits(12); - if (encoding > 0) { + this.eatBits(12); + if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); } } } - eof = true; + this.eof = true; + } + } else if (this.err && this.eolin) { + var code1; + while (true) { + code1 = this.lookBits(13); + if (code1 == EOF) { + this.eof = true; + return; + } + if ((code1 >> 1) == 1) { + break; + } + this.eatBits(1); + } + this.eatBits(12); + if (this.encoding > 0) { + this.eatBits(1); + this.nextLine2 = !(code1 & 1); } } if (codingLine[0] > 0) - outputBits = codingLine[codingPos = 0]; + this.outputBits = codingLine[this.codingPos = 0]; else - outputBits = codingLine[codingPos = 1]; - ++row; + this.outputBits = codingLine[this.codingPos = 1]; + this.row++; } - if (outputBits >= 8) { - buf = (codingPos & 1) ? 0 : 0xFF; - outputBits -= 8; - if (outputBits == 0&& codingLine[codingPos] < columns) { - ++codingPos; - outputBits = codingLine[codingPos] - codingLine[codingPos - 1]; + if (this.outputBits >= 8) { + this.buf = (this.codingPos & 1) ? 0 : 0xFF; + this.outputBits -= 8; + if (this.outputBits == 0 && codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; } } else { - bits = 8; - buf = 0; + this.bits = 8; + this.buf = 0; do { - if (outputBits > bits) { - buf << bits; - if (!(codingPos & 1)) { - buf |= 0xFF >> (8 - bits); + if (this.outputBits > this.bits) { + this.buf << this.bits; + if (!(this.codingPos & 1)) { + this.buf |= 0xFF >> (8 - this.bits); } - outputBits -= bits; - bits = 0; + this.outputBits -= this.bits; + this.bits = 0; } else { - buf <<= outputBits; - if (!(codingPos & 1)) { - buf |= 0xFF >> (8 - outputBits); + this.buf <<= this.outputBits; + if (!(this.codingPos & 1)) { + this.buf |= 0xFF >> (8 - this.outputBits); } - bits -= outputBits; - outputBits = 0; - if (codingLine[codingPos] < columns) { - ++codingPos; - outputBits = codingLine[codingPos] - codingLine[codingPos - 1]; - } else if (bits > 0) { - buf <<= bits; - bits = 0; + this.bits -= this.outputBits; + this.outputBits = 0; + if (codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; + } else if (this.bits > 0) { + this.buf <<= this.bits; + this.bits = 0; } } - } while (bits); + } while (this.bits); } - if (black) { - buf ^= 0xFF; + if (this.black) { + this.buf ^= 0xFF; } - return buf; + return this.buf; }; constructor.prototype.getTwoDimCode = function() { var code = 0; @@ -1675,23 +1696,24 @@ var CCITTFaxStream = (function() { code = this.lookBits(7); p = twoDimTable[code]; if (p[0] > 0) { - eatBits(p[0]); + this.eatBits(p[0]); return p[1]; } } else { for (var n = 1; n <= 7; ++n) { - code = lookBits(n); + code = this.lookBits(n); if (n < 7) { code <<= 7 - n; } p = twoDimTable[code]; if (p[0] == n) { - eatBits(n); + this.eatBits(n); return p[1]; } } } - error("Bad two dim code"); + warn("Bad two dim code"); + return EOF; }; constructor.prototype.getWhiteCode = function() { @@ -1721,7 +1743,7 @@ var CCITTFaxStream = (function() { if (n < 9) code <<= 9 - n; p = whiteTable2[code]; - if (p[0] == b) { + if (p[0] == n) { this.eatBits(n); return p[0]; } @@ -1739,7 +1761,9 @@ var CCITTFaxStream = (function() { } } } - error("bad white code"); + warn("bad white code"); + this.eatBits(1); + return 1; }; constructor.prototype.getBlackCode = function() { var code, p, n; @@ -1779,7 +1803,7 @@ var CCITTFaxStream = (function() { if (n < 12) code <<= 12 - n; if (code >= 64) { - p = blackTable[code - 64]; + p = blackTable2[code - 64]; if (p[0] == n) { this.eatBits(n); return p[1]; @@ -1787,7 +1811,7 @@ var CCITTFaxStream = (function() { } } for (n = 10; n <= 13; ++n) { - code = lookBits(n); + code = this.lookBits(n); if (code == EOF) return 1; if (n < 13) @@ -1799,24 +1823,27 @@ var CCITTFaxStream = (function() { } } } - error("bad black code"); + warn("bad black code"); + this.eatBits(1); + return 1; }; constructor.prototype.lookBits = function(n) { var c; - while (inputBits < n) { - if (typeof (c = str.getByte()) == "undefined") { - if (inputBits == 0) + while (this.inputBits < n) { + if (typeof (c = this.str.getByte()) == "undefined") { + if (this.inputBits == 0) return EOF; - return (inputBuf << (n - inputBits)) & (0xFFFF >> (16 - n)); + return (this.inputBuf << (n - this.inputBits)) + & (0xFFFF >> (16 - n)); } - inputBuf = (inputBuf << 8) + c; - inputBits += 8; + this.inputBuf = (this.inputBuf << 8) + c; + this.inputBits += 8; } - return (inputBuf >> (inputBits - n)) & (0xFFFF >> (16 - n)); + return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n)); }; constructor.prototype.eatBits = function(n) { - if ((inputBits -= n) < 0) - inputBits = 0; + if ((this.inputBits -= n) < 0) + this.inputBits = 0; } return constructor; @@ -2433,7 +2460,7 @@ var Parser = (function() { return new Ascii85Stream(stream); } else if (name == "CCITTFaxDecode") { TODO("implement fax stream"); - return new FakeStream(stream); + return new CCITTFaxStream(stream); } else { error("filter '" + name + "' not supported yet"); } @@ -4186,6 +4213,45 @@ var CanvasGraphics = (function() { } } + if (bitsPerComponent == 1) { + var xref = this.xref; + var csStream = dict.get2("ColorSpace", "CS"); + csStream = xref.fetchIfRef(csStream); + if (IsName(csStream) && inline) + csStream = colorSpaces.get(csStream); + var colorSpace = new ColorSpace(xref, csStream); + var numComps = colorSpace.numComps; + if (numComps != 1) + error("worng numComps"); + + var imgArray = image.getBytes((numComps * w * h) >> 3); + var imgIdx = 0; + + var tmpCanvas = document.createElement("canvas"); + tmpCanvas.width = w; + tmpCanvas.height = h; + var tmpCtx = tmpCanvas.getContext("2d"); + var imgData = tmpCtx.getImageData(0, 0, w, h); + var pixels = imgData.data; + + var mask = 128; + var b = 0; + for (var i = 0; i < length; i += 4) { + mask <<= 1; + if (mask >= 256) { + b = imgArray[imgIdx++]; + mask = 1; + } + + var p = b & mask; + pixels[i] = 255 * p; + pixels[i+1] = 255 * p; + pixels[i+2] = 255 * p; + pixels[i+3] = 255; + } + return; + } + if (bitsPerComponent !== 8) error("Unsupported bpc"); From 6c8e545e5efc4830d22429603ad59b62b0f68a72 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 07:51:59 -0700 Subject: [PATCH 322/439] Still fixing faxstream --- pdf.js | 310 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 188 insertions(+), 122 deletions(-) diff --git a/pdf.js b/pdf.js index 37bdc5a6f..00d07df6f 100644 --- a/pdf.js +++ b/pdf.js @@ -1324,6 +1324,7 @@ var CCITTFaxStream = (function() { this.inputBuf; this.outputBits = 0; this.buf = EOF; + this.err = false; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1356,33 +1357,42 @@ var CCITTFaxStream = (function() { var codingPos = this.codingPos; if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) - error("row is wrong length"); + if (a1 > this.columns) { + warn("row is wrong length"); + this.err = true; + a1 = this.columns; + } if ((codingPos & 1) ^ blackPixels) { ++codingPos; - this.codingPos = codingPos; } codingLine[codingPos] = a1; } + this.codingPos = codingPos; }; constructor.prototype.addPixelsNeg = function(a1, blackPixels) { var codingLine = this.codingLine; var codingPos = this.codingPos; if (a1 > codingLine[codingPos]) { - if (a1 > this.columns) - error("row is wrong length"); + if (a1 > this.columns) { + warn("row is wrong length"); + this.err = true; + a1 = this.columns; + } if ((codingPos & 1) ^ blackPixels) ++codingPos; codingLine[codingPos] = a1; } else if (a1 < codingLine[codingPos]) { - if (a1 < 0) - error("invalid code"); + if (a1 < 0) { + warn("invalid code"); + this.err = true; + a1 = 0; + } while (codingPos > 0 && a1 < codingLine[codingPos - 1]) --codingPos; - this.codingLine[codingPos] = a1; + codingLine[codingPos] = a1; } this.codingPos = codingPos; @@ -1392,15 +1402,14 @@ var CCITTFaxStream = (function() { var codingLine = this.codingLine; var columns = this.columns; - var outputBits = this.outputBits; - var codingPos = this.codingPos; - var refPos, blackPixels, bits; if (this.buf != EOF) return buf; - if (outputBits == 0) { + this.err = false; + + if (this.outputBits == 0) { if (this.eof) return; @@ -1411,16 +1420,15 @@ var CCITTFaxStream = (function() { refLine[i++] = columns; refLine[i] = columns; codingLine[0] = 0; - codingPos = 0; + this.codingPos = 0; refPos = 0; blackPixels = 0; - while (codingLine[codingPos] < columns) { + while (codingLine[this.codingPos] < columns) { var code1 = this.getTwoDumCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); - codingPos = this.codingPos; if (refLine[refPos + 1] < columns) refPos += 2; break; @@ -1443,36 +1451,32 @@ var CCITTFaxStream = (function() { code2 += (code3 = this.getBlackCode()); } while (code3 >= 64); } - this.addPixels(codingLine[codingPos] + code1, blackPixels); - codingPos = this.codingPos; - if (codingLine[codingPos] < columns) { - this.addPixels(codeLine[codingPos] + code2, + this.addPixels(codingLine[this.codingPos] + code1, blackPixels); + if (codingLine[this.codingPos] < columns) { + this.addPixels(codingLine[this.codingPos] + code2, blackPixels ^ 1); - codingPos = this.codingPos; } - while (refLine[refPos] <= codingLine[codingPos] + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { refPos += 2; } break; case twoDimVertR3: this.addPixels(refLine[refPos] + 3, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertR2: this.addPixels(refLine[refPos] + 2, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { refPos += 2; } @@ -1480,94 +1484,92 @@ var CCITTFaxStream = (function() { break; case twoDimVertR1: this.addPixels(refLine[refPos] + 1, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] < codingLine[codingPos] && + while (refLine[refPos] < codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVert0: this.addPixels(refLine[refPos], blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertL3: this.addPixelsNeg(refLine[refPos] - 3, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codeLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case twoDimVertL2: this.addPixelsNeg(refLine[refPos] - 2, blackPixels); - codingPos = this.codingPos; blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codingLine[codingPos] && - refLine[b11] < columns) + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[redPos] < columns) refPos += 2; } break; -///////// STOPPED HERE case twoDimVertL1: this.addPixelsNeg(refLine[refPos] - 1, blackPixels); - this.blackPixels ^= 1; - if (codingLine[codingPos] < columns) { + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { if (refPos > 0) --refPos; else ++refPos; - while (refLine[refPos] <= codeLine[codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } break; case EOF: - addPixels(columns, 0); + this.addPixels(columns, 0); this.eof = true; break; default: - error("bad 2d code"); + warn("bad 2d code"); + addPixels(columns, 0); + this.err = true; + break; } } } else { codingLine[0] = 0; - codingPos = 0; + this.codingPos = 0; blackPixels = 0; - while(codeLine[codingPos] < columns) { + while(codingLine[this.codingPos] < columns) { code1 = 0; if (blackPixels) { do { - code1 += (code3 = getBlackCode()); + code1 += (code3 = this.getBlackCode()); } while (code3 >= 64); } else { do { - code1 += (code3 = getWhiteCode()); + code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); } - this.addPixels(codingLine[codingPos] + code1, blackPixels); + this.addPixels(codingLine[this.codingPos] + code1, blackPixels); blackPixels ^= 1; } } @@ -1575,98 +1577,117 @@ var CCITTFaxStream = (function() { if (this.byteAlign) inputBits &= ~7; - getEol = false; - if (eob && row == rows - 1) { - eof = true; + var gotEOL = false; + + if (this.eoblock && this.row == this.rows - 1) { + this.eof = true; } else { - code1 = lookBits(12); + code1 = this.lookBits(12); while (code1 == 0) { - eatBits(1); + this.eatBits(1); code1 = this.lookBits(12); } - if (code1 = 1) { - eatBits(12); - gotEol = true; - } else if (code1 = EOF) { - eof = true; + if (code1 == 1) { + this.eatBits(12); + gotEOL = true; + } else if (code1 == EOF) { + this.eof = true; } } - if (!oef && encoding > 0) { - nextLine2D = !this.lookBits(1); - eatBits(1); + if (!this.eof && this.encoding > 0) { + this.nextLine2D = !this.lookBits(1); + this.eatBits(1); } - if (eob && gotEol) { + if (this.eoblock && gotEOL) { code1 = this.lookBits(12); if (code1 == 1) { eatBits(12); - if (encoding > 0) { + if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); } - if (encoding >= 0) { - for (i = 0; i < 4; ++i) { + if (this.encoding >= 0) { + for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) error("bad rtc code"); - eatBits(12); - if (encoding > 0) { + this.eatBits(12); + if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); } } } - eof = true; + this.eof = true; + } + } else if (this.err && this.eolin) { + var code1; + while (true) { + code1 = this.lookBits(13); + if (code1 == EOF) { + this.eof = true; + return; + } + if ((code1 >> 1) == 1) { + break; + } + this.eatBits(1); + } + this.eatBits(12); + if (this.encoding > 0) { + this.eatBits(1); + this.nextLine2 = !(code1 & 1); } } if (codingLine[0] > 0) - outputBits = codingLine[codingPos = 0]; + this.outputBits = codingLine[this.codingPos = 0]; else - outputBits = codingLine[codingPos = 1]; - ++row; + this.outputBits = codingLine[this.codingPos = 1]; + this.row++; } - if (outputBits >= 8) { - buf = (codingPos & 1) ? 0 : 0xFF; - outputBits -= 8; - if (outputBits == 0&& codingLine[codingPos] < columns) { - ++codingPos; - outputBits = codingLine[codingPos] - codingLine[codingPos - 1]; + if (this.outputBits >= 8) { + this.buf = (this.codingPos & 1) ? 0 : 0xFF; + this.outputBits -= 8; + if (this.outputBits == 0 && codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; } } else { - bits = 8; - buf = 0; + this.bits = 8; + this.buf = 0; do { - if (outputBits > bits) { - buf << bits; - if (!(codingPos & 1)) { - buf |= 0xFF >> (8 - bits); + if (this.outputBits > this.bits) { + this.buf << this.bits; + if (!(this.codingPos & 1)) { + this.buf |= 0xFF >> (8 - this.bits); } - outputBits -= bits; - bits = 0; + this.outputBits -= this.bits; + this.bits = 0; } else { - buf <<= outputBits; - if (!(codingPos & 1)) { - buf |= 0xFF >> (8 - outputBits); + this.buf <<= this.outputBits; + if (!(this.codingPos & 1)) { + this.buf |= 0xFF >> (8 - this.outputBits); } - bits -= outputBits; - outputBits = 0; - if (codingLine[codingPos] < columns) { - ++codingPos; - outputBits = codingLine[codingPos] - codingLine[codingPos - 1]; - } else if (bits > 0) { - buf <<= bits; - bits = 0; + this.bits -= this.outputBits; + this.outputBits = 0; + if (codingLine[this.codingPos] < columns) { + this.codingPos++; + this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; + } else if (this.bits > 0) { + this.buf <<= this.bits; + this.bits = 0; } } - } while (bits); + } while (this.bits); } - if (black) { - buf ^= 0xFF; + if (this.black) { + this.buf ^= 0xFF; } - return buf; + return this.buf; }; constructor.prototype.getTwoDimCode = function() { var code = 0; @@ -1675,23 +1696,24 @@ var CCITTFaxStream = (function() { code = this.lookBits(7); p = twoDimTable[code]; if (p[0] > 0) { - eatBits(p[0]); + this.eatBits(p[0]); return p[1]; } } else { for (var n = 1; n <= 7; ++n) { - code = lookBits(n); + code = this.lookBits(n); if (n < 7) { code <<= 7 - n; } p = twoDimTable[code]; if (p[0] == n) { - eatBits(n); + this.eatBits(n); return p[1]; } } } - error("Bad two dim code"); + warn("Bad two dim code"); + return EOF; }; constructor.prototype.getWhiteCode = function() { @@ -1721,7 +1743,7 @@ var CCITTFaxStream = (function() { if (n < 9) code <<= 9 - n; p = whiteTable2[code]; - if (p[0] == b) { + if (p[0] == n) { this.eatBits(n); return p[0]; } @@ -1739,7 +1761,9 @@ var CCITTFaxStream = (function() { } } } - error("bad white code"); + warn("bad white code"); + this.eatBits(1); + return 1; }; constructor.prototype.getBlackCode = function() { var code, p, n; @@ -1779,7 +1803,7 @@ var CCITTFaxStream = (function() { if (n < 12) code <<= 12 - n; if (code >= 64) { - p = blackTable[code - 64]; + p = blackTable2[code - 64]; if (p[0] == n) { this.eatBits(n); return p[1]; @@ -1787,7 +1811,7 @@ var CCITTFaxStream = (function() { } } for (n = 10; n <= 13; ++n) { - code = lookBits(n); + code = this.lookBits(n); if (code == EOF) return 1; if (n < 13) @@ -1799,24 +1823,27 @@ var CCITTFaxStream = (function() { } } } - error("bad black code"); + warn("bad black code"); + this.eatBits(1); + return 1; }; constructor.prototype.lookBits = function(n) { var c; - while (inputBits < n) { - if (typeof (c = str.getByte()) == "undefined") { - if (inputBits == 0) + while (this.inputBits < n) { + if (typeof (c = this.str.getByte()) == "undefined") { + if (this.inputBits == 0) return EOF; - return (inputBuf << (n - inputBits)) & (0xFFFF >> (16 - n)); + return (this.inputBuf << (n - this.inputBits)) + & (0xFFFF >> (16 - n)); } - inputBuf = (inputBuf << 8) + c; - inputBits += 8; + this.inputBuf = (this.inputBuf << 8) + c; + this.inputBits += 8; } - return (inputBuf >> (inputBits - n)) & (0xFFFF >> (16 - n)); + return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n)); }; constructor.prototype.eatBits = function(n) { - if ((inputBits -= n) < 0) - inputBits = 0; + if ((this.inputBits -= n) < 0) + this.inputBits = 0; } return constructor; @@ -2433,7 +2460,7 @@ var Parser = (function() { return new Ascii85Stream(stream); } else if (name == "CCITTFaxDecode") { TODO("implement fax stream"); - return new FakeStream(stream); + return new CCITTFaxStream(stream); } else { error("filter '" + name + "' not supported yet"); } @@ -4186,6 +4213,45 @@ var CanvasGraphics = (function() { } } + if (bitsPerComponent == 1) { + var xref = this.xref; + var csStream = dict.get2("ColorSpace", "CS"); + csStream = xref.fetchIfRef(csStream); + if (IsName(csStream) && inline) + csStream = colorSpaces.get(csStream); + var colorSpace = new ColorSpace(xref, csStream); + var numComps = colorSpace.numComps; + if (numComps != 1) + error("worng numComps"); + + var imgArray = image.getBytes((numComps * w * h) >> 3); + var imgIdx = 0; + + var tmpCanvas = document.createElement("canvas"); + tmpCanvas.width = w; + tmpCanvas.height = h; + var tmpCtx = tmpCanvas.getContext("2d"); + var imgData = tmpCtx.getImageData(0, 0, w, h); + var pixels = imgData.data; + + var mask = 128; + var b = 0; + for (var i = 0; i < length; i += 4) { + mask <<= 1; + if (mask >= 256) { + b = imgArray[imgIdx++]; + mask = 1; + } + + var p = b & mask; + pixels[i] = 255 * p; + pixels[i+1] = 255 * p; + pixels[i+2] = 255 * p; + pixels[i+3] = 255; + } + return; + } + if (bitsPerComponent !== 8) error("Unsupported bpc"); From 6446b6d03a6138e5693516d7df1e295e51a25971 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 08:43:26 -0700 Subject: [PATCH 323/439] Run browsers in parallel. No limit on the number of concurrent browsers right now. --- test/test.py | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/test/test.py b/test/test.py index 53f65f78b..7e678bd90 100644 --- a/test/test.py +++ b/test/test.py @@ -1,4 +1,4 @@ -import json, platform, os, shutil, sys, subprocess, tempfile, threading, urllib, urllib2 +import json, platform, os, shutil, sys, subprocess, tempfile, threading, time, urllib, urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import SocketServer from optparse import OptionParser @@ -138,6 +138,7 @@ class BrowserCommand(): def __init__(self, browserRecord): self.name = browserRecord["name"] self.path = browserRecord["path"] + self.tempDir = None if platform.system() == "Darwin" and (self.path.endswith(".app") or self.path.endswith(".app/")): self._fixupMacPath() @@ -151,19 +152,19 @@ class BrowserCommand(): def setup(self): self.tempDir = tempfile.mkdtemp() self.profileDir = os.path.join(self.tempDir, "profile") - print self.profileDir shutil.copytree(os.path.join(DOC_ROOT, "test", "resources", "firefox"), self.profileDir) def teardown(self): - shutil.rmtree(self.tempDir) + if self.tempDir is not None and os.path.exists(self.tempDir): + shutil.rmtree(self.tempDir) def start(self, url): cmds = [self.path] if platform.system() == "Darwin": cmds.append("-foreground") cmds.extend(["-no-remote", "-profile", self.profileDir, url]) - subprocess.call(cmds) + subprocess.Popen(cmds) def makeBrowserCommands(browserManifestFile): with open(browserManifestFile) as bmf: @@ -223,15 +224,22 @@ def setUp(options): State.remaining = len(testBrowsers) * len(manifestList) - for b in testBrowsers: - try: - b.setup() - print 'Launching', b.name - qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) - b.start('http://localhost:8080/test/test_slave.html?'+ qs) - finally: - b.teardown() + return testBrowsers +def startBrowsers(browsers, options): + for b in browsers: + b.setup() + print 'Launching', b.name + qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) + b.start('http://localhost:8080/test/test_slave.html?'+ qs) + +def teardownBrowsers(browsers): + for b in browsers: + try: + b.teardown() + except: + print "Error cleaning up after browser at ", b.path + def check(task, results, browser): failed = False for r in xrange(len(results)): @@ -385,8 +393,14 @@ def main(): httpd_thread.setDaemon(True) httpd_thread.start() - setUp(options) - processResults() + browsers = setUp(options) + try: + startBrowsers(browsers, options) + while not State.done: + time.sleep(1) + processResults() + finally: + teardownBrowsers(browsers) if __name__ == '__main__': main() From a1440b8e15bc8d2d79db8b644b3398bdb6c062a8 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 08:43:26 -0700 Subject: [PATCH 324/439] Run browsers in parallel. No limit on the number of concurrent browsers right now. --- test/test.py | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/test/test.py b/test/test.py index 53f65f78b..7e678bd90 100644 --- a/test/test.py +++ b/test/test.py @@ -1,4 +1,4 @@ -import json, platform, os, shutil, sys, subprocess, tempfile, threading, urllib, urllib2 +import json, platform, os, shutil, sys, subprocess, tempfile, threading, time, urllib, urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import SocketServer from optparse import OptionParser @@ -138,6 +138,7 @@ class BrowserCommand(): def __init__(self, browserRecord): self.name = browserRecord["name"] self.path = browserRecord["path"] + self.tempDir = None if platform.system() == "Darwin" and (self.path.endswith(".app") or self.path.endswith(".app/")): self._fixupMacPath() @@ -151,19 +152,19 @@ class BrowserCommand(): def setup(self): self.tempDir = tempfile.mkdtemp() self.profileDir = os.path.join(self.tempDir, "profile") - print self.profileDir shutil.copytree(os.path.join(DOC_ROOT, "test", "resources", "firefox"), self.profileDir) def teardown(self): - shutil.rmtree(self.tempDir) + if self.tempDir is not None and os.path.exists(self.tempDir): + shutil.rmtree(self.tempDir) def start(self, url): cmds = [self.path] if platform.system() == "Darwin": cmds.append("-foreground") cmds.extend(["-no-remote", "-profile", self.profileDir, url]) - subprocess.call(cmds) + subprocess.Popen(cmds) def makeBrowserCommands(browserManifestFile): with open(browserManifestFile) as bmf: @@ -223,15 +224,22 @@ def setUp(options): State.remaining = len(testBrowsers) * len(manifestList) - for b in testBrowsers: - try: - b.setup() - print 'Launching', b.name - qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) - b.start('http://localhost:8080/test/test_slave.html?'+ qs) - finally: - b.teardown() + return testBrowsers +def startBrowsers(browsers, options): + for b in browsers: + b.setup() + print 'Launching', b.name + qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) + b.start('http://localhost:8080/test/test_slave.html?'+ qs) + +def teardownBrowsers(browsers): + for b in browsers: + try: + b.teardown() + except: + print "Error cleaning up after browser at ", b.path + def check(task, results, browser): failed = False for r in xrange(len(results)): @@ -385,8 +393,14 @@ def main(): httpd_thread.setDaemon(True) httpd_thread.start() - setUp(options) - processResults() + browsers = setUp(options) + try: + startBrowsers(browsers, options) + while not State.done: + time.sleep(1) + processResults() + finally: + teardownBrowsers(browsers) if __name__ == '__main__': main() From a67a4c0677abfd191de0330e18507f834315e7b3 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 09:00:13 -0700 Subject: [PATCH 325/439] Add a line to prevent TestPilot from installing. --- test/resources/firefox/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index d4b9d4130..7ca293923 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -32,3 +32,4 @@ user_pref("app.update.enabled", false); user_pref("browser.panorama.experienced_first_run", true); // Assume experienced user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); +user_pref("extensions.installDistroAddons", false); // prevent testpilot etc From 2bbfb7ae57bb033872dc57f77a80e9c1d5120144 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 09:00:13 -0700 Subject: [PATCH 326/439] Add a line to prevent TestPilot from installing. --- test/resources/firefox/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index d4b9d4130..7ca293923 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -32,3 +32,4 @@ user_pref("app.update.enabled", false); user_pref("browser.panorama.experienced_first_run", true); // Assume experienced user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); +user_pref("extensions.installDistroAddons", false); // prevent testpilot etc From 2b6b6d5ab23de0a99a54d824b0ab4dc4c7fe5af9 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 09:45:41 -0700 Subject: [PATCH 327/439] Try harder to clean up after the browsers. --- test/test.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/test.py b/test/test.py index 7e678bd90..bc30d5f8a 100644 --- a/test/test.py +++ b/test/test.py @@ -139,6 +139,7 @@ class BrowserCommand(): self.name = browserRecord["name"] self.path = browserRecord["path"] self.tempDir = None + self.process = None if platform.system() == "Darwin" and (self.path.endswith(".app") or self.path.endswith(".app/")): self._fixupMacPath() @@ -156,6 +157,17 @@ class BrowserCommand(): self.profileDir) def teardown(self): + # If the browser is still running, wait up to ten seconds for it to quit + if self.process and self.process.poll() is None: + checks = 0 + while self.process.poll() is None and checks < 20: + checks += 1 + time.sleep(.5) + # If it's still not dead, try to kill it + if self.process.poll() is None: + print "Process %s is still running. Killing." % self.name + self.process.kill() + if self.tempDir is not None and os.path.exists(self.tempDir): shutil.rmtree(self.tempDir) @@ -164,7 +176,7 @@ class BrowserCommand(): if platform.system() == "Darwin": cmds.append("-foreground") cmds.extend(["-no-remote", "-profile", self.profileDir, url]) - subprocess.Popen(cmds) + self.process = subprocess.Popen(cmds) def makeBrowserCommands(browserManifestFile): with open(browserManifestFile) as bmf: @@ -239,7 +251,9 @@ def teardownBrowsers(browsers): b.teardown() except: print "Error cleaning up after browser at ", b.path - + print "Temp dir was ", b.tempDir + print "Error:", sys.exc_info()[0] + def check(task, results, browser): failed = False for r in xrange(len(results)): From 87f72705e9e537cf1da76eefe91853702ed4ae7a Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 09:45:41 -0700 Subject: [PATCH 328/439] Try harder to clean up after the browsers. --- test/test.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/test.py b/test/test.py index 7e678bd90..bc30d5f8a 100644 --- a/test/test.py +++ b/test/test.py @@ -139,6 +139,7 @@ class BrowserCommand(): self.name = browserRecord["name"] self.path = browserRecord["path"] self.tempDir = None + self.process = None if platform.system() == "Darwin" and (self.path.endswith(".app") or self.path.endswith(".app/")): self._fixupMacPath() @@ -156,6 +157,17 @@ class BrowserCommand(): self.profileDir) def teardown(self): + # If the browser is still running, wait up to ten seconds for it to quit + if self.process and self.process.poll() is None: + checks = 0 + while self.process.poll() is None and checks < 20: + checks += 1 + time.sleep(.5) + # If it's still not dead, try to kill it + if self.process.poll() is None: + print "Process %s is still running. Killing." % self.name + self.process.kill() + if self.tempDir is not None and os.path.exists(self.tempDir): shutil.rmtree(self.tempDir) @@ -164,7 +176,7 @@ class BrowserCommand(): if platform.system() == "Darwin": cmds.append("-foreground") cmds.extend(["-no-remote", "-profile", self.profileDir, url]) - subprocess.Popen(cmds) + self.process = subprocess.Popen(cmds) def makeBrowserCommands(browserManifestFile): with open(browserManifestFile) as bmf: @@ -239,7 +251,9 @@ def teardownBrowsers(browsers): b.teardown() except: print "Error cleaning up after browser at ", b.path - + print "Temp dir was ", b.tempDir + print "Error:", sys.exc_info()[0] + def check(task, results, browser): failed = False for r in xrange(len(results)): From 2d4c2c0ff35a6cc5bc4135dd9e73ca0767687f83 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 10:24:31 -0700 Subject: [PATCH 329/439] draws a broken image --- pdf.js | 57 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/pdf.js b/pdf.js index dea681265..0be4abc7c 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ "use strict"; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = WARNINGS; +var verbosity = ERRORS; function log(msg) { if (console && console.log) @@ -889,7 +889,7 @@ var CCITTFaxStream = (function() { const twoDimVertR3 = 7; const twoDimVertL3 = 8; - const twoDimTable1 = [ + const twoDimTable = [ [-1, -1], [-1, -1], // 000000x [7, twoDimVertL3], // 0000010 [7, twoDimVertR3], // 0000011 @@ -1304,33 +1304,34 @@ var CCITTFaxStream = (function() { [2, 2], [2, 2], [2, 2], [2, 2] ]; - function constructor(str) { + function constructor(str, params) { this.str = str; - var dict = str.dict; - this.dict = dict; + this.dict = str.dict; - this.encoding = dict.get("K") || 0; - this.eoline = dict.get("EndOfLine") || false; - this.byteAlign = dict.get("EncodedByteAlign") || false; - this.columns = dict.get("Columns") || 1728; - this.rows = dict.get("Rows") || 0; - var eoblock = dict.get("EndOfBlock"); + params = params || new Dict(); + + this.encoding = params.get("K") || 0; + this.eoline = params.get("EndOfLine") || false; + this.byteAlign = params.get("EncodedByteAlign") || false; + this.columns = params.get("Columns") || 1728; + this.rows = params.get("Rows") || 0; + var eoblock = params.get("EndOfBlock"); if (typeof eoblock == "undefined") eoblock = true; - this.black = dict.get("BlackIs1") || false; + this.eoblock = eoblock; + this.black = params.get("BlackIs1") || false; - this.codingLine = new Uint8Array(this.columns + 1); + this.codingLine = new Uint32Array(this.columns + 1); this.codingLine[0] = this.columns; this.codingPos = 0; - this.refLine = new Uint8Array(this.columns + 2); + this.refLine = new Uint32Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; this.inputBuf; this.outputBits = 0; this.buf = EOF; - this.err = false; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1352,10 +1353,8 @@ var CCITTFaxStream = (function() { while (!this.eof) { var c = this.lookChar(); this.buf = EOF; - if (this.bufferLength <= this.pos) - this.ensureBuffer(this.pos + 1); - - this.buffer[this.pos++] = c; + this.ensureBuffer(this.bufferLength + 1); + this.buffer[this.bufferLength++] = c; } }; constructor.prototype.addPixels = function(a1, blackPixels) { @@ -1419,6 +1418,8 @@ var CCITTFaxStream = (function() { if (this.eof) return; + this.err = false; + if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) refLine[i] = codingLine[i]; @@ -1431,7 +1432,7 @@ var CCITTFaxStream = (function() { blackPixels = 0; while (codingLine[this.codingPos] < columns) { - var code1 = this.getTwoDumCode(); + var code1 = this.getTwoDimCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); @@ -1530,7 +1531,7 @@ var CCITTFaxStream = (function() { else ++refPos; while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[redPos] < columns) + refLine[refPos] < columns) refPos += 2; } break; @@ -2466,7 +2467,7 @@ var Parser = (function() { return new Ascii85Stream(stream); } else if (name == "CCITTFaxDecode") { TODO("implement fax stream"); - return new CCITTFaxStream(stream); + return new CCITTFaxStream(stream, params); } else { error("filter '" + name + "' not supported yet"); } @@ -4272,12 +4273,14 @@ var CanvasGraphics = (function() { tmpCanvas.width = w; tmpCanvas.height = h; var tmpCtx = tmpCanvas.getContext("2d"); + tmpCtx.fillStyle = "#000"; + tmpCtx.fillRect(0, 0, w, h); var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; var mask = 128; var b = 0; - for (var i = 0; i < length; i += 4) { + for (var i = 0, length = imgArray.length*8*4; i < length; i += 4) { mask <<= 1; if (mask >= 256) { b = imgArray[imgIdx++]; @@ -4285,11 +4288,19 @@ var CanvasGraphics = (function() { } var p = b & mask; + if (p > 0) + p = 1; + else + p = 0; pixels[i] = 255 * p; pixels[i+1] = 255 * p; pixels[i+2] = 255 * p; pixels[i+3] = 255; } + + tmpCtx.putImageData(imgData, 0, 0); + ctx.drawImage(tmpCanvas, 0, -h); + this.restore(); return; } From 383bc110cc65951cfb44d454188e673a8b5c0f0a Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 10:24:31 -0700 Subject: [PATCH 330/439] draws a broken image --- pdf.js | 57 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/pdf.js b/pdf.js index dea681265..0be4abc7c 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ "use strict"; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = WARNINGS; +var verbosity = ERRORS; function log(msg) { if (console && console.log) @@ -889,7 +889,7 @@ var CCITTFaxStream = (function() { const twoDimVertR3 = 7; const twoDimVertL3 = 8; - const twoDimTable1 = [ + const twoDimTable = [ [-1, -1], [-1, -1], // 000000x [7, twoDimVertL3], // 0000010 [7, twoDimVertR3], // 0000011 @@ -1304,33 +1304,34 @@ var CCITTFaxStream = (function() { [2, 2], [2, 2], [2, 2], [2, 2] ]; - function constructor(str) { + function constructor(str, params) { this.str = str; - var dict = str.dict; - this.dict = dict; + this.dict = str.dict; - this.encoding = dict.get("K") || 0; - this.eoline = dict.get("EndOfLine") || false; - this.byteAlign = dict.get("EncodedByteAlign") || false; - this.columns = dict.get("Columns") || 1728; - this.rows = dict.get("Rows") || 0; - var eoblock = dict.get("EndOfBlock"); + params = params || new Dict(); + + this.encoding = params.get("K") || 0; + this.eoline = params.get("EndOfLine") || false; + this.byteAlign = params.get("EncodedByteAlign") || false; + this.columns = params.get("Columns") || 1728; + this.rows = params.get("Rows") || 0; + var eoblock = params.get("EndOfBlock"); if (typeof eoblock == "undefined") eoblock = true; - this.black = dict.get("BlackIs1") || false; + this.eoblock = eoblock; + this.black = params.get("BlackIs1") || false; - this.codingLine = new Uint8Array(this.columns + 1); + this.codingLine = new Uint32Array(this.columns + 1); this.codingLine[0] = this.columns; this.codingPos = 0; - this.refLine = new Uint8Array(this.columns + 2); + this.refLine = new Uint32Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; this.inputBuf; this.outputBits = 0; this.buf = EOF; - this.err = false; var code1; while ((code1 = this.lookBits(12)) == 0) { @@ -1352,10 +1353,8 @@ var CCITTFaxStream = (function() { while (!this.eof) { var c = this.lookChar(); this.buf = EOF; - if (this.bufferLength <= this.pos) - this.ensureBuffer(this.pos + 1); - - this.buffer[this.pos++] = c; + this.ensureBuffer(this.bufferLength + 1); + this.buffer[this.bufferLength++] = c; } }; constructor.prototype.addPixels = function(a1, blackPixels) { @@ -1419,6 +1418,8 @@ var CCITTFaxStream = (function() { if (this.eof) return; + this.err = false; + if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) refLine[i] = codingLine[i]; @@ -1431,7 +1432,7 @@ var CCITTFaxStream = (function() { blackPixels = 0; while (codingLine[this.codingPos] < columns) { - var code1 = this.getTwoDumCode(); + var code1 = this.getTwoDimCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); @@ -1530,7 +1531,7 @@ var CCITTFaxStream = (function() { else ++refPos; while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[redPos] < columns) + refLine[refPos] < columns) refPos += 2; } break; @@ -2466,7 +2467,7 @@ var Parser = (function() { return new Ascii85Stream(stream); } else if (name == "CCITTFaxDecode") { TODO("implement fax stream"); - return new CCITTFaxStream(stream); + return new CCITTFaxStream(stream, params); } else { error("filter '" + name + "' not supported yet"); } @@ -4272,12 +4273,14 @@ var CanvasGraphics = (function() { tmpCanvas.width = w; tmpCanvas.height = h; var tmpCtx = tmpCanvas.getContext("2d"); + tmpCtx.fillStyle = "#000"; + tmpCtx.fillRect(0, 0, w, h); var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; var mask = 128; var b = 0; - for (var i = 0; i < length; i += 4) { + for (var i = 0, length = imgArray.length*8*4; i < length; i += 4) { mask <<= 1; if (mask >= 256) { b = imgArray[imgIdx++]; @@ -4285,11 +4288,19 @@ var CanvasGraphics = (function() { } var p = b & mask; + if (p > 0) + p = 1; + else + p = 0; pixels[i] = 255 * p; pixels[i+1] = 255 * p; pixels[i+2] = 255 * p; pixels[i+3] = 255; } + + tmpCtx.putImageData(imgData, 0, 0); + ctx.drawImage(tmpCanvas, 0, -h); + this.restore(); return; } From 3d85caa212cf8b86379d94932abca2618ee5b007 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 21:25:08 +0200 Subject: [PATCH 331/439] Do not add the font-loader canvas to the page dom to save some load time --- fonts.js | 58 +++++++++----------------------------------------------- 1 file changed, 9 insertions(+), 49 deletions(-) diff --git a/fonts.js b/fonts.js index 7e8aecd6d..c817b12e5 100644 --- a/fonts.js +++ b/fonts.js @@ -104,6 +104,7 @@ var FontsLoader = { worker ? obj.bindWorker(str) : obj.bindDOM(str); } + return ready; } }; @@ -766,96 +767,55 @@ var Font = (function () { return fontData; }, - bindWorker: function font_bind_worker(dataStr) { + bindWorker: function font_bindWorker(data) { postMessage({ action: "font", data: { - raw: dataStr, + raw: data, fontName: this.name, mimetype: this.mimetype } }); }, - bindDOM: function font_bind_dom(dataStr) { + bindDOM: function font_bindDom(data) { var fontName = this.name; /** Hack begin */ // Actually there is not event when a font has finished downloading so // the following code are a dirty hack to 'guess' when a font is ready + // This code could go away when bug 471915 has landed var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); - - // Get the font size canvas think it will be for 'spaces' var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + ctx.font = "bold italic 20px " + fontName + ", Symbol"; var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); - - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; - - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); - - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } - - ctx.fillText(testString, 20, 20); - } - // Periodicaly check for the width of the testString, it will be // different once the real font has loaded var textWidth = ctx.measureText(testString).width; var interval = window.setInterval(function canvasInterval(self) { this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + ctx.font = "bold italic 20px " + fontName + ", Symbol"; // For some reasons the font has not loaded, so mark it loaded for the // page to proceed but cry if ((Date.now() - this.start) >= kMaxWaitForFontFace) { window.clearInterval(interval); Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); + warn("Is " + fontName + " loaded?"); this.start = 0; } else if (textWidth != ctx.measureText(testString).width) { window.clearInterval(interval); Fonts[fontName].loading = false; this.start = 0; } - - if (debug) - ctx.fillText(testString, 20, 50); }, 30, this); /** Hack end */ - - // Convert the data string and add it to the page. - var base64 = window.btoa(dataStr); // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; + var url = "url(data:" + this.mimetype + ";base64," + window.btoa(data) + ");"; var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); From c1c8ca4ef3a010725bc694041912df9a77ec2e7c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 21:25:08 +0200 Subject: [PATCH 332/439] Do not add the font-loader canvas to the page dom to save some load time --- fonts.js | 58 +++++++++----------------------------------------------- 1 file changed, 9 insertions(+), 49 deletions(-) diff --git a/fonts.js b/fonts.js index 7e8aecd6d..c817b12e5 100644 --- a/fonts.js +++ b/fonts.js @@ -104,6 +104,7 @@ var FontsLoader = { worker ? obj.bindWorker(str) : obj.bindDOM(str); } + return ready; } }; @@ -766,96 +767,55 @@ var Font = (function () { return fontData; }, - bindWorker: function font_bind_worker(dataStr) { + bindWorker: function font_bindWorker(data) { postMessage({ action: "font", data: { - raw: dataStr, + raw: data, fontName: this.name, mimetype: this.mimetype } }); }, - bindDOM: function font_bind_dom(dataStr) { + bindDOM: function font_bindDom(data) { var fontName = this.name; /** Hack begin */ // Actually there is not event when a font has finished downloading so // the following code are a dirty hack to 'guess' when a font is ready + // This code could go away when bug 471915 has landed var canvas = document.createElement("canvas"); - var style = "border: 1px solid black; position:absolute; top: " + - (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; - canvas.setAttribute("style", style); - canvas.setAttribute("width", 340); - canvas.setAttribute("heigth", 100); - document.body.appendChild(canvas); - - // Get the font size canvas think it will be for 'spaces' var ctx = canvas.getContext("2d"); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + ctx.font = "bold italic 20px " + fontName + ", Symbol"; var testString = " "; - // When debugging use the characters provided by the charsets to visually - // see what's happening instead of 'spaces' - var debug = false; - if (debug) { - var name = document.createElement("font"); - name.setAttribute("style", "position: absolute; left: 20px; top: " + - (100 * fontCount + 60) + "px"); - name.innerHTML = fontName; - document.body.appendChild(name); - - // Retrieve font charset - var charset = Fonts[fontName].properties.charset || []; - - // if the charset is too small make it repeat a few times - var count = 30; - while (count-- && charset.length <= 30) - charset = charset.concat(charset.slice()); - - for (var i = 0; i < charset.length; i++) { - var unicode = GlyphsUnicode[charset[i]]; - if (!unicode) - continue; - testString += String.fromCharCode(unicode); - } - - ctx.fillText(testString, 20, 20); - } - // Periodicaly check for the width of the testString, it will be // different once the real font has loaded var textWidth = ctx.measureText(testString).width; var interval = window.setInterval(function canvasInterval(self) { this.start = this.start || Date.now(); - ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; + ctx.font = "bold italic 20px " + fontName + ", Symbol"; // For some reasons the font has not loaded, so mark it loaded for the // page to proceed but cry if ((Date.now() - this.start) >= kMaxWaitForFontFace) { window.clearInterval(interval); Fonts[fontName].loading = false; - warn("Is " + fontName + " for charset: " + charset + " loaded?"); + warn("Is " + fontName + " loaded?"); this.start = 0; } else if (textWidth != ctx.measureText(testString).width) { window.clearInterval(interval); Fonts[fontName].loading = false; this.start = 0; } - - if (debug) - ctx.fillText(testString, 20, 50); }, 30, this); /** Hack end */ - - // Convert the data string and add it to the page. - var base64 = window.btoa(dataStr); // Add the @font-face rule to the document - var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; + var url = "url(data:" + this.mimetype + ";base64," + window.btoa(data) + ");"; var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.length); From 83fabc49c2dac7f2dac16bdd26a759a8575f0183 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 21:46:48 +0200 Subject: [PATCH 333/439] Update the multi_page_viewer.js code to work with the new FontLoader API --- multi_page_viewer.js | 73 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 3a02ea332..1631433ca 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -3,6 +3,8 @@ "use strict"; +var pageTimeout; + var PDFViewer = { queryParams: {}, @@ -75,81 +77,45 @@ var PDFViewer = { }, drawPage: function(num) { - if (!PDFViewer.pdf) { + if (!PDFViewer.pdf) return; - } - + var div = document.getElementById('pageContainer' + num); var canvas = document.createElement('canvas'); - + if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - var page = PDFViewer.pdf.getPage(num); - + canvas.id = 'page' + num; canvas.mozOpaque = true; - + // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. canvas.width = PDFViewer.pageWidth(); canvas.height = PDFViewer.pageHeight(); - + div.appendChild(canvas); + var ctx = canvas.getContext('2d'); ctx.save(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); - + var gfx = new CanvasGraphics(ctx); - var fonts = []; - + // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display + var fonts = []; page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; + + var loadFont = function() { + if (!FontsLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; + page.display(gfx); } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); + loadFont(); } }, @@ -258,7 +224,6 @@ var PDFViewer = { }; window.onload = function() { - // Parse the URL query parameters into a cached object. PDFViewer.queryParams = function() { var qs = window.location.search.substring(1); From f13cbe883f32fea1b590a352b18ac0b18891ebf3 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 21:46:48 +0200 Subject: [PATCH 334/439] Update the multi_page_viewer.js code to work with the new FontLoader API --- multi_page_viewer.js | 73 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 3a02ea332..1631433ca 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -3,6 +3,8 @@ "use strict"; +var pageTimeout; + var PDFViewer = { queryParams: {}, @@ -75,81 +77,45 @@ var PDFViewer = { }, drawPage: function(num) { - if (!PDFViewer.pdf) { + if (!PDFViewer.pdf) return; - } - + var div = document.getElementById('pageContainer' + num); var canvas = document.createElement('canvas'); - + if (div && !div.hasChildNodes()) { - div.appendChild(canvas); - var page = PDFViewer.pdf.getPage(num); - + canvas.id = 'page' + num; canvas.mozOpaque = true; - + // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. canvas.width = PDFViewer.pageWidth(); canvas.height = PDFViewer.pageHeight(); - + div.appendChild(canvas); + var ctx = canvas.getContext('2d'); ctx.save(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); - + var gfx = new CanvasGraphics(ctx); - var fonts = []; - + // page.compile will collect all fonts for us, once we have loaded them // we can trigger the actual page rendering with page.display + var fonts = []; page.compile(gfx, fonts); - - var areFontsReady = true; - - // Inspect fonts and translate the missing one - var fontCount = fonts.length; - - for (var i = 0; i < fontCount; i++) { - var font = fonts[i]; - - if (Fonts[font.name]) { - areFontsReady = areFontsReady && !Fonts[font.name].loading; - continue; + + var loadFont = function() { + if (!FontsLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; } - - new Font(font.name, font.file, font.properties); - - areFontsReady = false; + page.display(gfx); } - - var pageInterval; - - var delayLoadFont = function() { - for (var i = 0; i < fontCount; i++) { - if (Fonts[font.name].loading) { - return; - } - } - - clearInterval(pageInterval); - - while (div.hasChildNodes()) { - div.removeChild(div.firstChild); - } - - PDFViewer.drawPage(num); - } - - if (!areFontsReady) { - pageInterval = setInterval(delayLoadFont, 10); - return; - } - - page.display(gfx); + loadFont(); } }, @@ -258,7 +224,6 @@ var PDFViewer = { }; window.onload = function() { - // Parse the URL query parameters into a cached object. PDFViewer.queryParams = function() { var qs = window.location.search.substring(1); From b7f24d27192f7ceb0f9c11f306561331e920228b Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 13:59:37 -0700 Subject: [PATCH 335/439] working version of faxstream --- pdf.js | 77 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/pdf.js b/pdf.js index 0be4abc7c..7b0889485 100644 --- a/pdf.js +++ b/pdf.js @@ -1322,10 +1322,11 @@ var CCITTFaxStream = (function() { this.black = params.get("BlackIs1") || false; this.codingLine = new Uint32Array(this.columns + 1); + this.refLine = new Uint32Array(this.columns + 2); + this.codingLine[0] = this.columns; this.codingPos = 0; - this.refLine = new Uint32Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; @@ -1350,12 +1351,20 @@ var CCITTFaxStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { + var vals = []; while (!this.eof) { var c = this.lookChar(); + vals.push(c); this.buf = EOF; this.ensureBuffer(this.bufferLength + 1); this.buffer[this.bufferLength++] = c; } + var all = ""; + for (var i = 0; i < vals.length; ++i) + all += vals[i] + " \n"; + + var text = document.getElementById("text"); + text.value = all; }; constructor.prototype.addPixels = function(a1, blackPixels) { var codingLine = this.codingLine; @@ -1412,8 +1421,6 @@ var CCITTFaxStream = (function() { if (this.buf != EOF) return buf; - this.err = false; - if (this.outputBits == 0) { if (this.eof) return; @@ -1494,7 +1501,7 @@ var CCITTFaxStream = (function() { blackPixels ^= 1; if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] < codingLine[this.codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } @@ -1535,7 +1542,6 @@ var CCITTFaxStream = (function() { refPos += 2; } break; - case twoDimVertL1: this.addPixelsNeg(refLine[refPos] - 1, blackPixels); blackPixels ^= 1; @@ -1556,7 +1562,7 @@ var CCITTFaxStream = (function() { break; default: warn("bad 2d code"); - addPixels(columns, 0); + this.addPixels(columns, 0); this.err = true; break; } @@ -1586,7 +1592,7 @@ var CCITTFaxStream = (function() { var gotEOL = false; - if (this.eoblock && this.row == this.rows - 1) { + if (!this.eoblock && this.row == this.rows - 1) { this.eof = true; } else { code1 = this.lookBits(12); @@ -1610,7 +1616,7 @@ var CCITTFaxStream = (function() { if (this.eoblock && gotEOL) { code1 = this.lookBits(12); if (code1 == 1) { - eatBits(12); + this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); @@ -1619,7 +1625,7 @@ var CCITTFaxStream = (function() { for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) - error("bad rtc code"); + warning("bad rtc code"); this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); @@ -1629,7 +1635,7 @@ var CCITTFaxStream = (function() { } this.eof = true; } - } else if (this.err && this.eolin) { + } else if (this.err && this.eoline) { var code1; while (true) { code1 = this.lookBits(13); @@ -1645,7 +1651,7 @@ var CCITTFaxStream = (function() { this.eatBits(12); if (this.encoding > 0) { this.eatBits(1); - this.nextLine2 = !(code1 & 1); + this.nextLine2D = !(code1 & 1); } } @@ -1664,32 +1670,32 @@ var CCITTFaxStream = (function() { this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; } } else { - this.bits = 8; + var bits = 8; this.buf = 0; do { - if (this.outputBits > this.bits) { - this.buf << this.bits; + if (this.outputBits > bits) { + this.buf <<= bits; if (!(this.codingPos & 1)) { - this.buf |= 0xFF >> (8 - this.bits); + this.buf |= 0xFF >> (8 - bits); } - this.outputBits -= this.bits; - this.bits = 0; + this.outputBits -= bits; + bits = 0; } else { this.buf <<= this.outputBits; if (!(this.codingPos & 1)) { this.buf |= 0xFF >> (8 - this.outputBits); } - this.bits -= this.outputBits; + bits -= this.outputBits; this.outputBits = 0; if (codingLine[this.codingPos] < columns) { this.codingPos++; this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; - } else if (this.bits > 0) { - this.buf <<= this.bits; - this.bits = 0; + } else if (bits > 0) { + this.buf <<= bits; + bits = 0; } } - } while (this.bits); + } while (bits); } if (this.black) { this.buf ^= 0xFF; @@ -1729,7 +1735,7 @@ var CCITTFaxStream = (function() { var n; if (this.eoblock) { code = this.lookBits(12); - if (typeof code == "undefined") + if (code == EOF) return 1; if ((code >> 5) == 0) @@ -1744,20 +1750,20 @@ var CCITTFaxStream = (function() { } else { for (var n = 1; n <= 9; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 9) code <<= 9 - n; p = whiteTable2[code]; if (p[0] == n) { - this.eatBits(n); + this.eatBits(n); return p[0]; } } for (var n = 11; n <= 12; ++n) { code == this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 12) code <<= 12 - n; @@ -1776,7 +1782,7 @@ var CCITTFaxStream = (function() { var code, p, n; if (this.eoblock) { code = this.lookBits(13); - if (typeof code == "undefined") + if (code == EOF) return 1; if ((code >> 7) == 0) p = blackTable1[code]; @@ -1792,7 +1798,7 @@ var CCITTFaxStream = (function() { } else { for (var n = 2; n <= 6; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 6) code <<= 6 - n; @@ -1805,7 +1811,7 @@ var CCITTFaxStream = (function() { } for (var n = 7; n <= 12; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 12) code <<= 12 - n; @@ -4266,6 +4272,9 @@ var CanvasGraphics = (function() { if (numComps != 1) error("worng numComps"); + ctx.strokeStyle = "#090"; + ctx.strokeRect(0 + 1, -h + 1, w / 2, h -2 ); + var imgArray = image.getBytes((numComps * w * h) >> 3); var imgIdx = 0; @@ -4278,13 +4287,13 @@ var CanvasGraphics = (function() { var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; - var mask = 128; + var mask = 1; var b = 0; - for (var i = 0, length = imgArray.length*8*4; i < length; i += 4) { - mask <<= 1; - if (mask >= 256) { + for (var i = 0, length = 4 * w * h; i < length; i += 4) { + mask >>= 1; + if (mask <= 0) { b = imgArray[imgIdx++]; - mask = 1; + mask = 128; } var p = b & mask; From 363a631356f3c68fd497d44b7b5f7124aba40180 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 13:59:37 -0700 Subject: [PATCH 336/439] working version of faxstream --- pdf.js | 77 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/pdf.js b/pdf.js index 0be4abc7c..7b0889485 100644 --- a/pdf.js +++ b/pdf.js @@ -1322,10 +1322,11 @@ var CCITTFaxStream = (function() { this.black = params.get("BlackIs1") || false; this.codingLine = new Uint32Array(this.columns + 1); + this.refLine = new Uint32Array(this.columns + 2); + this.codingLine[0] = this.columns; this.codingPos = 0; - this.refLine = new Uint32Array(this.columns + 2); this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; @@ -1350,12 +1351,20 @@ var CCITTFaxStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { + var vals = []; while (!this.eof) { var c = this.lookChar(); + vals.push(c); this.buf = EOF; this.ensureBuffer(this.bufferLength + 1); this.buffer[this.bufferLength++] = c; } + var all = ""; + for (var i = 0; i < vals.length; ++i) + all += vals[i] + " \n"; + + var text = document.getElementById("text"); + text.value = all; }; constructor.prototype.addPixels = function(a1, blackPixels) { var codingLine = this.codingLine; @@ -1412,8 +1421,6 @@ var CCITTFaxStream = (function() { if (this.buf != EOF) return buf; - this.err = false; - if (this.outputBits == 0) { if (this.eof) return; @@ -1494,7 +1501,7 @@ var CCITTFaxStream = (function() { blackPixels ^= 1; if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] < codingLine[this.codingPos] && + while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) refPos += 2; } @@ -1535,7 +1542,6 @@ var CCITTFaxStream = (function() { refPos += 2; } break; - case twoDimVertL1: this.addPixelsNeg(refLine[refPos] - 1, blackPixels); blackPixels ^= 1; @@ -1556,7 +1562,7 @@ var CCITTFaxStream = (function() { break; default: warn("bad 2d code"); - addPixels(columns, 0); + this.addPixels(columns, 0); this.err = true; break; } @@ -1586,7 +1592,7 @@ var CCITTFaxStream = (function() { var gotEOL = false; - if (this.eoblock && this.row == this.rows - 1) { + if (!this.eoblock && this.row == this.rows - 1) { this.eof = true; } else { code1 = this.lookBits(12); @@ -1610,7 +1616,7 @@ var CCITTFaxStream = (function() { if (this.eoblock && gotEOL) { code1 = this.lookBits(12); if (code1 == 1) { - eatBits(12); + this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); this.eatBits(1); @@ -1619,7 +1625,7 @@ var CCITTFaxStream = (function() { for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) - error("bad rtc code"); + warning("bad rtc code"); this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); @@ -1629,7 +1635,7 @@ var CCITTFaxStream = (function() { } this.eof = true; } - } else if (this.err && this.eolin) { + } else if (this.err && this.eoline) { var code1; while (true) { code1 = this.lookBits(13); @@ -1645,7 +1651,7 @@ var CCITTFaxStream = (function() { this.eatBits(12); if (this.encoding > 0) { this.eatBits(1); - this.nextLine2 = !(code1 & 1); + this.nextLine2D = !(code1 & 1); } } @@ -1664,32 +1670,32 @@ var CCITTFaxStream = (function() { this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; } } else { - this.bits = 8; + var bits = 8; this.buf = 0; do { - if (this.outputBits > this.bits) { - this.buf << this.bits; + if (this.outputBits > bits) { + this.buf <<= bits; if (!(this.codingPos & 1)) { - this.buf |= 0xFF >> (8 - this.bits); + this.buf |= 0xFF >> (8 - bits); } - this.outputBits -= this.bits; - this.bits = 0; + this.outputBits -= bits; + bits = 0; } else { this.buf <<= this.outputBits; if (!(this.codingPos & 1)) { this.buf |= 0xFF >> (8 - this.outputBits); } - this.bits -= this.outputBits; + bits -= this.outputBits; this.outputBits = 0; if (codingLine[this.codingPos] < columns) { this.codingPos++; this.outputBits = codingLine[this.codingPos] - codingLine[this.codingPos - 1]; - } else if (this.bits > 0) { - this.buf <<= this.bits; - this.bits = 0; + } else if (bits > 0) { + this.buf <<= bits; + bits = 0; } } - } while (this.bits); + } while (bits); } if (this.black) { this.buf ^= 0xFF; @@ -1729,7 +1735,7 @@ var CCITTFaxStream = (function() { var n; if (this.eoblock) { code = this.lookBits(12); - if (typeof code == "undefined") + if (code == EOF) return 1; if ((code >> 5) == 0) @@ -1744,20 +1750,20 @@ var CCITTFaxStream = (function() { } else { for (var n = 1; n <= 9; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 9) code <<= 9 - n; p = whiteTable2[code]; if (p[0] == n) { - this.eatBits(n); + this.eatBits(n); return p[0]; } } for (var n = 11; n <= 12; ++n) { code == this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 12) code <<= 12 - n; @@ -1776,7 +1782,7 @@ var CCITTFaxStream = (function() { var code, p, n; if (this.eoblock) { code = this.lookBits(13); - if (typeof code == "undefined") + if (code == EOF) return 1; if ((code >> 7) == 0) p = blackTable1[code]; @@ -1792,7 +1798,7 @@ var CCITTFaxStream = (function() { } else { for (var n = 2; n <= 6; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 6) code <<= 6 - n; @@ -1805,7 +1811,7 @@ var CCITTFaxStream = (function() { } for (var n = 7; n <= 12; ++n) { code = this.lookBits(n); - if (typeof code == "undefined") + if (code == EOF) return 1; if (n < 12) code <<= 12 - n; @@ -4266,6 +4272,9 @@ var CanvasGraphics = (function() { if (numComps != 1) error("worng numComps"); + ctx.strokeStyle = "#090"; + ctx.strokeRect(0 + 1, -h + 1, w / 2, h -2 ); + var imgArray = image.getBytes((numComps * w * h) >> 3); var imgIdx = 0; @@ -4278,13 +4287,13 @@ var CanvasGraphics = (function() { var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; - var mask = 128; + var mask = 1; var b = 0; - for (var i = 0, length = imgArray.length*8*4; i < length; i += 4) { - mask <<= 1; - if (mask >= 256) { + for (var i = 0, length = 4 * w * h; i < length; i += 4) { + mask >>= 1; + if (mask <= 0) { b = imgArray[imgIdx++]; - mask = 1; + mask = 128; } var p = b & mask; From 1057d0f337aef3252184027e95c290001ec12c1b Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 14:10:25 -0700 Subject: [PATCH 337/439] removed debug code --- pdf.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pdf.js b/pdf.js index 7b0889485..c90e35bab 100644 --- a/pdf.js +++ b/pdf.js @@ -1351,20 +1351,12 @@ var CCITTFaxStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { - var vals = []; while (!this.eof) { var c = this.lookChar(); - vals.push(c); this.buf = EOF; this.ensureBuffer(this.bufferLength + 1); this.buffer[this.bufferLength++] = c; } - var all = ""; - for (var i = 0; i < vals.length; ++i) - all += vals[i] + " \n"; - - var text = document.getElementById("text"); - text.value = all; }; constructor.prototype.addPixels = function(a1, blackPixels) { var codingLine = this.codingLine; From 6df5714ec3ca465964e25263c35b180153b47d9b Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 14:10:25 -0700 Subject: [PATCH 338/439] removed debug code --- pdf.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pdf.js b/pdf.js index 7b0889485..c90e35bab 100644 --- a/pdf.js +++ b/pdf.js @@ -1351,20 +1351,12 @@ var CCITTFaxStream = (function() { constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { - var vals = []; while (!this.eof) { var c = this.lookChar(); - vals.push(c); this.buf = EOF; this.ensureBuffer(this.bufferLength + 1); this.buffer[this.bufferLength++] = c; } - var all = ""; - for (var i = 0; i < vals.length; ++i) - all += vals[i] + " \n"; - - var text = document.getElementById("text"); - text.value = all; }; constructor.prototype.addPixels = function(a1, blackPixels) { var codingLine = this.codingLine; From f317eae084fa8e77e808105454432aa26966d597 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 24 Jun 2011 17:12:06 -0400 Subject: [PATCH 339/439] nits --- fonts.js | 6 +++--- multi_page_viewer.js | 2 +- viewer.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fonts.js b/fonts.js index c817b12e5..ac06b76ae 100644 --- a/fonts.js +++ b/fonts.js @@ -80,7 +80,7 @@ var Fonts = { } }; -var FontsLoader = { +var FontLoader = { bind: function(fonts) { var worker = (typeof window == "undefined"); var ready = true; @@ -90,10 +90,10 @@ var FontsLoader = { if (Fonts[font.name]) { ready = ready && !Fonts[font.name].loading; continue; - } else { - ready = false; } + ready = false; + var obj = new Font(font.name, font.file, font.properties); var str = ""; diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 1631433ca..f262734d3 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -109,7 +109,7 @@ var PDFViewer = { page.compile(gfx, fonts); var loadFont = function() { - if (!FontsLoader.bind(fonts)) { + if (!FontLoader.bind(fonts)) { pageTimeout = window.setTimeout(loadFont, 10); return; } diff --git a/viewer.js b/viewer.js index 2bcff50a6..c7be739bc 100644 --- a/viewer.js +++ b/viewer.js @@ -76,7 +76,7 @@ function displayPage(num) { var t2 = Date.now(); function loadFont() { - if (!FontsLoader.bind(fonts)) { + if (!FontLoader.bind(fonts)) { pageTimeout = window.setTimeout(loadFont, 10); return; } From cdb8788865cda2ab73e54631874d3aef65927e5b Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 24 Jun 2011 17:12:06 -0400 Subject: [PATCH 340/439] nits --- fonts.js | 6 +++--- multi_page_viewer.js | 2 +- viewer.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fonts.js b/fonts.js index c817b12e5..ac06b76ae 100644 --- a/fonts.js +++ b/fonts.js @@ -80,7 +80,7 @@ var Fonts = { } }; -var FontsLoader = { +var FontLoader = { bind: function(fonts) { var worker = (typeof window == "undefined"); var ready = true; @@ -90,10 +90,10 @@ var FontsLoader = { if (Fonts[font.name]) { ready = ready && !Fonts[font.name].loading; continue; - } else { - ready = false; } + ready = false; + var obj = new Font(font.name, font.file, font.properties); var str = ""; diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 1631433ca..f262734d3 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -109,7 +109,7 @@ var PDFViewer = { page.compile(gfx, fonts); var loadFont = function() { - if (!FontsLoader.bind(fonts)) { + if (!FontLoader.bind(fonts)) { pageTimeout = window.setTimeout(loadFont, 10); return; } diff --git a/viewer.js b/viewer.js index 2bcff50a6..c7be739bc 100644 --- a/viewer.js +++ b/viewer.js @@ -76,7 +76,7 @@ function displayPage(num) { var t2 = Date.now(); function loadFont() { - if (!FontsLoader.bind(fonts)) { + if (!FontLoader.bind(fonts)) { pageTimeout = window.setTimeout(loadFont, 10); return; } From dd9423624c633db28032ed6fbbb905b2286afc55 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 23:33:16 +0200 Subject: [PATCH 341/439] Fix some warnings --- utils/fonts_utils.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index de4ceea72..532853460 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -194,6 +194,8 @@ function readFontIndexData(aStream, aIsByte) { return aStream.getByte() << 24 | aStream.getByte() << 16 | aStream.getByte() << 8 | aStream.getByte(); } + error(offsize + " is not a valid offset size"); + return null; }; var offsets = []; @@ -320,12 +322,12 @@ var Type2Parser = function(aFilePath) { 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 priv = font.get("Private"); + log("Reading Private Dict (offset: " + priv.offset + " size: " + priv.size + ")"); + aStream.pos = priv.offset; var privateDict = []; - for (var i = 0; i < private.size; i++) + for (var i = 0; i < priv.size; i++) privateDict.push(aStream.getByte()); dump("private:" + privateDict); parseAsToken(privateDict, CFFDictPrivateDataMap); @@ -386,7 +388,7 @@ function writeToFile(aBytes, aFilePath) { var stream = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); - stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0); + stream.init(file, 0x04 | 0x08 | 0x20, 600, 0); var bos = Cc["@mozilla.org/binaryoutputstream;1"] .createInstance(Ci.nsIBinaryOutputStream); From 7eab70532ef299fff7de79a7351f6b0ed013c38c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 24 Jun 2011 23:33:16 +0200 Subject: [PATCH 342/439] Fix some warnings --- utils/fonts_utils.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index de4ceea72..532853460 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -194,6 +194,8 @@ function readFontIndexData(aStream, aIsByte) { return aStream.getByte() << 24 | aStream.getByte() << 16 | aStream.getByte() << 8 | aStream.getByte(); } + error(offsize + " is not a valid offset size"); + return null; }; var offsets = []; @@ -320,12 +322,12 @@ var Type2Parser = function(aFilePath) { 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 priv = font.get("Private"); + log("Reading Private Dict (offset: " + priv.offset + " size: " + priv.size + ")"); + aStream.pos = priv.offset; var privateDict = []; - for (var i = 0; i < private.size; i++) + for (var i = 0; i < priv.size; i++) privateDict.push(aStream.getByte()); dump("private:" + privateDict); parseAsToken(privateDict, CFFDictPrivateDataMap); @@ -386,7 +388,7 @@ function writeToFile(aBytes, aFilePath) { var stream = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); - stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0); + stream.init(file, 0x04 | 0x08 | 0x20, 600, 0); var bos = Cc["@mozilla.org/binaryoutputstream;1"] .createInstance(Ci.nsIBinaryOutputStream); From 9748d2ad4978c9fa69f24aea4c994415d51fb2c5 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 16:14:33 -0700 Subject: [PATCH 343/439] Concurrent browsers sending snapshots asynchronously. --- test/test.py | 19 +++++++++++++---- test/test_slave.html | 50 +++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/test/test.py b/test/test.py index bc30d5f8a..a89aa0a7b 100644 --- a/test/test.py +++ b/test/test.py @@ -69,9 +69,10 @@ class State: eqLog = None class Result: - def __init__(self, snapshot, failure): + def __init__(self, snapshot, failure, page): self.snapshot = snapshot self.failure = failure + self.page = page class TestServer(SocketServer.TCPServer): allow_reuse_address = True @@ -122,10 +123,20 @@ class PDFTestHandler(BaseHTTPRequestHandler): result = json.loads(self.rfile.read(numBytes)) browser, id, failure, round, page, snapshot = result['browser'], result['id'], result['failure'], result['round'], result['page'], result['snapshot'] taskResults = State.taskResults[browser][id] - taskResults[round].append(Result(snapshot, failure)) - assert len(taskResults[round]) == page + taskResults[round].append(Result(snapshot, failure, page)) - if result['taskDone']: + def isTaskDone(): + numPages = result["numPages"] + rounds = State.manifest[id]["rounds"] + for round in range(0,rounds): + if len(taskResults[round]) < numPages: + return False + return True + + if isTaskDone(): + # sort the results since they sometimes come in out of order + for results in taskResults: + results.sort(key=lambda result: result.page) check(State.manifest[id], taskResults, browser) # Please oh please GC this ... del State.taskResults[browser][id] diff --git a/test/test_slave.html b/test/test_slave.html index 1053025e1..03982bbb5 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -139,31 +139,41 @@ function snapshotCurrentPage(gfx) { } } - currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages - && (1 + currentTask.round) == currentTask.rounds); sendTaskResult(canvas.toDataURL("image/png")); log("done"+ (failure ? " (failed!)" : "") +"\n"); - ++currentTask.pageNum, nextPage(); -} - -function done() { - log("Done!\n"); + // Set up the next request + backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0; setTimeout(function() { - document.body.innerHTML = "Tests are finished.

CLOSE ME!

"; - if (window.SpecialPowers) - SpecialPowers.quitApplication(); - else - window.close(); + ++currentTask.pageNum, nextPage(); }, - 100 + backoff ); } +function quitApp() { + log("Done!"); + document.body.innerHTML = "Tests are finished.

CLOSE ME!

"; + if (window.SpecialPowers) + SpecialPowers.quitApplication(); + else + window.close(); +} + +function done() { + if (inFlightRequests > 0) { + document.getElementById("inFlightCount").innerHTML = inFlightRequests; + setTimeout(done, 100); + } else { + setTimeout(quitApp, 100); + } +} + +var inFlightRequests = 0; function sendTaskResult(snapshot) { var result = { browser: browser, id: currentTask.id, - taskDone: currentTask.taskDone, + numPages: pdfDoc.numPages, failure: failure, file: currentTask.file, round: currentTask.round, @@ -172,9 +182,14 @@ function sendTaskResult(snapshot) { var r = new XMLHttpRequest(); // (The POST URI is ignored atm.) - r.open("POST", "/submit_task_results", false); + r.open("POST", "/submit_task_results", true); r.setRequestHeader("Content-Type", "application/json"); - // XXX async + r.onreadystatechange = function(e) { + if (r.readyState == 4) { + inFlightRequests--; + } + } + document.getElementById("inFlightCount").innerHTML = inFlightRequests++; r.send(JSON.stringify(result)); } @@ -194,7 +209,8 @@ function log(str) { -

+  

+  

Inflight requests:

From 185b3e62722a4e5f214ef0b54e1e1d5d43c95fab Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 16:14:33 -0700 Subject: [PATCH 344/439] Concurrent browsers sending snapshots asynchronously. --- test/test.py | 19 +++++++++++++---- test/test_slave.html | 50 +++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/test/test.py b/test/test.py index bc30d5f8a..a89aa0a7b 100644 --- a/test/test.py +++ b/test/test.py @@ -69,9 +69,10 @@ class State: eqLog = None class Result: - def __init__(self, snapshot, failure): + def __init__(self, snapshot, failure, page): self.snapshot = snapshot self.failure = failure + self.page = page class TestServer(SocketServer.TCPServer): allow_reuse_address = True @@ -122,10 +123,20 @@ class PDFTestHandler(BaseHTTPRequestHandler): result = json.loads(self.rfile.read(numBytes)) browser, id, failure, round, page, snapshot = result['browser'], result['id'], result['failure'], result['round'], result['page'], result['snapshot'] taskResults = State.taskResults[browser][id] - taskResults[round].append(Result(snapshot, failure)) - assert len(taskResults[round]) == page + taskResults[round].append(Result(snapshot, failure, page)) - if result['taskDone']: + def isTaskDone(): + numPages = result["numPages"] + rounds = State.manifest[id]["rounds"] + for round in range(0,rounds): + if len(taskResults[round]) < numPages: + return False + return True + + if isTaskDone(): + # sort the results since they sometimes come in out of order + for results in taskResults: + results.sort(key=lambda result: result.page) check(State.manifest[id], taskResults, browser) # Please oh please GC this ... del State.taskResults[browser][id] diff --git a/test/test_slave.html b/test/test_slave.html index 1053025e1..03982bbb5 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -139,31 +139,41 @@ function snapshotCurrentPage(gfx) { } } - currentTask.taskDone = (currentTask.pageNum == pdfDoc.numPages - && (1 + currentTask.round) == currentTask.rounds); sendTaskResult(canvas.toDataURL("image/png")); log("done"+ (failure ? " (failed!)" : "") +"\n"); - ++currentTask.pageNum, nextPage(); -} - -function done() { - log("Done!\n"); + // Set up the next request + backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0; setTimeout(function() { - document.body.innerHTML = "Tests are finished.

CLOSE ME!

"; - if (window.SpecialPowers) - SpecialPowers.quitApplication(); - else - window.close(); + ++currentTask.pageNum, nextPage(); }, - 100 + backoff ); } +function quitApp() { + log("Done!"); + document.body.innerHTML = "Tests are finished.

CLOSE ME!

"; + if (window.SpecialPowers) + SpecialPowers.quitApplication(); + else + window.close(); +} + +function done() { + if (inFlightRequests > 0) { + document.getElementById("inFlightCount").innerHTML = inFlightRequests; + setTimeout(done, 100); + } else { + setTimeout(quitApp, 100); + } +} + +var inFlightRequests = 0; function sendTaskResult(snapshot) { var result = { browser: browser, id: currentTask.id, - taskDone: currentTask.taskDone, + numPages: pdfDoc.numPages, failure: failure, file: currentTask.file, round: currentTask.round, @@ -172,9 +182,14 @@ function sendTaskResult(snapshot) { var r = new XMLHttpRequest(); // (The POST URI is ignored atm.) - r.open("POST", "/submit_task_results", false); + r.open("POST", "/submit_task_results", true); r.setRequestHeader("Content-Type", "application/json"); - // XXX async + r.onreadystatechange = function(e) { + if (r.readyState == 4) { + inFlightRequests--; + } + } + document.getElementById("inFlightCount").innerHTML = inFlightRequests++; r.send(JSON.stringify(result)); } @@ -194,7 +209,8 @@ function log(str) { -

+  

+  

Inflight requests:

From b90869e97f644a7f9fb59ff177eddd87847ca4c2 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 24 Jun 2011 17:11:39 -0700 Subject: [PATCH 345/439] update test_slave for the new font-loading API --- test/test_slave.html | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/test/test_slave.html b/test/test_slave.html index 03982bbb5..08a3804f3 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -88,43 +88,29 @@ function nextPage() { clear(ctx); var fonts = []; - var fontsReady = true; var gfx = new CanvasGraphics(ctx); try { currentPage = pdfDoc.getPage(currentTask.pageNum); currentPage.compile(gfx, fonts); - - // Inspect fonts and translate the missing ones - var count = fonts.length; - for (var i = 0; i < count; ++i) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } } catch(e) { failure = 'compile: '+ e.toString(); } - var checkFontsLoadedIntervalTimer = null; + var fontLoaderTimer = null; function checkFontsLoaded() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) { - return; - } + if (!FontLoader.bind(fonts)) { + fontLoaderTimer = window.setTimeout(checkFontsLoaded, 10); + return; } - window.clearInterval(checkFontsLoadedIntervalTimer); - snapshotCurrentPage(gfx); } - if (failure || fontsReady) { + if (failure) { + // Skip font loading if there was a failure, since the fonts might + // be in an inconsistent state. snapshotCurrentPage(gfx); } else { - checkFontsLoadedIntervalTimer = setInterval(checkFontsLoaded, 10); + checkFontsLoaded(); } } From bfff2ba63f05472e5ea29d6ba031872241a00a7e Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 24 Jun 2011 17:11:39 -0700 Subject: [PATCH 346/439] update test_slave for the new font-loading API --- test/test_slave.html | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/test/test_slave.html b/test/test_slave.html index 03982bbb5..08a3804f3 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -88,43 +88,29 @@ function nextPage() { clear(ctx); var fonts = []; - var fontsReady = true; var gfx = new CanvasGraphics(ctx); try { currentPage = pdfDoc.getPage(currentTask.pageNum); currentPage.compile(gfx, fonts); - - // Inspect fonts and translate the missing ones - var count = fonts.length; - for (var i = 0; i < count; ++i) { - var font = fonts[i]; - if (Fonts[font.name]) { - fontsReady = fontsReady && !Fonts[font.name].loading; - continue; - } - new Font(font.name, font.file, font.properties); - fontsReady = false; - } } catch(e) { failure = 'compile: '+ e.toString(); } - var checkFontsLoadedIntervalTimer = null; + var fontLoaderTimer = null; function checkFontsLoaded() { - for (var i = 0; i < count; i++) { - if (Fonts[font.name].loading) { - return; - } + if (!FontLoader.bind(fonts)) { + fontLoaderTimer = window.setTimeout(checkFontsLoaded, 10); + return; } - window.clearInterval(checkFontsLoadedIntervalTimer); - snapshotCurrentPage(gfx); } - if (failure || fontsReady) { + if (failure) { + // Skip font loading if there was a failure, since the fonts might + // be in an inconsistent state. snapshotCurrentPage(gfx); } else { - checkFontsLoadedIntervalTimer = setInterval(checkFontsLoaded, 10); + checkFontsLoaded(); } } From 0b422b42773a4abe46c23a14525dd94e8480e77d Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 17:13:31 -0700 Subject: [PATCH 347/439] Turn off safe-browsing code in test harness. --- test/resources/firefox/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index 7ca293923..b01e2eb76 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -33,3 +33,4 @@ user_pref("browser.panorama.experienced_first_run", true); // Assume experienced user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); user_pref("extensions.installDistroAddons", false); // prevent testpilot etc +user_pref("browser.safebrowsing.enable", false); // prevent traffic to google servers From 40f67c95731c6c9f5cf45a30adbfb4b23fe83e1c Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 17:13:31 -0700 Subject: [PATCH 348/439] Turn off safe-browsing code in test harness. --- test/resources/firefox/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index 7ca293923..b01e2eb76 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -33,3 +33,4 @@ user_pref("browser.panorama.experienced_first_run", true); // Assume experienced user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); user_pref("extensions.installDistroAddons", false); // prevent testpilot etc +user_pref("browser.safebrowsing.enable", false); // prevent traffic to google servers From 4278660216d1b4d5fbb6869d785b6c50c2c750f8 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 17:58:07 -0700 Subject: [PATCH 349/439] Clean up 404 noise from favicon.ico, send Content-Length with GET responses. --- test/test.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/test.py b/test/test.py index a89aa0a7b..5aece2c24 100644 --- a/test/test.py +++ b/test/test.py @@ -51,6 +51,7 @@ MIMEs = { '.json': 'application/json', '.pdf': 'application/pdf', '.xhtml': 'application/xhtml+xml', + '.ico': 'image/x-icon' } class State: @@ -84,6 +85,14 @@ class PDFTestHandler(BaseHTTPRequestHandler): if VERBOSE: BaseHTTPRequestHandler.log_request(code, size) + def sendFile(self, path, ext): + self.send_response(200) + self.send_header("Content-Type", MIMEs[ext]) + self.send_header("Content-Length", os.path.getsize(path)) + self.end_headers() + with open(path) as f: + self.wfile.write(f.read()) + def do_GET(self): url = urlparse(self.path) # Ignore query string @@ -92,9 +101,14 @@ class PDFTestHandler(BaseHTTPRequestHandler): prefix = os.path.commonprefix(( path, DOC_ROOT )) _, ext = os.path.splitext(path) + if url.path == "/favicon.ico": + self.sendFile(os.path.join(DOC_ROOT, "test", "resources", "favicon.ico"), ext) + return + if not (prefix == DOC_ROOT and os.path.isfile(path) and ext in MIMEs): + print path self.send_error(404) return @@ -103,14 +117,8 @@ class PDFTestHandler(BaseHTTPRequestHandler): self.send_error(501) return - self.send_response(200) - self.send_header("Content-Type", MIMEs[ext]) - self.end_headers() - - # Sigh, os.sendfile() plz - f = open(path) - self.wfile.write(f.read()) - f.close() + self.sendFile(path, ext) + def do_POST(self): From 813b31750a5fbda72110882f3540e5066252bc73 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 17:58:07 -0700 Subject: [PATCH 350/439] Clean up 404 noise from favicon.ico, send Content-Length with GET responses. --- test/test.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/test.py b/test/test.py index a89aa0a7b..5aece2c24 100644 --- a/test/test.py +++ b/test/test.py @@ -51,6 +51,7 @@ MIMEs = { '.json': 'application/json', '.pdf': 'application/pdf', '.xhtml': 'application/xhtml+xml', + '.ico': 'image/x-icon' } class State: @@ -84,6 +85,14 @@ class PDFTestHandler(BaseHTTPRequestHandler): if VERBOSE: BaseHTTPRequestHandler.log_request(code, size) + def sendFile(self, path, ext): + self.send_response(200) + self.send_header("Content-Type", MIMEs[ext]) + self.send_header("Content-Length", os.path.getsize(path)) + self.end_headers() + with open(path) as f: + self.wfile.write(f.read()) + def do_GET(self): url = urlparse(self.path) # Ignore query string @@ -92,9 +101,14 @@ class PDFTestHandler(BaseHTTPRequestHandler): prefix = os.path.commonprefix(( path, DOC_ROOT )) _, ext = os.path.splitext(path) + if url.path == "/favicon.ico": + self.sendFile(os.path.join(DOC_ROOT, "test", "resources", "favicon.ico"), ext) + return + if not (prefix == DOC_ROOT and os.path.isfile(path) and ext in MIMEs): + print path self.send_error(404) return @@ -103,14 +117,8 @@ class PDFTestHandler(BaseHTTPRequestHandler): self.send_error(501) return - self.send_response(200) - self.send_header("Content-Type", MIMEs[ext]) - self.end_headers() - - # Sigh, os.sendfile() plz - f = open(path) - self.wfile.write(f.read()) - f.close() + self.sendFile(path, ext) + def do_POST(self): From 69c1a5497184c875a328e408aeebb2090dcc7868 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sat, 25 Jun 2011 03:48:49 +0200 Subject: [PATCH 351/439] Add a 'scale' url parameter --- viewer.html | 4 ++-- viewer.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/viewer.html b/viewer.html index 6e733319e..7bb06ee35 100644 --- a/viewer.html +++ b/viewer.html @@ -5,6 +5,7 @@ + @@ -25,8 +26,7 @@
- - +
diff --git a/viewer.js b/viewer.js index 2bcff50a6..c7adee892 100644 --- a/viewer.js +++ b/viewer.js @@ -3,11 +3,12 @@ "use strict"; -var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageTimeout; +var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages, pageTimeout; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; - pageNum = parseInt(queryParams().page) || 1; + pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1; + pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5; var fileName = userInput; if (!userInput) { fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; @@ -59,6 +60,8 @@ function displayPage(num) { var t0 = Date.now(); var page = pdfDocument.getPage(pageNum = num); + canvas.width = parseInt(canvas.getAttribute("defaultwidth")) * pageScale; + canvas.height = parseInt(canvas.getAttribute("defaultheight")) * pageScale; var t1 = Date.now(); var ctx = canvas.getContext("2d"); From 1a141cbf17613b9c9b0e9dfab21d01afe22f8002 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sat, 25 Jun 2011 03:48:49 +0200 Subject: [PATCH 352/439] Add a 'scale' url parameter --- viewer.html | 4 ++-- viewer.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/viewer.html b/viewer.html index 6e733319e..7bb06ee35 100644 --- a/viewer.html +++ b/viewer.html @@ -5,6 +5,7 @@ + @@ -25,8 +26,7 @@
- - +
diff --git a/viewer.js b/viewer.js index 2bcff50a6..c7adee892 100644 --- a/viewer.js +++ b/viewer.js @@ -3,11 +3,12 @@ "use strict"; -var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageTimeout; +var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages, pageTimeout; function load(userInput) { canvas = document.getElementById("canvas"); canvas.mozOpaque = true; - pageNum = parseInt(queryParams().page) || 1; + pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1; + pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5; var fileName = userInput; if (!userInput) { fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf"; @@ -59,6 +60,8 @@ function displayPage(num) { var t0 = Date.now(); var page = pdfDocument.getPage(pageNum = num); + canvas.width = parseInt(canvas.getAttribute("defaultwidth")) * pageScale; + canvas.height = parseInt(canvas.getAttribute("defaultheight")) * pageScale; var t1 = Date.now(); var ctx = canvas.getContext("2d"); From 7be264ea88551f8c40163c1b07c733f27fb3c274 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 19:07:42 -0700 Subject: [PATCH 353/439] fully working faxstreams --- pdf.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdf.js b/pdf.js index c90e35bab..341d8fe06 100644 --- a/pdf.js +++ b/pdf.js @@ -4282,6 +4282,11 @@ var CanvasGraphics = (function() { var mask = 1; var b = 0; for (var i = 0, length = 4 * w * h; i < length; i += 4) { + if (i % (4*w) == 0) { + mask = 1; + b = 0; + } + mask >>= 1; if (mask <= 0) { b = imgArray[imgIdx++]; From cde62c85bcb2ccfcc7aa518e81995e77ee26bd9d Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 19:07:42 -0700 Subject: [PATCH 354/439] fully working faxstreams --- pdf.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdf.js b/pdf.js index c90e35bab..341d8fe06 100644 --- a/pdf.js +++ b/pdf.js @@ -4282,6 +4282,11 @@ var CanvasGraphics = (function() { var mask = 1; var b = 0; for (var i = 0, length = 4 * w * h; i < length; i += 4) { + if (i % (4*w) == 0) { + mask = 1; + b = 0; + } + mask >>= 1; if (mask <= 0) { b = imgArray[imgIdx++]; From 6ca1c4cf8346d789d952388602d35c3bdcadbcc7 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 24 Jun 2011 19:23:29 -0700 Subject: [PATCH 355/439] add Intel ISA doc as load test, and make harness resilient to bad PDF loads --- test/pdfs/intelisa.pdf.link | 1 + test/test_manifest.json | 6 ++++++ test/test_slave.html | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/pdfs/intelisa.pdf.link diff --git a/test/pdfs/intelisa.pdf.link b/test/pdfs/intelisa.pdf.link new file mode 100644 index 000000000..371cdf947 --- /dev/null +++ b/test/pdfs/intelisa.pdf.link @@ -0,0 +1 @@ +http://www.intel.com/Assets/PDF/manual/253665.pdf \ No newline at end of file diff --git a/test/test_manifest.json b/test/test_manifest.json index e4a7ada81..9b9d5e333 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -14,6 +14,12 @@ "rounds": 1, "type": "load" }, + { "id": "intelisa-load", + "file": "pdfs/intelisa.pdf", + "link": true, + "rounds": 1, + "type": "load" + }, { "id": "pdfspec-load", "file": "pdfs/pdf.pdf", "link": true, diff --git a/test/test_slave.html b/test/test_slave.html index 08a3804f3..d685eeaf2 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -63,7 +63,14 @@ function nextTask() { if (r.readyState == 4) { var data = r.mozResponseArrayBuffer || r.mozResponse || r.responseArrayBuffer || r.response; - pdfDoc = new PDFDoc(new Stream(data)); + + try { + pdfDoc = new PDFDoc(new Stream(data)); + } catch(e) { + pdfDoc.numPages = 1; + failure = 'load PDF doc: '+ e.toString(); + } + currentTask.pageNum = 1, nextPage(); } }; From 29b7489a3fb0ecf2c28a462bd9ebed871b7b76cd Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 24 Jun 2011 19:23:29 -0700 Subject: [PATCH 356/439] add Intel ISA doc as load test, and make harness resilient to bad PDF loads --- test/pdfs/intelisa.pdf.link | 1 + test/test_manifest.json | 6 ++++++ test/test_slave.html | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/pdfs/intelisa.pdf.link diff --git a/test/pdfs/intelisa.pdf.link b/test/pdfs/intelisa.pdf.link new file mode 100644 index 000000000..371cdf947 --- /dev/null +++ b/test/pdfs/intelisa.pdf.link @@ -0,0 +1 @@ +http://www.intel.com/Assets/PDF/manual/253665.pdf \ No newline at end of file diff --git a/test/test_manifest.json b/test/test_manifest.json index e4a7ada81..9b9d5e333 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -14,6 +14,12 @@ "rounds": 1, "type": "load" }, + { "id": "intelisa-load", + "file": "pdfs/intelisa.pdf", + "link": true, + "rounds": 1, + "type": "load" + }, { "id": "pdfspec-load", "file": "pdfs/pdf.pdf", "link": true, diff --git a/test/test_slave.html b/test/test_slave.html index 08a3804f3..d685eeaf2 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -63,7 +63,14 @@ function nextTask() { if (r.readyState == 4) { var data = r.mozResponseArrayBuffer || r.mozResponse || r.responseArrayBuffer || r.response; - pdfDoc = new PDFDoc(new Stream(data)); + + try { + pdfDoc = new PDFDoc(new Stream(data)); + } catch(e) { + pdfDoc.numPages = 1; + failure = 'load PDF doc: '+ e.toString(); + } + currentTask.pageNum = 1, nextPage(); } }; From d56e6614a383b45a8643ad61b903c44658341357 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 19:25:03 -0700 Subject: [PATCH 357/439] Add favicon.ico file --- test/resources/favicon.ico | Bin 0 -> 1406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/resources/favicon.ico diff --git a/test/resources/favicon.ico b/test/resources/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d44438903b751f4732f5365783eb0229b0501f9a GIT binary patch literal 1406 zcmZvcze^lJ6vy9y;f`fV)+?@Ze|W?Y>#3{^YAe`S+YM=~Z34NW`?g{0%{Gm#-zuW37pASug&9hEW%I5<8GkmQYMp$Ony#e@#BjuEiFmE-c}V zrd^0bcjyk?p*!@r%%gjB&%~p9bOs6N0X?7xgn+KhmAQuGZ0RljmPD3CR#cKborS@| zU}3N@BqSIt3>F3pgM}es!eC*rFjyEY3<(_u3xkEh!eC*riUx;;!$uC(Q~?ymczRl( zp~pvt#bNF+awK)Iq%v^Rap7Qbu%xoU;oxv^I5->}sZ?+{7#s`^hFCfWhl9bv5b#p^ zR6=~ZlX)s{tPWIod!kaQ@%AuzOg#o3CXcu0rYDKV+vAsduroh z@GyAl5Vwu0q^Cz=q>tN34FY}vwg5-KFKun)paubs5IK0TwB0NUumo5F5COyV3cwOr z7zhdo0TzBV@~|fXmJsWaSmN6dcL5Csg+XCZ7!(GDA-zs81Q-+sg(1K|8XEC1C=3dN z!a!;oIt&Vf!k_>s{()r5LM6zN!!dVoXv!U9oUF=cIXF0wqoX4^K0cO{lM^{VKbNz! zGr7FHl<9OTS65eZb8{oNx3_YCe=mzaDxXeI`5%v|Zu}3#fqZEe^Tw%4_Mf9?On&&F zi}beZwkZd!>yBC3w&vx-=SH%5uQV+Iv+k~DdEGL9UJhoPqdUoZxoMl$(3xtsdZBU89L3N8 literal 0 HcmV?d00001 From 3a99b05b794167fceecd550ee5dfa16d5f0311a8 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Fri, 24 Jun 2011 19:25:03 -0700 Subject: [PATCH 358/439] Add favicon.ico file --- test/resources/favicon.ico | Bin 0 -> 1406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/resources/favicon.ico diff --git a/test/resources/favicon.ico b/test/resources/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d44438903b751f4732f5365783eb0229b0501f9a GIT binary patch literal 1406 zcmZvcze^lJ6vy9y;f`fV)+?@Ze|W?Y>#3{^YAe`S+YM=~Z34NW`?g{0%{Gm#-zuW37pASug&9hEW%I5<8GkmQYMp$Ony#e@#BjuEiFmE-c}V zrd^0bcjyk?p*!@r%%gjB&%~p9bOs6N0X?7xgn+KhmAQuGZ0RljmPD3CR#cKborS@| zU}3N@BqSIt3>F3pgM}es!eC*rFjyEY3<(_u3xkEh!eC*riUx;;!$uC(Q~?ymczRl( zp~pvt#bNF+awK)Iq%v^Rap7Qbu%xoU;oxv^I5->}sZ?+{7#s`^hFCfWhl9bv5b#p^ zR6=~ZlX)s{tPWIod!kaQ@%AuzOg#o3CXcu0rYDKV+vAsduroh z@GyAl5Vwu0q^Cz=q>tN34FY}vwg5-KFKun)paubs5IK0TwB0NUumo5F5COyV3cwOr z7zhdo0TzBV@~|fXmJsWaSmN6dcL5Csg+XCZ7!(GDA-zs81Q-+sg(1K|8XEC1C=3dN z!a!;oIt&Vf!k_>s{()r5LM6zN!!dVoXv!U9oUF=cIXF0wqoX4^K0cO{lM^{VKbNz! zGr7FHl<9OTS65eZb8{oNx3_YCe=mzaDxXeI`5%v|Zu}3#fqZEe^Tw%4_Mf9?On&&F zi}beZwkZd!>yBC3w&vx-=SH%5uQV+Iv+k~DdEGL9UJhoPqdUoZxoMl$(3xtsdZBU89L3N8 literal 0 HcmV?d00001 From 4189bb610e90e35c2f21aa53acf27a672283101c Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 19:40:51 -0700 Subject: [PATCH 359/439] Fixed bug, used pixBytes instead of rowBytes --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 48fc8f1ae..a34cd7c42 100644 --- a/pdf.js +++ b/pdf.js @@ -708,7 +708,7 @@ var PredictorStream = (function() { var rawBytes = this.stream.getBytes(rowBytes); var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + pixBytes); + var buffer = this.ensureBuffer(bufferLength + rowBytes); var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); From 86eeedc3976d16adee600de0196dad4239a481d4 Mon Sep 17 00:00:00 2001 From: sbarman Date: Fri, 24 Jun 2011 19:40:51 -0700 Subject: [PATCH 360/439] Fixed bug, used pixBytes instead of rowBytes --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 48fc8f1ae..a34cd7c42 100644 --- a/pdf.js +++ b/pdf.js @@ -708,7 +708,7 @@ var PredictorStream = (function() { var rawBytes = this.stream.getBytes(rowBytes); var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + pixBytes); + var buffer = this.ensureBuffer(bufferLength + rowBytes); var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); From 4326a1d5bf146c75ec16512613cedde09b7b0cf3 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 22:08:33 -0500 Subject: [PATCH 361/439] Fix arcfour initialization and encoding; png prediction fix --- pdf.js | 14 +++++++++----- security.js | 11 +++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pdf.js b/pdf.js index 3ebedd9e1..a4de3d8b2 100644 --- a/pdf.js +++ b/pdf.js @@ -716,7 +716,7 @@ var PredictorStream = (function() { var rawBytes = this.stream.getBytes(rowBytes); var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + pixBytes); + var buffer = this.ensureBuffer(bufferLength + rowBytes); var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); @@ -833,7 +833,7 @@ var DecryptStream = (function() { var buffer = this.ensureBuffer(bufferLength + n); for (i = 0; i < n; i++) buffer[bufferLength++] = chunk[i]; - this.bufferLength = n; + this.bufferLength = bufferLength; this.eof = n < chunkSize; }; @@ -1468,7 +1468,7 @@ var Parser = (function() { stream = stream.makeSubStream(pos, length, dict); if (cipherTransform) - stream = cipherTransform.createString(stream); + stream = cipherTransform.createStream(stream); stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; @@ -1802,7 +1802,11 @@ var XRef = (function() { } error("bad XRef entry"); } - e = parser.getObj(this.encrypt); + if (this.encrypt) { + e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } else { + e = parser.getObj(); + } // Don't cache streams since they are mutable. if (!IsStream(e)) this.cache[num] = e; @@ -2629,7 +2633,7 @@ var CanvasGraphics = (function() { } } } else if (cmd == "Tf") { // eagerly collect all fonts - var fontRes; // = resources.get("Font"); + var fontRes = resources.get("Font"); if (fontRes) { fontRes = xref.fetchIfRef(fontRes); var font = xref.fetchIfRef(fontRes.get(args[0].name)); diff --git a/security.js b/security.js index d6aa8d3b2..14cc21902 100644 --- a/security.js +++ b/security.js @@ -5,7 +5,6 @@ var ARCFourCipher = (function() { function constructor(key) { - var key = this.key; this.a = 0; this.b = 0; var s = new Uint8Array(256); @@ -133,13 +132,13 @@ var CipherTransform = (function() { } constructor.prototype = { createStream: function (stream) { - var cipher = new streamCipherConstructor(); + var cipher = new this.streamCipherConstructor(); return new DecryptStream(stream, function(data) { return cipher.encryptBlock(data); }); }, decryptString: function(s) { - var cipher = new stringCipherConstructor(); + var cipher = new this.stringCipherConstructor(); var data = string2bytes(s); data = cipher.encryptBlock(data); return bytes2string(data); @@ -240,9 +239,9 @@ var CipherTransformFactory = (function() { constructor.prototype = { createCipherTransform: function(num, gen) { var encryptionKey = this.encryptionKey; - var key = new Uint8Array(encryptionKey.length + 5), i, j, n; - for (j = 0, n = encryptionKey.length; j < n; ++j) - key[j] = encryptionKey[j]; + var key = new Uint8Array(encryptionKey.length + 5), i, n; + for (i = 0, n = encryptionKey.length; i < n; ++i) + key[i] = encryptionKey[i]; key[i++] = num & 0xFF; key[i++] = (num >> 8) & 0xFF; key[i++] = (num >> 16) & 0xFF; From 63e74b53e91542a8eebb9e8aace90743edd00690 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 22:08:33 -0500 Subject: [PATCH 362/439] Fix arcfour initialization and encoding; png prediction fix --- pdf.js | 14 +++++++++----- security.js | 11 +++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pdf.js b/pdf.js index 3ebedd9e1..a4de3d8b2 100644 --- a/pdf.js +++ b/pdf.js @@ -716,7 +716,7 @@ var PredictorStream = (function() { var rawBytes = this.stream.getBytes(rowBytes); var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + pixBytes); + var buffer = this.ensureBuffer(bufferLength + rowBytes); var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); @@ -833,7 +833,7 @@ var DecryptStream = (function() { var buffer = this.ensureBuffer(bufferLength + n); for (i = 0; i < n; i++) buffer[bufferLength++] = chunk[i]; - this.bufferLength = n; + this.bufferLength = bufferLength; this.eof = n < chunkSize; }; @@ -1468,7 +1468,7 @@ var Parser = (function() { stream = stream.makeSubStream(pos, length, dict); if (cipherTransform) - stream = cipherTransform.createString(stream); + stream = cipherTransform.createStream(stream); stream = this.filter(stream, dict, length); stream.parameters = dict; return stream; @@ -1802,7 +1802,11 @@ var XRef = (function() { } error("bad XRef entry"); } - e = parser.getObj(this.encrypt); + if (this.encrypt) { + e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } else { + e = parser.getObj(); + } // Don't cache streams since they are mutable. if (!IsStream(e)) this.cache[num] = e; @@ -2629,7 +2633,7 @@ var CanvasGraphics = (function() { } } } else if (cmd == "Tf") { // eagerly collect all fonts - var fontRes; // = resources.get("Font"); + var fontRes = resources.get("Font"); if (fontRes) { fontRes = xref.fetchIfRef(fontRes); var font = xref.fetchIfRef(fontRes.get(args[0].name)); diff --git a/security.js b/security.js index d6aa8d3b2..14cc21902 100644 --- a/security.js +++ b/security.js @@ -5,7 +5,6 @@ var ARCFourCipher = (function() { function constructor(key) { - var key = this.key; this.a = 0; this.b = 0; var s = new Uint8Array(256); @@ -133,13 +132,13 @@ var CipherTransform = (function() { } constructor.prototype = { createStream: function (stream) { - var cipher = new streamCipherConstructor(); + var cipher = new this.streamCipherConstructor(); return new DecryptStream(stream, function(data) { return cipher.encryptBlock(data); }); }, decryptString: function(s) { - var cipher = new stringCipherConstructor(); + var cipher = new this.stringCipherConstructor(); var data = string2bytes(s); data = cipher.encryptBlock(data); return bytes2string(data); @@ -240,9 +239,9 @@ var CipherTransformFactory = (function() { constructor.prototype = { createCipherTransform: function(num, gen) { var encryptionKey = this.encryptionKey; - var key = new Uint8Array(encryptionKey.length + 5), i, j, n; - for (j = 0, n = encryptionKey.length; j < n; ++j) - key[j] = encryptionKey[j]; + var key = new Uint8Array(encryptionKey.length + 5), i, n; + for (i = 0, n = encryptionKey.length; i < n; ++i) + key[i] = encryptionKey[i]; key[i++] = num & 0xFF; key[i++] = (num >> 8) & 0xFF; key[i++] = (num >> 16) & 0xFF; From 159c986e6e6858b87a609af068d65ca5d9f8aefd Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sat, 25 Jun 2011 05:12:35 +0200 Subject: [PATCH 363/439] Add the Type1 subrs into the CFF local subrs index --- fonts.js | 93 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/fonts.js b/fonts.js index c817b12e5..ceacf6388 100644 --- a/fonts.js +++ b/fonts.js @@ -1288,6 +1288,8 @@ CFF.prototype = { "hlineto": 6, "vlineto": 7, "rrcurveto": 8, + "callsubr": 10, + "return": 11, "endchar": 14, "rmoveto": 21, "hmoveto": 22, @@ -1295,7 +1297,7 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function flattenCharstring(charstring, subrs) { + flattenCharstring: function flattenCharstring(charstring) { var i = 0; while (true) { var obj = charstring[i]; @@ -1304,35 +1306,30 @@ CFF.prototype = { if (obj.charAt) { switch (obj) { - case "callsubr": - var subr = subrs[charstring[i - 1]]; - if (subr.length > 1) { - subr = this.flattenCharstring(subr, subrs); - subr.pop(); - charstring.splice(i - 1, 2, subr); - } else { - charstring.splice(i - 1, 2); - } - i -= 1; - break; - case "callothersubr": var index = charstring[i - 1]; var count = charstring[i - 2]; var data = charstring[i - 3]; - // XXX The callothersubr needs to support at least the 3 defaults - // otherSubrs of the spec - if (index != 3) - error("callothersubr for index: " + index + " (" + charstring + ")"); + // If the flex mechanishm is not used in a font program, Adobe + // state that that entries 0, 1 and 2 can simply be replace by + // {}, which means that we can simply ignore them. + if (index < 3) { + i -= 3; + continue; + } - if (!data) { - charstring.splice(i - 2, 4, "pop", 3); - i -= 3; - } else { - // 5 to remove the arguments, the callothersubr call and the pop command - charstring.splice(i - 3, 5, 3); - i -= 3; + // This is the same things about hint replacment, if it is not used + // entry 3 can be replaced by {} + if (index == 3) { + if (!data) { + charstring.splice(i - 2, 4, "pop", 3); + i -= 3; + } else { + // 5 to remove the arguments, the callothersubr call and the pop command + charstring.splice(i - 3, 5, 3); + i -= 3; + } } break; @@ -1343,15 +1340,6 @@ CFF.prototype = { i -= 2; break; - case "pop": - if (i) - charstring.splice(i - 2, 2); - else - charstring.splice(i - 1, 1); - i -= 1; - break; - - case "hsbw": var charWidthVector = charstring[i - 1]; var leftSidebearing = charstring[i - 2]; @@ -1406,7 +1394,7 @@ CFF.prototype = { var glyphsCount = charstrings.length; for (var i = 0; i < glyphsCount; i++) { var charstring = charstrings[i].charstring; - glyphs.push(this.flattenCharstring(charstring.slice(), subrs)); + glyphs.push(this.flattenCharstring(charstring.slice())); } // Create a CFF font data @@ -1511,22 +1499,35 @@ CFF.prototype = { 247, 32, 11, 247, 10, 161, 147, 154, 150, 143, 12, 13, 139, 12, 14, - 28, 0, 55, 19 + 28, 0, 55, 19 // Subrs offset ]); cff.set(privateData, currentOffset); currentOffset += privateData.length; - // Dump shit at the end of the file - var shit = [ - 0x00, 0x01, 0x01, 0x01, - 0x13, 0x5D, 0x65, 0x64, - 0x5E, 0x5B, 0xAF, 0x66, - 0xBA, 0xBB, 0xB1, 0xB0, - 0xB9, 0xBA, 0x65, 0xB2, - 0x5C, 0x1F, 0x0B - ]; - cff.set(shit, currentOffset); - currentOffset += shit.length; + // Local Subrs + var flattenedSubrs = []; + + var bias = 0; + var subrsCount = subrs.length; + if (subrsCount < 1240) + bias = 107; + else if (subrsCount < 33900) + bias = 1131; + else + bias = 32768; + + // Add a bunch of empty subrs to deal with the Type2 bias + for (var i = 0; i < bias; i++) + flattenedSubrs.push([0x0B]); + + for (var i = 0; i < subrsCount; i++) { + var subr = subrs[i]; + flattenedSubrs.push(this.flattenCharstring(subr)); + } + + var subrsData = this.createCFFIndexHeader(flattenedSubrs, true); + cff.set(subrsData, currentOffset); + currentOffset += subrsData.length; var fontData = []; for (var i = 0; i < currentOffset; i++) From 7bc26ba12765742817c3ea810d90bd796230cce2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Sat, 25 Jun 2011 05:12:35 +0200 Subject: [PATCH 364/439] Add the Type1 subrs into the CFF local subrs index --- fonts.js | 93 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/fonts.js b/fonts.js index c817b12e5..ceacf6388 100644 --- a/fonts.js +++ b/fonts.js @@ -1288,6 +1288,8 @@ CFF.prototype = { "hlineto": 6, "vlineto": 7, "rrcurveto": 8, + "callsubr": 10, + "return": 11, "endchar": 14, "rmoveto": 21, "hmoveto": 22, @@ -1295,7 +1297,7 @@ CFF.prototype = { "hvcurveto": 31, }, - flattenCharstring: function flattenCharstring(charstring, subrs) { + flattenCharstring: function flattenCharstring(charstring) { var i = 0; while (true) { var obj = charstring[i]; @@ -1304,35 +1306,30 @@ CFF.prototype = { if (obj.charAt) { switch (obj) { - case "callsubr": - var subr = subrs[charstring[i - 1]]; - if (subr.length > 1) { - subr = this.flattenCharstring(subr, subrs); - subr.pop(); - charstring.splice(i - 1, 2, subr); - } else { - charstring.splice(i - 1, 2); - } - i -= 1; - break; - case "callothersubr": var index = charstring[i - 1]; var count = charstring[i - 2]; var data = charstring[i - 3]; - // XXX The callothersubr needs to support at least the 3 defaults - // otherSubrs of the spec - if (index != 3) - error("callothersubr for index: " + index + " (" + charstring + ")"); + // If the flex mechanishm is not used in a font program, Adobe + // state that that entries 0, 1 and 2 can simply be replace by + // {}, which means that we can simply ignore them. + if (index < 3) { + i -= 3; + continue; + } - if (!data) { - charstring.splice(i - 2, 4, "pop", 3); - i -= 3; - } else { - // 5 to remove the arguments, the callothersubr call and the pop command - charstring.splice(i - 3, 5, 3); - i -= 3; + // This is the same things about hint replacment, if it is not used + // entry 3 can be replaced by {} + if (index == 3) { + if (!data) { + charstring.splice(i - 2, 4, "pop", 3); + i -= 3; + } else { + // 5 to remove the arguments, the callothersubr call and the pop command + charstring.splice(i - 3, 5, 3); + i -= 3; + } } break; @@ -1343,15 +1340,6 @@ CFF.prototype = { i -= 2; break; - case "pop": - if (i) - charstring.splice(i - 2, 2); - else - charstring.splice(i - 1, 1); - i -= 1; - break; - - case "hsbw": var charWidthVector = charstring[i - 1]; var leftSidebearing = charstring[i - 2]; @@ -1406,7 +1394,7 @@ CFF.prototype = { var glyphsCount = charstrings.length; for (var i = 0; i < glyphsCount; i++) { var charstring = charstrings[i].charstring; - glyphs.push(this.flattenCharstring(charstring.slice(), subrs)); + glyphs.push(this.flattenCharstring(charstring.slice())); } // Create a CFF font data @@ -1511,22 +1499,35 @@ CFF.prototype = { 247, 32, 11, 247, 10, 161, 147, 154, 150, 143, 12, 13, 139, 12, 14, - 28, 0, 55, 19 + 28, 0, 55, 19 // Subrs offset ]); cff.set(privateData, currentOffset); currentOffset += privateData.length; - // Dump shit at the end of the file - var shit = [ - 0x00, 0x01, 0x01, 0x01, - 0x13, 0x5D, 0x65, 0x64, - 0x5E, 0x5B, 0xAF, 0x66, - 0xBA, 0xBB, 0xB1, 0xB0, - 0xB9, 0xBA, 0x65, 0xB2, - 0x5C, 0x1F, 0x0B - ]; - cff.set(shit, currentOffset); - currentOffset += shit.length; + // Local Subrs + var flattenedSubrs = []; + + var bias = 0; + var subrsCount = subrs.length; + if (subrsCount < 1240) + bias = 107; + else if (subrsCount < 33900) + bias = 1131; + else + bias = 32768; + + // Add a bunch of empty subrs to deal with the Type2 bias + for (var i = 0; i < bias; i++) + flattenedSubrs.push([0x0B]); + + for (var i = 0; i < subrsCount; i++) { + var subr = subrs[i]; + flattenedSubrs.push(this.flattenCharstring(subr)); + } + + var subrsData = this.createCFFIndexHeader(flattenedSubrs, true); + cff.set(subrsData, currentOffset); + currentOffset += subrsData.length; var fontData = []; for (var i = 0; i < currentOffset; i++) From d68b136ac475efc8fd5588148b8eb7d33f74f3e8 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 22:17:57 -0500 Subject: [PATCH 365/439] security.js -> crypto.js; add ref to the multi-page-viewer --- security.js => crypto.js | 0 multi_page_viewer.html | 1 + viewer.html | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) rename security.js => crypto.js (100%) diff --git a/security.js b/crypto.js similarity index 100% rename from security.js rename to crypto.js diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 47234686d..649e3a7cc 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -6,6 +6,7 @@ + diff --git a/viewer.html b/viewer.html index 4b9dd3cbd..b8e3fffb8 100644 --- a/viewer.html +++ b/viewer.html @@ -6,7 +6,7 @@ - + From 2e1d947ec531aadc0896e48a75e31172d356839d Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Fri, 24 Jun 2011 22:17:57 -0500 Subject: [PATCH 366/439] security.js -> crypto.js; add ref to the multi-page-viewer --- security.js => crypto.js | 0 multi_page_viewer.html | 1 + viewer.html | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) rename security.js => crypto.js (100%) diff --git a/security.js b/crypto.js similarity index 100% rename from security.js rename to crypto.js diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 47234686d..649e3a7cc 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -6,6 +6,7 @@ + diff --git a/viewer.html b/viewer.html index 4b9dd3cbd..b8e3fffb8 100644 --- a/viewer.html +++ b/viewer.html @@ -6,7 +6,7 @@ - + From 2f246236cba86fe9c0a9ff182851b05ef51ecf4b Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 24 Jun 2011 23:27:22 -0400 Subject: [PATCH 367/439] fix issue #78, don't try to use 'in' operator on null --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index a34cd7c42..48fd742b2 100644 --- a/pdf.js +++ b/pdf.js @@ -979,7 +979,7 @@ function IsArray(v) { } function IsStream(v) { - return typeof v == "object" && "getChar" in v; + return typeof v == "object" && v != null && ("getChar" in v); } function IsRef(v) { From 5422182eda9451ba406c4762065aa88da7249bac Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Fri, 24 Jun 2011 23:27:22 -0400 Subject: [PATCH 368/439] fix issue #78, don't try to use 'in' operator on null --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index a34cd7c42..48fd742b2 100644 --- a/pdf.js +++ b/pdf.js @@ -979,7 +979,7 @@ function IsArray(v) { } function IsStream(v) { - return typeof v == "object" && "getChar" in v; + return typeof v == "object" && v != null && ("getChar" in v); } function IsRef(v) { From 9b7ff00f67d706ab63c6d8fbf08c851ab7935427 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Fri, 24 Jun 2011 20:41:47 -0700 Subject: [PATCH 369/439] errors thrown by |get numPages()| were not caught. GETTERS!!! --- test/test_slave.html | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/test_slave.html b/test/test_slave.html index d685eeaf2..32076d075 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -6,7 +6,7 @@ From 6b675d8db69fb2d8c804ffc6c4c185fbe965921c Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sat, 25 Jun 2011 09:42:59 -0700 Subject: [PATCH 386/439] Make the log auto-scroll if the scrollbar is near the bottom, but maintain position if it isn't. --- test/test_slave.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/test_slave.html b/test/test_slave.html index d685eeaf2..5652a5860 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -194,9 +194,17 @@ function clear(ctx) { ctx.restore(); } +/* Auto-scroll if the scrollbar is near the bottom, otherwise do +nothing. */ +function checkScrolling() { + if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) { + stdout.scrollTop = stdout.scrollHeight; + } +} + function log(str) { stdout.innerHTML += str; - window.scrollTo(0, stdout.getBoundingClientRect().bottom); + checkScrolling(); } From d0544a351126d639a0553970696ff1bc82759974 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sat, 25 Jun 2011 09:51:27 -0700 Subject: [PATCH 387/439] Fix whitespace. --- test/test_slave.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_slave.html b/test/test_slave.html index 71ec7cacc..303a58c9b 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -200,8 +200,7 @@ function clear(ctx) { ctx.restore(); } -/* Auto-scroll if the scrollbar is near the bottom, otherwise do -nothing. */ +/* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */ function checkScrolling() { if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) { stdout.scrollTop = stdout.scrollHeight; From cfcac65de4598f4a643e47656cc4ccc98f334adc Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sat, 25 Jun 2011 09:51:27 -0700 Subject: [PATCH 388/439] Fix whitespace. --- test/test_slave.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_slave.html b/test/test_slave.html index 71ec7cacc..303a58c9b 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -200,8 +200,7 @@ function clear(ctx) { ctx.restore(); } -/* Auto-scroll if the scrollbar is near the bottom, otherwise do -nothing. */ +/* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */ function checkScrolling() { if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) { stdout.scrollTop = stdout.scrollHeight; From ee954d8c0aa18e3fe4e765eb0d23cc3cde67103a Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sat, 25 Jun 2011 11:02:35 -0700 Subject: [PATCH 389/439] Still more whitespace fixing. --- test/test_slave.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_slave.html b/test/test_slave.html index 303a58c9b..07ac87388 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -203,7 +203,7 @@ function clear(ctx) { /* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */ function checkScrolling() { if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) { - stdout.scrollTop = stdout.scrollHeight; + stdout.scrollTop = stdout.scrollHeight; } } From fc65ddb7dfff4971e8157fb58b31676bec398bd4 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sat, 25 Jun 2011 11:02:35 -0700 Subject: [PATCH 390/439] Still more whitespace fixing. --- test/test_slave.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_slave.html b/test/test_slave.html index 303a58c9b..07ac87388 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -203,7 +203,7 @@ function clear(ctx) { /* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */ function checkScrolling() { if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) { - stdout.scrollTop = stdout.scrollHeight; + stdout.scrollTop = stdout.scrollHeight; } } From 3f6df90e507d824b43c09905d82c437b7ec18ea8 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 01:05:22 -0400 Subject: [PATCH 391/439] Fixed issue #67: zooming in in the multi-page viewer makes pages disappear. --- multi_page_viewer.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index f262734d3..aeb9ea38f 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -132,10 +132,6 @@ var PDFViewer = { for (i = 1; i <= PDFViewer.numberOfPages; i++) { PDFViewer.createPage(i); } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } } for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { @@ -153,6 +149,12 @@ var PDFViewer = { } PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + + // Clear the array of the last pages drawn to force a redraw. + PDFViewer.lastPagesDrawn = []; + + // Jump the scroll position to the correct page. + PDFViewer.goToPage(PDFViewer.pageNumber); }, goToPage: function(num) { From 745379a1ae89d9514a7c2d30806d681fc6f595c8 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 01:05:22 -0400 Subject: [PATCH 392/439] Fixed issue #67: zooming in in the multi-page viewer makes pages disappear. --- multi_page_viewer.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index f262734d3..aeb9ea38f 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -132,10 +132,6 @@ var PDFViewer = { for (i = 1; i <= PDFViewer.numberOfPages; i++) { PDFViewer.createPage(i); } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } } for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) { @@ -153,6 +149,12 @@ var PDFViewer = { } PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%'; + + // Clear the array of the last pages drawn to force a redraw. + PDFViewer.lastPagesDrawn = []; + + // Jump the scroll position to the correct page. + PDFViewer.goToPage(PDFViewer.pageNumber); }, goToPage: function(num) { From 9c3e2d4626c60019e116bdd248d73e95f530b1b6 Mon Sep 17 00:00:00 2001 From: sbarman Date: Sat, 25 Jun 2011 22:52:41 -0700 Subject: [PATCH 393/439] Removed bpc=1 code --- pdf.js | 61 ++-------------------------------------------------------- 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/pdf.js b/pdf.js index 7f81cbe07..d9adda494 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ "use strict"; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = ERRORS; +var verbosity = WARNINGS; function log(msg) { if (console && console.log) @@ -4273,65 +4273,8 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent == 1) { - var xref = this.xref; - var csStream = dict.get2("ColorSpace", "CS"); - csStream = xref.fetchIfRef(csStream); - if (IsName(csStream) && inline) - csStream = colorSpaces.get(csStream); - var colorSpace = new ColorSpace(xref, csStream); - var numComps = colorSpace.numComps; - if (numComps != 1) - error("worng numComps"); - - ctx.strokeStyle = "#090"; - ctx.strokeRect(0 + 1, -h + 1, w / 2, h -2 ); - - var imgArray = image.getBytes((numComps * w * h) >> 3); - var imgIdx = 0; - - var tmpCanvas = document.createElement("canvas"); - tmpCanvas.width = w; - tmpCanvas.height = h; - var tmpCtx = tmpCanvas.getContext("2d"); - tmpCtx.fillStyle = "#000"; - tmpCtx.fillRect(0, 0, w, h); - var imgData = tmpCtx.getImageData(0, 0, w, h); - var pixels = imgData.data; - - var mask = 1; - var b = 0; - for (var i = 0, length = 4 * w * h; i < length; i += 4) { - if (i % (4*w) == 0) { - mask = 1; - b = 0; - } - - mask >>= 1; - if (mask <= 0) { - b = imgArray[imgIdx++]; - mask = 128; - } - - var p = b & mask; - if (p > 0) - p = 1; - else - p = 0; - pixels[i] = 255 * p; - pixels[i+1] = 255 * p; - pixels[i+2] = 255 * p; - pixels[i+3] = 255; - } - - tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, -h); - this.restore(); - return; - } - if (bitsPerComponent !== 8) - error("Unsupported bpc"); + TODO("Support bpc="+ bitsPerComponent); var xref = this.xref; var colorSpaces = this.colorSpaces; From c2dce23025ecf9a55103011af5d583f9bd36e1d9 Mon Sep 17 00:00:00 2001 From: sbarman Date: Sat, 25 Jun 2011 22:52:41 -0700 Subject: [PATCH 394/439] Removed bpc=1 code --- pdf.js | 61 ++-------------------------------------------------------- 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/pdf.js b/pdf.js index 7f81cbe07..d9adda494 100644 --- a/pdf.js +++ b/pdf.js @@ -4,7 +4,7 @@ "use strict"; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = ERRORS; +var verbosity = WARNINGS; function log(msg) { if (console && console.log) @@ -4273,65 +4273,8 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent == 1) { - var xref = this.xref; - var csStream = dict.get2("ColorSpace", "CS"); - csStream = xref.fetchIfRef(csStream); - if (IsName(csStream) && inline) - csStream = colorSpaces.get(csStream); - var colorSpace = new ColorSpace(xref, csStream); - var numComps = colorSpace.numComps; - if (numComps != 1) - error("worng numComps"); - - ctx.strokeStyle = "#090"; - ctx.strokeRect(0 + 1, -h + 1, w / 2, h -2 ); - - var imgArray = image.getBytes((numComps * w * h) >> 3); - var imgIdx = 0; - - var tmpCanvas = document.createElement("canvas"); - tmpCanvas.width = w; - tmpCanvas.height = h; - var tmpCtx = tmpCanvas.getContext("2d"); - tmpCtx.fillStyle = "#000"; - tmpCtx.fillRect(0, 0, w, h); - var imgData = tmpCtx.getImageData(0, 0, w, h); - var pixels = imgData.data; - - var mask = 1; - var b = 0; - for (var i = 0, length = 4 * w * h; i < length; i += 4) { - if (i % (4*w) == 0) { - mask = 1; - b = 0; - } - - mask >>= 1; - if (mask <= 0) { - b = imgArray[imgIdx++]; - mask = 128; - } - - var p = b & mask; - if (p > 0) - p = 1; - else - p = 0; - pixels[i] = 255 * p; - pixels[i+1] = 255 * p; - pixels[i+2] = 255 * p; - pixels[i+3] = 255; - } - - tmpCtx.putImageData(imgData, 0, 0); - ctx.drawImage(tmpCanvas, 0, -h); - this.restore(); - return; - } - if (bitsPerComponent !== 8) - error("Unsupported bpc"); + TODO("Support bpc="+ bitsPerComponent); var xref = this.xref; var colorSpaces = this.colorSpaces; From fc539ddcb311bf93b41c9be985abfcda872763b7 Mon Sep 17 00:00:00 2001 From: sbarman Date: Sat, 25 Jun 2011 22:56:51 -0700 Subject: [PATCH 395/439] clean up code to before --- pdf.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index d9adda494..db13acfee 100644 --- a/pdf.js +++ b/pdf.js @@ -81,7 +81,7 @@ var Stream = (function() { }, getByte: function stream_getByte() { if (this.pos >= this.end) - return; + return null; return this.bytes[this.pos++]; }, // returns subarray of original buffer @@ -103,12 +103,12 @@ var Stream = (function() { }, lookChar: function stream_lookChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos]); }, getChar: function stream_getChar() { if (this.pos >= this.end) - return ; + return null; return String.fromCharCode(this.bytes[this.pos++]); }, skip: function stream_skip(n) { @@ -171,7 +171,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return this.buffer[this.pos++]; @@ -203,7 +203,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos]); @@ -212,7 +212,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos++]); @@ -4273,8 +4273,11 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) + if (bitsPerComponent !== 8) { TODO("Support bpc="+ bitsPerComponent); + this.restore(); + return; + } var xref = this.xref; var colorSpaces = this.colorSpaces; From d29e666cbfb94a29d9bda05ea3a5bc976135bf8d Mon Sep 17 00:00:00 2001 From: sbarman Date: Sat, 25 Jun 2011 22:56:51 -0700 Subject: [PATCH 396/439] clean up code to before --- pdf.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index d9adda494..db13acfee 100644 --- a/pdf.js +++ b/pdf.js @@ -81,7 +81,7 @@ var Stream = (function() { }, getByte: function stream_getByte() { if (this.pos >= this.end) - return; + return null; return this.bytes[this.pos++]; }, // returns subarray of original buffer @@ -103,12 +103,12 @@ var Stream = (function() { }, lookChar: function stream_lookChar() { if (this.pos >= this.end) - return; + return null; return String.fromCharCode(this.bytes[this.pos]); }, getChar: function stream_getChar() { if (this.pos >= this.end) - return ; + return null; return String.fromCharCode(this.bytes[this.pos++]); }, skip: function stream_skip(n) { @@ -171,7 +171,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return this.buffer[this.pos++]; @@ -203,7 +203,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos]); @@ -212,7 +212,7 @@ var DecodeStream = (function() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return ; + return null; this.readBlock(); } return String.fromCharCode(this.buffer[this.pos++]); @@ -4273,8 +4273,11 @@ var CanvasGraphics = (function() { } } - if (bitsPerComponent !== 8) + if (bitsPerComponent !== 8) { TODO("Support bpc="+ bitsPerComponent); + this.restore(); + return; + } var xref = this.xref; var colorSpaces = this.colorSpaces; From c40333317be0b8e5573e7344e4e448540ddb1720 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 02:14:57 -0400 Subject: [PATCH 397/439] Added experimental slide-out sidebar with page thumbnails. --- multi_page_viewer.css | 41 +++++++++++++++++-- multi_page_viewer.html | 13 +++--- multi_page_viewer.js | 90 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/multi_page_viewer.css b/multi_page_viewer.css index b3eaab792..2eaca4870 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -74,6 +74,20 @@ span { width: 100%; } +.thumbnailPageNumber { + color: #fff; + font-size: 0.55em; + text-align: right; + margin: -6px 2px 6px 0px; + width: 102px; +} + +.thumbnail { + width: 104px; + height: 134px; + margin: 0px auto 10px; +} + .page { width: 816px; height: 1056px; @@ -163,27 +177,46 @@ span { } #sidebar { - background-color: rgba(0, 0, 0, 0.8); position: fixed; - width: 150px; + width: 200px; top: 62px; bottom: 18px; + left: -170px; + transition: left 0.25s ease-in-out 1s; + -moz-transition: left 0.25s ease-in-out 1s; + -webkit-transition: left 0.25s ease-in-out 1s; +} + +#sidebar:hover { + left: 0px; + transition: left 0.25s ease-in-out 0s; + -moz-transition: left 0.25s ease-in-out 0s; + -webkit-transition: left 0.25s ease-in-out 0s; +} + +#sidebarBox { + background-color: rgba(0, 0, 0, 0.7); + width: 150px; + height: 100%; border-top-right-radius: 8px; border-bottom-right-radius: 8px; -moz-border-radius-topright: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-top-right-radius: 8px; -webkit-border-bottom-right-radius: 8px; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #sidebarScrollView { position: absolute; overflow: hidden; overflow-y: auto; - top: 40px; - right: 10px; + top: 10px; bottom: 10px; left: 10px; + width: 130px; } #sidebarContentView { diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 649e3a7cc..e90606a23 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -40,13 +40,16 @@ Open File
- + --> +
+
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index aeb9ea38f..4f2bd5197 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -10,6 +10,8 @@ var PDFViewer = { element: null, + sidebarContentView: null, + previousPageButton: null, nextPageButton: null, pageNumberInput: null, @@ -52,6 +54,78 @@ var PDFViewer = { return pages; }, + createThumbnail: function(num) { + if (PDFViewer.sidebarContentView) { + var anchor = document.createElement('a'); + anchor.href = '#' + num; + + var containerDiv = document.createElement('div'); + containerDiv.id = 'thumbnailContainer' + num; + containerDiv.className = 'thumbnail'; + + var pageNumberDiv = document.createElement('div'); + pageNumberDiv.className = 'thumbnailPageNumber'; + pageNumberDiv.innerHTML = '' + num; + + anchor.appendChild(containerDiv); + PDFViewer.sidebarContentView.appendChild(anchor); + PDFViewer.sidebarContentView.appendChild(pageNumberDiv); + } + }, + + removeThumbnail: function(num) { + var div = document.getElementById('thumbnailContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawThumbnail: function(num) { + if (!PDFViewer.pdf) + return; + + var div = document.getElementById('thumbnailContainer' + num); + + if (div && !div.hasChildNodes()) { + var page = PDFViewer.pdf.getPage(num); + var canvas = document.createElement('canvas'); + + canvas.id = 'thumbnail' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = 104; + canvas.height = 134; + div.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + + var loadFont = function() { + if (!FontLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; + } + page.display(gfx); + } + loadFont(); + } + }, + createPage: function(num) { var anchor = document.createElement('a'); anchor.name = '' + num; @@ -81,11 +155,11 @@ var PDFViewer = { return; var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - + if (div && !div.hasChildNodes()) { var page = PDFViewer.pdf.getPage(num); - + var canvas = document.createElement('canvas'); + canvas.id = 'page' + num; canvas.mozOpaque = true; @@ -130,6 +204,7 @@ var PDFViewer = { if (PDFViewer.pdf) { for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createThumbnail(i); PDFViewer.createPage(i); } } @@ -218,6 +293,13 @@ var PDFViewer = { if (PDFViewer.numberOfPages > 0) { PDFViewer.drawPage(1); document.location.hash = 1; + + setTimeout(function() { + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createThumbnail(i); + PDFViewer.drawThumbnail(i); + } + }, 500); } PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; @@ -242,6 +324,8 @@ window.onload = function() { PDFViewer.element = document.getElementById('viewer'); + PDFViewer.sidebarContentView = document.getElementById('sidebarContentView'); + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); PDFViewer.pageNumberInput.onkeydown = function(evt) { var charCode = evt.charCode || evt.keyCode; From 5fa3ef6c19bb216d265d8c15838fb7a7c47df7ae Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 02:14:57 -0400 Subject: [PATCH 398/439] Added experimental slide-out sidebar with page thumbnails. --- multi_page_viewer.css | 41 +++++++++++++++++-- multi_page_viewer.html | 13 +++--- multi_page_viewer.js | 90 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/multi_page_viewer.css b/multi_page_viewer.css index b3eaab792..2eaca4870 100644 --- a/multi_page_viewer.css +++ b/multi_page_viewer.css @@ -74,6 +74,20 @@ span { width: 100%; } +.thumbnailPageNumber { + color: #fff; + font-size: 0.55em; + text-align: right; + margin: -6px 2px 6px 0px; + width: 102px; +} + +.thumbnail { + width: 104px; + height: 134px; + margin: 0px auto 10px; +} + .page { width: 816px; height: 1056px; @@ -163,27 +177,46 @@ span { } #sidebar { - background-color: rgba(0, 0, 0, 0.8); position: fixed; - width: 150px; + width: 200px; top: 62px; bottom: 18px; + left: -170px; + transition: left 0.25s ease-in-out 1s; + -moz-transition: left 0.25s ease-in-out 1s; + -webkit-transition: left 0.25s ease-in-out 1s; +} + +#sidebar:hover { + left: 0px; + transition: left 0.25s ease-in-out 0s; + -moz-transition: left 0.25s ease-in-out 0s; + -webkit-transition: left 0.25s ease-in-out 0s; +} + +#sidebarBox { + background-color: rgba(0, 0, 0, 0.7); + width: 150px; + height: 100%; border-top-right-radius: 8px; border-bottom-right-radius: 8px; -moz-border-radius-topright: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-top-right-radius: 8px; -webkit-border-bottom-right-radius: 8px; + box-shadow: 0px 2px 8px #000; + -moz-box-shadow: 0px 2px 8px #000; + -webkit-box-shadow: 0px 2px 8px #000; } #sidebarScrollView { position: absolute; overflow: hidden; overflow-y: auto; - top: 40px; - right: 10px; + top: 10px; bottom: 10px; left: 10px; + width: 130px; } #sidebarContentView { diff --git a/multi_page_viewer.html b/multi_page_viewer.html index 649e3a7cc..e90606a23 100644 --- a/multi_page_viewer.html +++ b/multi_page_viewer.html @@ -40,13 +40,16 @@ Open File - + --> + +
diff --git a/multi_page_viewer.js b/multi_page_viewer.js index aeb9ea38f..4f2bd5197 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -10,6 +10,8 @@ var PDFViewer = { element: null, + sidebarContentView: null, + previousPageButton: null, nextPageButton: null, pageNumberInput: null, @@ -52,6 +54,78 @@ var PDFViewer = { return pages; }, + createThumbnail: function(num) { + if (PDFViewer.sidebarContentView) { + var anchor = document.createElement('a'); + anchor.href = '#' + num; + + var containerDiv = document.createElement('div'); + containerDiv.id = 'thumbnailContainer' + num; + containerDiv.className = 'thumbnail'; + + var pageNumberDiv = document.createElement('div'); + pageNumberDiv.className = 'thumbnailPageNumber'; + pageNumberDiv.innerHTML = '' + num; + + anchor.appendChild(containerDiv); + PDFViewer.sidebarContentView.appendChild(anchor); + PDFViewer.sidebarContentView.appendChild(pageNumberDiv); + } + }, + + removeThumbnail: function(num) { + var div = document.getElementById('thumbnailContainer' + num); + + if (div) { + while (div.hasChildNodes()) { + div.removeChild(div.firstChild); + } + } + }, + + drawThumbnail: function(num) { + if (!PDFViewer.pdf) + return; + + var div = document.getElementById('thumbnailContainer' + num); + + if (div && !div.hasChildNodes()) { + var page = PDFViewer.pdf.getPage(num); + var canvas = document.createElement('canvas'); + + canvas.id = 'thumbnail' + num; + canvas.mozOpaque = true; + + // Canvas dimensions must be specified in CSS pixels. CSS pixels + // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. + canvas.width = 104; + canvas.height = 134; + div.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + + var gfx = new CanvasGraphics(ctx); + + // page.compile will collect all fonts for us, once we have loaded them + // we can trigger the actual page rendering with page.display + var fonts = []; + page.compile(gfx, fonts); + + var loadFont = function() { + if (!FontLoader.bind(fonts)) { + pageTimeout = window.setTimeout(loadFont, 10); + return; + } + page.display(gfx); + } + loadFont(); + } + }, + createPage: function(num) { var anchor = document.createElement('a'); anchor.name = '' + num; @@ -81,11 +155,11 @@ var PDFViewer = { return; var div = document.getElementById('pageContainer' + num); - var canvas = document.createElement('canvas'); - + if (div && !div.hasChildNodes()) { var page = PDFViewer.pdf.getPage(num); - + var canvas = document.createElement('canvas'); + canvas.id = 'page' + num; canvas.mozOpaque = true; @@ -130,6 +204,7 @@ var PDFViewer = { if (PDFViewer.pdf) { for (i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createThumbnail(i); PDFViewer.createPage(i); } } @@ -218,6 +293,13 @@ var PDFViewer = { if (PDFViewer.numberOfPages > 0) { PDFViewer.drawPage(1); document.location.hash = 1; + + setTimeout(function() { + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createThumbnail(i); + PDFViewer.drawThumbnail(i); + } + }, 500); } PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; @@ -242,6 +324,8 @@ window.onload = function() { PDFViewer.element = document.getElementById('viewer'); + PDFViewer.sidebarContentView = document.getElementById('sidebarContentView'); + PDFViewer.pageNumberInput = document.getElementById('pageNumber'); PDFViewer.pageNumberInput.onkeydown = function(evt) { var charCode = evt.charCode || evt.keyCode; From d307a90ed4fd9b8e80221cad96952a71ec524deb Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 02:23:18 -0400 Subject: [PATCH 399/439] Minor fix for issues with thumbnails when a new PDF was opened from the local filesystem. --- multi_page_viewer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 4f2bd5197..5a94f12ed 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -282,6 +282,10 @@ var PDFViewer = { PDFViewer.element.removeChild(PDFViewer.element.firstChild); } + while (PDFViewer.sidebarContentView.hasChildNodes()) { + PDFViewer.sidebarContentView.removeChild(PDFViewer.sidebarContentView.firstChild); + } + PDFViewer.pdf = new PDFDoc(new Stream(data)); PDFViewer.numberOfPages = PDFViewer.pdf.numPages; document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); From d33c331e7ff16264ad5ff9898a981041cf45b586 Mon Sep 17 00:00:00 2001 From: Justin D'Arcangelo Date: Sun, 26 Jun 2011 02:23:18 -0400 Subject: [PATCH 400/439] Minor fix for issues with thumbnails when a new PDF was opened from the local filesystem. --- multi_page_viewer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/multi_page_viewer.js b/multi_page_viewer.js index 4f2bd5197..5a94f12ed 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -282,6 +282,10 @@ var PDFViewer = { PDFViewer.element.removeChild(PDFViewer.element.firstChild); } + while (PDFViewer.sidebarContentView.hasChildNodes()) { + PDFViewer.sidebarContentView.removeChild(PDFViewer.sidebarContentView.firstChild); + } + PDFViewer.pdf = new PDFDoc(new Stream(data)); PDFViewer.numberOfPages = PDFViewer.pdf.numPages; document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); From 5d154e04bf5536bccf5bce773b389a7cf64b1a8b Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 26 Jun 2011 09:15:33 -0500 Subject: [PATCH 401/439] Support for multi-size page PDFs --- multi_page_viewer.js | 42 ++++++++++++++++++++++++++-------------- test/pdfs/sizes.pdf | Bin 0 -> 13739 bytes test/test_manifest.json | 5 +++++ test/test_slave.html | 14 +++++++++----- viewer.js | 4 ++++ 5 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 test/pdfs/sizes.pdf diff --git a/multi_page_viewer.js b/multi_page_viewer.js index f262734d3..f46038c9c 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -26,41 +26,53 @@ var PDFViewer = { scale: 1.0, - pageWidth: function() { - return 816 * PDFViewer.scale; + pageWidth: function(page) { + return page.mediaBox[2] * PDFViewer.scale; }, - pageHeight: function() { - return 1056 * PDFViewer.scale; + pageHeight: function(page) { + return page.mediaBox[3] * PDFViewer.scale; }, lastPagesDrawn: [], - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + visiblePages: function() { + const pageBottomMargin = 20; var windowTop = window.pageYOffset; var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pageHeight, page; + var i, n = PDFViewer.numberOfPages, currentHeight = 0; + for (i = 1; i <= n; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + if (currentHeight + pageHeight > windowTop) + break; + currentHeight += pageHeight; + } var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); + for (; i <= n && currentHeight < windowBottom; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + currentHeight += pageHeight; + pages.push(i); } return pages; }, createPage: function(num) { + var page = PDFViewer.pdf.getPage(num); + var anchor = document.createElement('a'); anchor.name = '' + num; var div = document.createElement('div'); div.id = 'pageContainer' + num; div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; + div.style.width = PDFViewer.pageWidth(page) + 'px'; + div.style.height = PDFViewer.pageHeight(page) + 'px'; PDFViewer.element.appendChild(anchor); PDFViewer.element.appendChild(div); @@ -91,8 +103,8 @@ var PDFViewer = { // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); + canvas.width = PDFViewer.pageWidth(page); + canvas.height = PDFViewer.pageHeight(page); div.appendChild(canvas); var ctx = canvas.getContext('2d'); diff --git a/test/pdfs/sizes.pdf b/test/pdfs/sizes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f621f821e9bb28c8b0cf9bdfac9b895d33d23c9e GIT binary patch literal 13739 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 T{2NMOC>Y8CprsX45C{A}>P(JG literal 0 HcmV?d00001 diff --git a/test/test_manifest.json b/test/test_manifest.json index 9b9d5e333..4c5e912f6 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -25,5 +25,10 @@ "link": true, "rounds": 1, "type": "load" + }, + { "id": "sizes", + "file": "pdfs/sizes.pdf", + "rounds": 1, + "type": "eq" } ] diff --git a/test/test_slave.html b/test/test_slave.html index 32076d075..7dfbfeb87 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -25,9 +25,6 @@ function load() { manifestFile = params.manifestFile; canvas = document.createElement("canvas"); - // 8.5x11in @ 100% ... XXX need something better here - canvas.width = 816; - canvas.height = 1056; canvas.mozOpaque = true; stdout = document.getElementById("stdout"); @@ -93,7 +90,6 @@ function nextPage() { log(" loading page "+ currentTask.pageNum +"... "); var ctx = canvas.getContext("2d"); - clear(ctx); var fonts = []; var gfx = null; @@ -105,6 +101,15 @@ function nextPage() { failure = 'compile: '+ e.toString(); } + try { + // using mediaBox for the canvas size + canvas.width = currentPage.mediaBox[2]; + canvas.height = currentPage.mediaBox[3]; + clear(ctx); + } catch(e) { + failure = 'page setup: '+ e.toString(); + } + var fontLoaderTimer = null; function checkFontsLoaded() { try { @@ -193,7 +198,6 @@ function sendTaskResult(snapshot) { } function clear(ctx) { - var ctx = canvas.getContext("2d"); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; ctx.fillRect(0, 0, canvas.width, canvas.height); diff --git a/viewer.js b/viewer.js index c7be739bc..3dffa8144 100644 --- a/viewer.js +++ b/viewer.js @@ -60,6 +60,10 @@ function displayPage(num) { var page = pdfDocument.getPage(pageNum = num); + // scale canvas by 2 + canvas.width = 2 * page.mediaBox[2]; + canvas.hieght = 2 * page.mediaBox[3]; + var t1 = Date.now(); var ctx = canvas.getContext("2d"); ctx.save(); From 8a044058f3c4ec47abf1ce1b2e8e00d76583f412 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 26 Jun 2011 09:15:33 -0500 Subject: [PATCH 402/439] Support for multi-size page PDFs --- multi_page_viewer.js | 42 ++++++++++++++++++++++++++-------------- test/pdfs/sizes.pdf | Bin 0 -> 13739 bytes test/test_manifest.json | 5 +++++ test/test_slave.html | 14 +++++++++----- viewer.js | 4 ++++ 5 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 test/pdfs/sizes.pdf diff --git a/multi_page_viewer.js b/multi_page_viewer.js index f262734d3..f46038c9c 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -26,41 +26,53 @@ var PDFViewer = { scale: 1.0, - pageWidth: function() { - return 816 * PDFViewer.scale; + pageWidth: function(page) { + return page.mediaBox[2] * PDFViewer.scale; }, - pageHeight: function() { - return 1056 * PDFViewer.scale; + pageHeight: function(page) { + return page.mediaBox[3] * PDFViewer.scale; }, lastPagesDrawn: [], - visiblePages: function() { - var pageHeight = PDFViewer.pageHeight() + 20; // Add 20 for the margins. + visiblePages: function() { + const pageBottomMargin = 20; var windowTop = window.pageYOffset; var windowBottom = window.pageYOffset + window.innerHeight; - var pageStartIndex = Math.floor(windowTop / pageHeight); - var pageStopIndex = Math.ceil(windowBottom / pageHeight); + + var pageHeight, page; + var i, n = PDFViewer.numberOfPages, currentHeight = 0; + for (i = 1; i <= n; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + if (currentHeight + pageHeight > windowTop) + break; + currentHeight += pageHeight; + } var pages = []; - - for (var i = pageStartIndex; i <= pageStopIndex; i++) { - pages.push(i + 1); + for (; i <= n && currentHeight < windowBottom; i++) { + var page = PDFViewer.pdf.getPage(i); + pageHeight = PDFViewer.pageHeight(page) + pageBottomMargin; + currentHeight += pageHeight; + pages.push(i); } return pages; }, createPage: function(num) { + var page = PDFViewer.pdf.getPage(num); + var anchor = document.createElement('a'); anchor.name = '' + num; var div = document.createElement('div'); div.id = 'pageContainer' + num; div.className = 'page'; - div.style.width = PDFViewer.pageWidth() + 'px'; - div.style.height = PDFViewer.pageHeight() + 'px'; + div.style.width = PDFViewer.pageWidth(page) + 'px'; + div.style.height = PDFViewer.pageHeight(page) + 'px'; PDFViewer.element.appendChild(anchor); PDFViewer.element.appendChild(div); @@ -91,8 +103,8 @@ var PDFViewer = { // Canvas dimensions must be specified in CSS pixels. CSS pixels // are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi. - canvas.width = PDFViewer.pageWidth(); - canvas.height = PDFViewer.pageHeight(); + canvas.width = PDFViewer.pageWidth(page); + canvas.height = PDFViewer.pageHeight(page); div.appendChild(canvas); var ctx = canvas.getContext('2d'); diff --git a/test/pdfs/sizes.pdf b/test/pdfs/sizes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f621f821e9bb28c8b0cf9bdfac9b895d33d23c9e GIT binary patch literal 13739 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 T{2NMOC>Y8CprsX45C{A}>P(JG literal 0 HcmV?d00001 diff --git a/test/test_manifest.json b/test/test_manifest.json index 9b9d5e333..4c5e912f6 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -25,5 +25,10 @@ "link": true, "rounds": 1, "type": "load" + }, + { "id": "sizes", + "file": "pdfs/sizes.pdf", + "rounds": 1, + "type": "eq" } ] diff --git a/test/test_slave.html b/test/test_slave.html index 32076d075..7dfbfeb87 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -25,9 +25,6 @@ function load() { manifestFile = params.manifestFile; canvas = document.createElement("canvas"); - // 8.5x11in @ 100% ... XXX need something better here - canvas.width = 816; - canvas.height = 1056; canvas.mozOpaque = true; stdout = document.getElementById("stdout"); @@ -93,7 +90,6 @@ function nextPage() { log(" loading page "+ currentTask.pageNum +"... "); var ctx = canvas.getContext("2d"); - clear(ctx); var fonts = []; var gfx = null; @@ -105,6 +101,15 @@ function nextPage() { failure = 'compile: '+ e.toString(); } + try { + // using mediaBox for the canvas size + canvas.width = currentPage.mediaBox[2]; + canvas.height = currentPage.mediaBox[3]; + clear(ctx); + } catch(e) { + failure = 'page setup: '+ e.toString(); + } + var fontLoaderTimer = null; function checkFontsLoaded() { try { @@ -193,7 +198,6 @@ function sendTaskResult(snapshot) { } function clear(ctx) { - var ctx = canvas.getContext("2d"); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; ctx.fillRect(0, 0, canvas.width, canvas.height); diff --git a/viewer.js b/viewer.js index c7be739bc..3dffa8144 100644 --- a/viewer.js +++ b/viewer.js @@ -60,6 +60,10 @@ function displayPage(num) { var page = pdfDocument.getPage(pageNum = num); + // scale canvas by 2 + canvas.width = 2 * page.mediaBox[2]; + canvas.hieght = 2 * page.mediaBox[3]; + var t1 = Date.now(); var ctx = canvas.getContext("2d"); ctx.save(); From 8a369b7876c697bee20c775a80d279545edcb300 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 10:54:57 -0700 Subject: [PATCH 403/439] Add timing information to test harness. --- test/test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test.py b/test/test.py index 5aece2c24..96aeb5cec 100644 --- a/test/test.py +++ b/test/test.py @@ -415,6 +415,7 @@ def processResults(): def main(): + t1 = time.time() optionParser = TestOptions() options, args = optionParser.parse_args() options = optionParser.verifyOptions(options) @@ -434,6 +435,8 @@ def main(): processResults() finally: teardownBrowsers(browsers) + t2 = time.time() + print "Runtime was", int(t2 - t1), "seconds" if __name__ == '__main__': main() From 14da398dee3fa349a4e3190acf85784fc3ef49e3 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 10:54:57 -0700 Subject: [PATCH 404/439] Add timing information to test harness. --- test/test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test.py b/test/test.py index 5aece2c24..96aeb5cec 100644 --- a/test/test.py +++ b/test/test.py @@ -415,6 +415,7 @@ def processResults(): def main(): + t1 = time.time() optionParser = TestOptions() options, args = optionParser.parse_args() options = optionParser.verifyOptions(options) @@ -434,6 +435,8 @@ def main(): processResults() finally: teardownBrowsers(browsers) + t2 = time.time() + print "Runtime was", int(t2 - t1), "seconds" if __name__ == '__main__': main() From 9ca7cbdc7388926c9e697dbb71ac4b446acd6de7 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 10:58:41 -0700 Subject: [PATCH 405/439] Check for browsers in verifyOptions, so the script fails early. --- test/test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test.py b/test/test.py index 96aeb5cec..b867251ee 100644 --- a/test/test.py +++ b/test/test.py @@ -37,6 +37,8 @@ class TestOptions(OptionParser): options.manifestFile = DEFAULT_MANIFEST_FILE if options.browser and options.browserManifestFile: print "Warning: ignoring browser argument since manifest file was also supplied" + if not options.browser and not options.browserManifestFile: + self.error("No test browsers found. Use --browserManifest or --browser args.") return options def prompt(question): @@ -219,10 +221,9 @@ def setUp(options): if options.browserManifestFile: testBrowsers = makeBrowserCommands(options.browserManifestFile) elif options.browser: - testBrowsers = [BrowserCommand({"path":options.browser, "name":"firefox"})] - else: - print "No test browsers found. Use --browserManifest or --browser args." - + testBrowsers = [BrowserCommand({"path":options.browser, "name":"firefox"})] + assert len(testBrowsers) > 0 + with open(options.manifestFile) as mf: manifestList = json.load(mf) From 605535e94e1cd99a57ec5c44caacddbfdb07c55e Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 10:58:41 -0700 Subject: [PATCH 406/439] Check for browsers in verifyOptions, so the script fails early. --- test/test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test.py b/test/test.py index 96aeb5cec..b867251ee 100644 --- a/test/test.py +++ b/test/test.py @@ -37,6 +37,8 @@ class TestOptions(OptionParser): options.manifestFile = DEFAULT_MANIFEST_FILE if options.browser and options.browserManifestFile: print "Warning: ignoring browser argument since manifest file was also supplied" + if not options.browser and not options.browserManifestFile: + self.error("No test browsers found. Use --browserManifest or --browser args.") return options def prompt(question): @@ -219,10 +221,9 @@ def setUp(options): if options.browserManifestFile: testBrowsers = makeBrowserCommands(options.browserManifestFile) elif options.browser: - testBrowsers = [BrowserCommand({"path":options.browser, "name":"firefox"})] - else: - print "No test browsers found. Use --browserManifest or --browser args." - + testBrowsers = [BrowserCommand({"path":options.browser, "name":"firefox"})] + assert len(testBrowsers) > 0 + with open(options.manifestFile) as mf: manifestList = json.load(mf) From 6a2e52c8ab704f6d9dbf4775c222bb133675c80b Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 11:10:32 -0700 Subject: [PATCH 407/439] Suppress telemetry banner. --- test/resources/firefox/user.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index b01e2eb76..c92af9167 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -34,3 +34,5 @@ user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); user_pref("extensions.installDistroAddons", false); // prevent testpilot etc user_pref("browser.safebrowsing.enable", false); // prevent traffic to google servers +user_pref("toolkit.telemetry.prompted", true); // prevent telemetry banner +user_pref("toolkit.telemetry.enabled", false); From d240600296fa3e30c06ac9caac848a7a5c6bb0bd Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 11:10:32 -0700 Subject: [PATCH 408/439] Suppress telemetry banner. --- test/resources/firefox/user.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/resources/firefox/user.js b/test/resources/firefox/user.js index b01e2eb76..c92af9167 100644 --- a/test/resources/firefox/user.js +++ b/test/resources/firefox/user.js @@ -34,3 +34,5 @@ user_pref("dom.w3c_touch_events.enabled", true); user_pref("extensions.checkCompatibility", false); user_pref("extensions.installDistroAddons", false); // prevent testpilot etc user_pref("browser.safebrowsing.enable", false); // prevent traffic to google servers +user_pref("toolkit.telemetry.prompted", true); // prevent telemetry banner +user_pref("toolkit.telemetry.enabled", false); From 4e38f4bc0d18089e706346359921c58e699e5c1b Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 12:05:02 -0700 Subject: [PATCH 409/439] Move downloading code into separate function for readability. --- test/test.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/test/test.py b/test/test.py index b867251ee..c6723ada4 100644 --- a/test/test.py +++ b/test/test.py @@ -204,6 +204,23 @@ def makeBrowserCommands(browserManifestFile): browsers = [BrowserCommand(browser) for browser in json.load(bmf)] return browsers +def downloadLinkedPDFs(manifestList): + for item in manifestList: + f, isLink = item['file'], item.get('link', False) + if isLink and not os.access(f, os.R_OK): + linkFile = open(f +'.link') + link = linkFile.read() + linkFile.close() + + sys.stdout.write('Downloading '+ link +' to '+ f +' ...') + sys.stdout.flush() + response = urllib2.urlopen(link) + + with open(f, 'w') as out: + out.write(response.read()) + + print 'done' + def setUp(options): # Only serve files from a pdf.js clone assert not ANAL or os.path.isfile('../pdf.js') and os.path.isdir('../.git') @@ -227,22 +244,7 @@ def setUp(options): with open(options.manifestFile) as mf: manifestList = json.load(mf) - for item in manifestList: - f, isLink = item['file'], item.get('link', False) - if isLink and not os.access(f, os.R_OK): - linkFile = open(f +'.link') - link = linkFile.read() - linkFile.close() - - sys.stdout.write('Downloading '+ link +' to '+ f +' ...') - sys.stdout.flush() - response = urllib2.urlopen(link) - - out = open(f, 'w') - out.write(response.read()) - out.close() - - print 'done' + downloadLinkedPDFs(manifestList) for b in testBrowsers: State.taskResults[b.name] = { } From 9d7e7ad33a0ec7394f8a9ff10e7546e5673c4181 Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Sun, 26 Jun 2011 12:05:02 -0700 Subject: [PATCH 410/439] Move downloading code into separate function for readability. --- test/test.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/test/test.py b/test/test.py index b867251ee..c6723ada4 100644 --- a/test/test.py +++ b/test/test.py @@ -204,6 +204,23 @@ def makeBrowserCommands(browserManifestFile): browsers = [BrowserCommand(browser) for browser in json.load(bmf)] return browsers +def downloadLinkedPDFs(manifestList): + for item in manifestList: + f, isLink = item['file'], item.get('link', False) + if isLink and not os.access(f, os.R_OK): + linkFile = open(f +'.link') + link = linkFile.read() + linkFile.close() + + sys.stdout.write('Downloading '+ link +' to '+ f +' ...') + sys.stdout.flush() + response = urllib2.urlopen(link) + + with open(f, 'w') as out: + out.write(response.read()) + + print 'done' + def setUp(options): # Only serve files from a pdf.js clone assert not ANAL or os.path.isfile('../pdf.js') and os.path.isdir('../.git') @@ -227,22 +244,7 @@ def setUp(options): with open(options.manifestFile) as mf: manifestList = json.load(mf) - for item in manifestList: - f, isLink = item['file'], item.get('link', False) - if isLink and not os.access(f, os.R_OK): - linkFile = open(f +'.link') - link = linkFile.read() - linkFile.close() - - sys.stdout.write('Downloading '+ link +' to '+ f +' ...') - sys.stdout.flush() - response = urllib2.urlopen(link) - - out = open(f, 'w') - out.write(response.read()) - out.close() - - print 'done' + downloadLinkedPDFs(manifestList) for b in testBrowsers: State.taskResults[b.name] = { } From 1f4fcfbd69d7ecfd0cde4734d1a31f5cddaee31c Mon Sep 17 00:00:00 2001 From: sbarman Date: Sun, 26 Jun 2011 22:54:18 -0700 Subject: [PATCH 411/439] refactored image drawing code --- pdf.js | 322 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 167 insertions(+), 155 deletions(-) diff --git a/pdf.js b/pdf.js index 2f21c95f0..8b8e6ff54 100644 --- a/pdf.js +++ b/pdf.js @@ -4234,23 +4234,11 @@ var CanvasGraphics = (function() { paintImageXObject: function(ref, image, inline) { this.save(); - if (image.getParams) { - // JPX/JPEG2000 streams directly contain bits per component - // and color space mode information. - TODO("get params from actual stream"); - // var bits = ... - // var colorspace = ... - } - // TODO cache rendered images? + var ctx = this.ctx; var dict = image.dict; var w = dict.get2("Width", "W"); var h = dict.get2("Height", "H"); - - if (w < 1 || h < 1) - error("Invalid image width or height"); - - var ctx = this.ctx; // scale the image to the unit square ctx.scale(1/w, -1/h); @@ -4265,154 +4253,15 @@ var CanvasGraphics = (function() { return; } - var interpolate = dict.get2("Interpolate", "I"); - if (!IsBool(interpolate)) - interpolate = false; - var imageMask = dict.get2("ImageMask", "IM"); - if (!IsBool(imageMask)) - imageMask = false; - - var bitsPerComponent = image.bitsPerComponent; - if (!bitsPerComponent) { - bitsPerComponent = dict.get2("BitsPerComponent", "BPC"); - if (!bitsPerComponent) { - if (imageMask) - bitsPerComponent = 1; - else - error("Bits per component missing in image"); - } - } - - if (bitsPerComponent !== 8) { - TODO("Support bpc="+ bitsPerComponent); - this.restore(); - return; - } - - var xref = this.xref; - var colorSpaces = this.colorSpaces; - - if (imageMask) { - error("support image masks"); - } - - // actual image - var csStream = dict.get2("ColorSpace", "CS"); - csStream = xref.fetchIfRef(csStream); - if (IsName(csStream) && inline) - csStream = colorSpaces.get(csStream); - - var colorSpace = new ColorSpace(xref, csStream); - var decode = dict.get2("Decode", "D"); - - TODO("create color map"); - - var mask = image.dict.get("Mask"); - mask = xref.fetchIfRef(mask); - var smask = image.dict.get("SMask"); - smask = xref.fetchIfRef(smask); - - if (IsStream(smask)) { - if (inline) - error("cannot combine smask and inlining"); - - var maskDict = smask.dict; - var maskW = maskDict.get2("Width", "W"); - var maskH = maskDict.get2("Height", "H"); - if (!IsNum(maskW) || !IsNum(maskH) || maskW < 1 || maskH < 1) - error("Invalid image width or height"); - if (maskW !== w || maskH !== h) - error("Invalid image width or height"); - - var maskInterpolate = maskDict.get2("Interpolate", "I"); - if (!IsBool(maskInterpolate)) - maskInterpolate = false; - - var maskBPC = maskDict.get2("BitsPerComponent", "BPC"); - if (!maskBPC) - error("Invalid image mask bpc"); - - var maskCsStream = maskDict.get2("ColorSpace", "CS"); - maskCsStream = xref.fetchIfRef(maskCsStream); - var maskColorSpace = new ColorSpace(xref, maskCsStream); - if (maskColorSpace.mode !== "DeviceGray") - error("Invalid color space for smask"); - - var maskDecode = maskDict.get2("Decode", "D"); - if (maskDecode) - TODO("Handle mask decode"); - // handle matte object - } + var imageObj = new PDFImage(this.xref, this.res, image, inline); var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCtx = tmpCanvas.getContext("2d"); var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; - if (bitsPerComponent != 8) - error("unhandled number of bits per component"); - - if (smask) { - if (maskColorSpace.numComps != 1) - error("Incorrect number of components in smask"); - - var numComps = colorSpace.numComps; - var imgArray = image.getBytes(numComps * w * h); - var imgIdx = 0; - - var smArray = smask.getBytes(w * h); - var smIdx = 0; - - var length = 4 * w * h; - switch (numComps) { - case 1: - for (var i = 0; i < length; i += 4) { - var p = imgArray[imgIdx++]; - pixels[i] = p; - pixels[i+1] = p; - pixels[i+2] = p; - pixels[i+3] = smArray[smIdx++]; - } - break; - case 3: - for (var i = 0; i < length; i += 4) { - pixels[i] = imgArray[imgIdx++]; - pixels[i+1] = imgArray[imgIdx++]; - pixels[i+2] = imgArray[imgIdx++]; - pixels[i+3] = smArray[smIdx++]; - } - break; - default: - TODO("Images with "+ numComps + " components per pixel"); - } - } else { - var numComps = colorSpace.numComps; - var imgArray = image.getBytes(numComps * w * h); - var imgIdx = 0; - - var length = 4 * w * h; - switch (numComps) { - case 1: - for (var i = 0; i < length; i += 4) { - var p = imgArray[imgIdx++]; - pixels[i] = p; - pixels[i+1] = p; - pixels[i+2] = p; - pixels[i+3] = 255; - } - break; - case 3: - for (var i = 0; i < length; i += 4) { - pixels[i] = imgArray[imgIdx++]; - pixels[i+1] = imgArray[imgIdx++]; - pixels[i+2] = imgArray[imgIdx++]; - pixels[i+3] = 255; - } - break; - default: - TODO("Images with "+ numComps + " components per pixel"); - } - } + imageObj.fillRgbaBuffer(pixels); + tmpCtx.putImageData(imgData, 0, 0); ctx.drawImage(tmpCanvas, 0, -h); this.restore(); @@ -4541,6 +4390,169 @@ var ColorSpace = (function() { return constructor; })(); +var PDFImage = (function() { + function constructor(xref, res, image, inline) { + this.image = image; + if (image.getParams) { + // JPX/JPEG2000 streams directly contain bits per component + // and color space mode information. + TODO("get params from actual stream"); + // var bits = ... + // var colorspace = ... + } + // TODO cache rendered images? + + var dict = image.dict; + this.width = dict.get2("Width", "W"); + this.height = dict.get2("Height", "H"); + + if (this.width < 1 || this.height < 1) + error("Invalid image width or height"); + + this.interpolate = dict.get2("Interpolate", "I") || false; + this.imageMask = dict.get2("ImageMask", "IM") || false; + + var bitsPerComponent = image.bitsPerComponent; + if (!bitsPerComponent) { + bitsPerComponent = dict.get2("BitsPerComponent", "BPC"); + if (!bitsPerComponent) { + if (this.imageMask) + bitsPerComponent = 1; + else + error("Bits per component missing in image"); + } + } + this.bpc = bitsPerComponent; + + var colorSpaces = res.get("ColorSpace"); + var csStream = xref.fetchIfRef(dict.get2("ColorSpace", "CS")); + if (IsName(csStream) && inline) + csStream = colorSpaces.get(csStream); + this.colorSpace = new ColorSpace(xref, csStream); + + this.numComps = this.colorSpace.numComps; + this.decode = dict.get2("Decode", "D"); + + var mask = xref.fetchIfRef(image.dict.get("Mask")); + var smask = xref.fetchIfRef(image.dict.get("SMask")); + + if (mask) { + TODO("masked images"); + } else if (smask) { + this.smask = new PDFImage(xref, res, smask); + } + }; + + constructor.prototype = { + getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { + var bufferPos = 0; + if (bpc == 8) { + var getComp = function() { + return buffer[bufferPos++]; + } + } else { + var rowBytes = (width * numComps * bpc + 7) >> 3; + var bits = 0; + var buf = 0; + var getComp = function() { + while (bits < bpc) { + buf = (buf << 8) | buffer[bufferPos++]; + bits += 8; + } + var remainingBits = bits - bpc; + var ret = buf >> remainingBits; + + if (bufferPos % rowBytes == 0) { + buf = 0; + bits = 0; + } else { + buf = buf & ((1 << remainingBits) - 1); + bits = remainingBits; + } + return Math.round(255 * ret / ((1 << bpc) - 1)); + } + } + return getComp; + }, + getOpacityFunction: function getOpacityFunction() { + var smask = this.smask; + if (smask) { + var w = smask.width; + var h = smask.height; + if (w != this.width || h != this.height) + error("smask dimensions do not match image dimensions"); + + var buf = new Uint8Array(w * h); + smask.fillGrayBuffer(buf); + var bufPos = 0; + var opacity = function() { + return buf[bufPos++]; + } + } else { + var opacity = function() { return 255; } + } + return opacity; + }, + fillRgbaBuffer: function fillRgbaBuffer(buffer) { + var numComps = this.numComps; + var width = this.width; + var height = this.height; + var bpc = this.bpc; + + // rows start at byte boundary; + var rowBytes = (width * numComps * bpc + 7) >> 3; + var imgArray = this.image.getBytes(height * rowBytes); + var imgPos = 0; + + var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var getOpacity = this.getOpacityFunction(); + var length = width * height * 4; + + switch (numComps) { + case 1: + for (var i = 0; i < length; i += 4) { + var p = getComp(); + buffer[i] = p; + buffer[i+1] = p; + buffer[i+2] = p; + buffer[i+3] = getOpacity(); + } + break; + case 3: + for (var i = 0; i < length; i += 4) { + buffer[i] = getComp(); + buffer[i+1] = getComp(); + buffer[i+2] = getComp(); + buffer[i+3] = getOpacity(); + } + break; + default: + TODO("Images with "+ numComps + " components per pixel"); + } + }, + fillGrayBuffer: function fillGrayScaleBuffer(buffer) { + var numComps = this.numComps; + if (numComps != 1) + error("Reading gray scale from a color image"); + + var width = this.width; + var height = this.height; + var bpc = this.bpc; + + // rows start at byte boundary; + var rowBytes = (width * numComps * bpc + 7) >> 3; + var imgArray = this.image.getBytes(height * rowBytes); + + var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var length = width * height; + + for (var i = 0; i < length; ++i) + buffer[i] = getComp(); + }, + }; + return constructor; +})(); + var PDFFunction = (function() { function constructor(xref, fn) { var dict = fn.dict; From 11601f30204be73b350d078e18118330613b3dba Mon Sep 17 00:00:00 2001 From: sbarman Date: Sun, 26 Jun 2011 22:54:18 -0700 Subject: [PATCH 412/439] refactored image drawing code --- pdf.js | 322 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 167 insertions(+), 155 deletions(-) diff --git a/pdf.js b/pdf.js index 2f21c95f0..8b8e6ff54 100644 --- a/pdf.js +++ b/pdf.js @@ -4234,23 +4234,11 @@ var CanvasGraphics = (function() { paintImageXObject: function(ref, image, inline) { this.save(); - if (image.getParams) { - // JPX/JPEG2000 streams directly contain bits per component - // and color space mode information. - TODO("get params from actual stream"); - // var bits = ... - // var colorspace = ... - } - // TODO cache rendered images? + var ctx = this.ctx; var dict = image.dict; var w = dict.get2("Width", "W"); var h = dict.get2("Height", "H"); - - if (w < 1 || h < 1) - error("Invalid image width or height"); - - var ctx = this.ctx; // scale the image to the unit square ctx.scale(1/w, -1/h); @@ -4265,154 +4253,15 @@ var CanvasGraphics = (function() { return; } - var interpolate = dict.get2("Interpolate", "I"); - if (!IsBool(interpolate)) - interpolate = false; - var imageMask = dict.get2("ImageMask", "IM"); - if (!IsBool(imageMask)) - imageMask = false; - - var bitsPerComponent = image.bitsPerComponent; - if (!bitsPerComponent) { - bitsPerComponent = dict.get2("BitsPerComponent", "BPC"); - if (!bitsPerComponent) { - if (imageMask) - bitsPerComponent = 1; - else - error("Bits per component missing in image"); - } - } - - if (bitsPerComponent !== 8) { - TODO("Support bpc="+ bitsPerComponent); - this.restore(); - return; - } - - var xref = this.xref; - var colorSpaces = this.colorSpaces; - - if (imageMask) { - error("support image masks"); - } - - // actual image - var csStream = dict.get2("ColorSpace", "CS"); - csStream = xref.fetchIfRef(csStream); - if (IsName(csStream) && inline) - csStream = colorSpaces.get(csStream); - - var colorSpace = new ColorSpace(xref, csStream); - var decode = dict.get2("Decode", "D"); - - TODO("create color map"); - - var mask = image.dict.get("Mask"); - mask = xref.fetchIfRef(mask); - var smask = image.dict.get("SMask"); - smask = xref.fetchIfRef(smask); - - if (IsStream(smask)) { - if (inline) - error("cannot combine smask and inlining"); - - var maskDict = smask.dict; - var maskW = maskDict.get2("Width", "W"); - var maskH = maskDict.get2("Height", "H"); - if (!IsNum(maskW) || !IsNum(maskH) || maskW < 1 || maskH < 1) - error("Invalid image width or height"); - if (maskW !== w || maskH !== h) - error("Invalid image width or height"); - - var maskInterpolate = maskDict.get2("Interpolate", "I"); - if (!IsBool(maskInterpolate)) - maskInterpolate = false; - - var maskBPC = maskDict.get2("BitsPerComponent", "BPC"); - if (!maskBPC) - error("Invalid image mask bpc"); - - var maskCsStream = maskDict.get2("ColorSpace", "CS"); - maskCsStream = xref.fetchIfRef(maskCsStream); - var maskColorSpace = new ColorSpace(xref, maskCsStream); - if (maskColorSpace.mode !== "DeviceGray") - error("Invalid color space for smask"); - - var maskDecode = maskDict.get2("Decode", "D"); - if (maskDecode) - TODO("Handle mask decode"); - // handle matte object - } + var imageObj = new PDFImage(this.xref, this.res, image, inline); var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCtx = tmpCanvas.getContext("2d"); var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; - if (bitsPerComponent != 8) - error("unhandled number of bits per component"); - - if (smask) { - if (maskColorSpace.numComps != 1) - error("Incorrect number of components in smask"); - - var numComps = colorSpace.numComps; - var imgArray = image.getBytes(numComps * w * h); - var imgIdx = 0; - - var smArray = smask.getBytes(w * h); - var smIdx = 0; - - var length = 4 * w * h; - switch (numComps) { - case 1: - for (var i = 0; i < length; i += 4) { - var p = imgArray[imgIdx++]; - pixels[i] = p; - pixels[i+1] = p; - pixels[i+2] = p; - pixels[i+3] = smArray[smIdx++]; - } - break; - case 3: - for (var i = 0; i < length; i += 4) { - pixels[i] = imgArray[imgIdx++]; - pixels[i+1] = imgArray[imgIdx++]; - pixels[i+2] = imgArray[imgIdx++]; - pixels[i+3] = smArray[smIdx++]; - } - break; - default: - TODO("Images with "+ numComps + " components per pixel"); - } - } else { - var numComps = colorSpace.numComps; - var imgArray = image.getBytes(numComps * w * h); - var imgIdx = 0; - - var length = 4 * w * h; - switch (numComps) { - case 1: - for (var i = 0; i < length; i += 4) { - var p = imgArray[imgIdx++]; - pixels[i] = p; - pixels[i+1] = p; - pixels[i+2] = p; - pixels[i+3] = 255; - } - break; - case 3: - for (var i = 0; i < length; i += 4) { - pixels[i] = imgArray[imgIdx++]; - pixels[i+1] = imgArray[imgIdx++]; - pixels[i+2] = imgArray[imgIdx++]; - pixels[i+3] = 255; - } - break; - default: - TODO("Images with "+ numComps + " components per pixel"); - } - } + imageObj.fillRgbaBuffer(pixels); + tmpCtx.putImageData(imgData, 0, 0); ctx.drawImage(tmpCanvas, 0, -h); this.restore(); @@ -4541,6 +4390,169 @@ var ColorSpace = (function() { return constructor; })(); +var PDFImage = (function() { + function constructor(xref, res, image, inline) { + this.image = image; + if (image.getParams) { + // JPX/JPEG2000 streams directly contain bits per component + // and color space mode information. + TODO("get params from actual stream"); + // var bits = ... + // var colorspace = ... + } + // TODO cache rendered images? + + var dict = image.dict; + this.width = dict.get2("Width", "W"); + this.height = dict.get2("Height", "H"); + + if (this.width < 1 || this.height < 1) + error("Invalid image width or height"); + + this.interpolate = dict.get2("Interpolate", "I") || false; + this.imageMask = dict.get2("ImageMask", "IM") || false; + + var bitsPerComponent = image.bitsPerComponent; + if (!bitsPerComponent) { + bitsPerComponent = dict.get2("BitsPerComponent", "BPC"); + if (!bitsPerComponent) { + if (this.imageMask) + bitsPerComponent = 1; + else + error("Bits per component missing in image"); + } + } + this.bpc = bitsPerComponent; + + var colorSpaces = res.get("ColorSpace"); + var csStream = xref.fetchIfRef(dict.get2("ColorSpace", "CS")); + if (IsName(csStream) && inline) + csStream = colorSpaces.get(csStream); + this.colorSpace = new ColorSpace(xref, csStream); + + this.numComps = this.colorSpace.numComps; + this.decode = dict.get2("Decode", "D"); + + var mask = xref.fetchIfRef(image.dict.get("Mask")); + var smask = xref.fetchIfRef(image.dict.get("SMask")); + + if (mask) { + TODO("masked images"); + } else if (smask) { + this.smask = new PDFImage(xref, res, smask); + } + }; + + constructor.prototype = { + getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { + var bufferPos = 0; + if (bpc == 8) { + var getComp = function() { + return buffer[bufferPos++]; + } + } else { + var rowBytes = (width * numComps * bpc + 7) >> 3; + var bits = 0; + var buf = 0; + var getComp = function() { + while (bits < bpc) { + buf = (buf << 8) | buffer[bufferPos++]; + bits += 8; + } + var remainingBits = bits - bpc; + var ret = buf >> remainingBits; + + if (bufferPos % rowBytes == 0) { + buf = 0; + bits = 0; + } else { + buf = buf & ((1 << remainingBits) - 1); + bits = remainingBits; + } + return Math.round(255 * ret / ((1 << bpc) - 1)); + } + } + return getComp; + }, + getOpacityFunction: function getOpacityFunction() { + var smask = this.smask; + if (smask) { + var w = smask.width; + var h = smask.height; + if (w != this.width || h != this.height) + error("smask dimensions do not match image dimensions"); + + var buf = new Uint8Array(w * h); + smask.fillGrayBuffer(buf); + var bufPos = 0; + var opacity = function() { + return buf[bufPos++]; + } + } else { + var opacity = function() { return 255; } + } + return opacity; + }, + fillRgbaBuffer: function fillRgbaBuffer(buffer) { + var numComps = this.numComps; + var width = this.width; + var height = this.height; + var bpc = this.bpc; + + // rows start at byte boundary; + var rowBytes = (width * numComps * bpc + 7) >> 3; + var imgArray = this.image.getBytes(height * rowBytes); + var imgPos = 0; + + var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var getOpacity = this.getOpacityFunction(); + var length = width * height * 4; + + switch (numComps) { + case 1: + for (var i = 0; i < length; i += 4) { + var p = getComp(); + buffer[i] = p; + buffer[i+1] = p; + buffer[i+2] = p; + buffer[i+3] = getOpacity(); + } + break; + case 3: + for (var i = 0; i < length; i += 4) { + buffer[i] = getComp(); + buffer[i+1] = getComp(); + buffer[i+2] = getComp(); + buffer[i+3] = getOpacity(); + } + break; + default: + TODO("Images with "+ numComps + " components per pixel"); + } + }, + fillGrayBuffer: function fillGrayScaleBuffer(buffer) { + var numComps = this.numComps; + if (numComps != 1) + error("Reading gray scale from a color image"); + + var width = this.width; + var height = this.height; + var bpc = this.bpc; + + // rows start at byte boundary; + var rowBytes = (width * numComps * bpc + 7) >> 3; + var imgArray = this.image.getBytes(height * rowBytes); + + var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var length = width * height; + + for (var i = 0; i < length; ++i) + buffer[i] = getComp(); + }, + }; + return constructor; +})(); + var PDFFunction = (function() { function constructor(xref, fn) { var dict = fn.dict; From 2fdb20062659b06baad531b4708ad0afc759f92e Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 09:58:02 -0700 Subject: [PATCH 413/439] working version of PDFImage --- pdf.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 8b8e6ff54..542c0d48a 100644 --- a/pdf.js +++ b/pdf.js @@ -4446,14 +4446,39 @@ var PDFImage = (function() { constructor.prototype = { getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { var bufferPos = 0; - if (bpc == 8) { + if (bpc == 1) { + var rowComps = width * numComps; + var curComp = 0; + var mask = 0; + var buf = 0; + + var getComp = function() { + if (mask <= 0) { + buf = buffer[bufferPos++]; + mask = 128; + } + + var ret = buf & mask; + curComp++; + + if (curComp % rowComps == 0) { + mask = 0; + buf = 0; + } else { + mask >>= 1; + } + return ret * 255; + } + } else if (bpc == 8) { var getComp = function() { return buffer[bufferPos++]; } } else { - var rowBytes = (width * numComps * bpc + 7) >> 3; + var rowComps = width * numComps; + var curComp = 0; var bits = 0; var buf = 0; + var getComp = function() { while (bits < bpc) { buf = (buf << 8) | buffer[bufferPos++]; @@ -4461,8 +4486,9 @@ var PDFImage = (function() { } var remainingBits = bits - bpc; var ret = buf >> remainingBits; + curComp++; - if (bufferPos % rowBytes == 0) { + if (curComp % rowComps == 0) { buf = 0; bits = 0; } else { From 683bc1942720c80e9d47788c5217bc7b746436dd Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 09:58:02 -0700 Subject: [PATCH 414/439] working version of PDFImage --- pdf.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 8b8e6ff54..542c0d48a 100644 --- a/pdf.js +++ b/pdf.js @@ -4446,14 +4446,39 @@ var PDFImage = (function() { constructor.prototype = { getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { var bufferPos = 0; - if (bpc == 8) { + if (bpc == 1) { + var rowComps = width * numComps; + var curComp = 0; + var mask = 0; + var buf = 0; + + var getComp = function() { + if (mask <= 0) { + buf = buffer[bufferPos++]; + mask = 128; + } + + var ret = buf & mask; + curComp++; + + if (curComp % rowComps == 0) { + mask = 0; + buf = 0; + } else { + mask >>= 1; + } + return ret * 255; + } + } else if (bpc == 8) { var getComp = function() { return buffer[bufferPos++]; } } else { - var rowBytes = (width * numComps * bpc + 7) >> 3; + var rowComps = width * numComps; + var curComp = 0; var bits = 0; var buf = 0; + var getComp = function() { while (bits < bpc) { buf = (buf << 8) | buffer[bufferPos++]; @@ -4461,8 +4486,9 @@ var PDFImage = (function() { } var remainingBits = bits - bpc; var ret = buf >> remainingBits; + curComp++; - if (bufferPos % rowBytes == 0) { + if (curComp % rowComps == 0) { buf = 0; bits = 0; } else { From c4d50b7677f78a628611c1532cc7162935da44aa Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 10:38:10 -0700 Subject: [PATCH 415/439] reasonably fast for black and white images --- pdf.js | 97 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/pdf.js b/pdf.js index 542c0d48a..0c6f12b50 100644 --- a/pdf.js +++ b/pdf.js @@ -4444,80 +4444,87 @@ var PDFImage = (function() { }; constructor.prototype = { - getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { + getComponents: function getComponents(buffer) { + var bpc = this.bpc; + if (bpc == 8) + return buffer; + + var width = this.width; + var height = this.height; + var numComps = this.numComps; + + var length = width * height; var bufferPos = 0; + var output = new Uint8Array(length); + if (bpc == 1) { var rowComps = width * numComps; - var curComp = 0; var mask = 0; var buf = 0; - var getComp = function() { - if (mask <= 0) { - buf = buffer[bufferPos++]; - mask = 128; - } - - var ret = buf & mask; - curComp++; - - if (curComp % rowComps == 0) { + for (var i = 0, ii = length; i < ii; ++i) { + if (i % rowComps == 0) { mask = 0; buf = 0; } else { mask >>= 1; } - return ret * 255; - } - } else if (bpc == 8) { - var getComp = function() { - return buffer[bufferPos++]; + + if (mask <= 0) { + buf = buffer[bufferPos++]; + mask = 128; + } + + var t = buf & mask; + if (t == 0) + output[i] = 0; + else + output[i] = 255; } } else { var rowComps = width * numComps; - var curComp = 0; var bits = 0; var buf = 0; - var getComp = function() { + for (var i = 0, ii = length; i < ii; ++i) { while (bits < bpc) { buf = (buf << 8) | buffer[bufferPos++]; bits += 8; } var remainingBits = bits - bpc; var ret = buf >> remainingBits; - curComp++; - if (curComp % rowComps == 0) { + if (i % rowComps == 0) { buf = 0; bits = 0; } else { buf = buf & ((1 << remainingBits) - 1); bits = remainingBits; } - return Math.round(255 * ret / ((1 << bpc) - 1)); + output[i] = Math.round(255 * ret / ((1 << bpc) - 1)); } } - return getComp; + return output; }, - getOpacityFunction: function getOpacityFunction() { + getOpacity: function getOpacity() { var smask = this.smask; + var width = this.width; + var height = this.height; + var buf = new Uint8Array(width * height); + if (smask) { - var w = smask.width; - var h = smask.height; - if (w != this.width || h != this.height) + var sw = smask.width; + var sh = smask.height; + if (sw != this.width || sh != this.height) error("smask dimensions do not match image dimensions"); - var buf = new Uint8Array(w * h); smask.fillGrayBuffer(buf); - var bufPos = 0; - var opacity = function() { - return buf[bufPos++]; - } + return buf; } else { - var opacity = function() { return 255; } + for (var i = 0, ii = width * height; i < ii; ++i) + buf[i] = 255; } - return opacity; + return buf; }, fillRgbaBuffer: function fillRgbaBuffer(buffer) { var numComps = this.numComps; @@ -4530,26 +4537,28 @@ var PDFImage = (function() { var imgArray = this.image.getBytes(height * rowBytes); var imgPos = 0; - var getComp = this.getCompFunction(bpc, width, numComps, imgArray) - var getOpacity = this.getOpacityFunction(); + var comps = this.getComponents(imgArray); + var compsPos = 0; + var opacity = this.getOpacity(); + var opacityPos = 0; var length = width * height * 4; switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = getComp(); + var p = comps[compsPos++]; buffer[i] = p; buffer[i+1] = p; buffer[i+2] = p; - buffer[i+3] = getOpacity(); + buffer[i+3] = opacity[opacityPos++]; } break; case 3: for (var i = 0; i < length; i += 4) { - buffer[i] = getComp(); - buffer[i+1] = getComp(); - buffer[i+2] = getComp(); - buffer[i+3] = getOpacity(); + buffer[i] = comps[compsPos++]; + buffer[i+1] = comps[compsPos++]; + buffer[i+2] = comps[compsPos++]; + buffer[i+3] = opacity[opacityPos++]; } break; default: @@ -4569,11 +4578,11 @@ var PDFImage = (function() { var rowBytes = (width * numComps * bpc + 7) >> 3; var imgArray = this.image.getBytes(height * rowBytes); - var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var comps = this.getComponents(imgArray); var length = width * height; for (var i = 0; i < length; ++i) - buffer[i] = getComp(); + buffer[i] = comps[i]; }, }; return constructor; From 8bf3a9d1b7baecc90611a540ca0149bed2adb859 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 10:38:10 -0700 Subject: [PATCH 416/439] reasonably fast for black and white images --- pdf.js | 97 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/pdf.js b/pdf.js index 542c0d48a..0c6f12b50 100644 --- a/pdf.js +++ b/pdf.js @@ -4444,80 +4444,87 @@ var PDFImage = (function() { }; constructor.prototype = { - getCompFunction: function getCompFunction(bpc, width, numComps, buffer) { + getComponents: function getComponents(buffer) { + var bpc = this.bpc; + if (bpc == 8) + return buffer; + + var width = this.width; + var height = this.height; + var numComps = this.numComps; + + var length = width * height; var bufferPos = 0; + var output = new Uint8Array(length); + if (bpc == 1) { var rowComps = width * numComps; - var curComp = 0; var mask = 0; var buf = 0; - var getComp = function() { - if (mask <= 0) { - buf = buffer[bufferPos++]; - mask = 128; - } - - var ret = buf & mask; - curComp++; - - if (curComp % rowComps == 0) { + for (var i = 0, ii = length; i < ii; ++i) { + if (i % rowComps == 0) { mask = 0; buf = 0; } else { mask >>= 1; } - return ret * 255; - } - } else if (bpc == 8) { - var getComp = function() { - return buffer[bufferPos++]; + + if (mask <= 0) { + buf = buffer[bufferPos++]; + mask = 128; + } + + var t = buf & mask; + if (t == 0) + output[i] = 0; + else + output[i] = 255; } } else { var rowComps = width * numComps; - var curComp = 0; var bits = 0; var buf = 0; - var getComp = function() { + for (var i = 0, ii = length; i < ii; ++i) { while (bits < bpc) { buf = (buf << 8) | buffer[bufferPos++]; bits += 8; } var remainingBits = bits - bpc; var ret = buf >> remainingBits; - curComp++; - if (curComp % rowComps == 0) { + if (i % rowComps == 0) { buf = 0; bits = 0; } else { buf = buf & ((1 << remainingBits) - 1); bits = remainingBits; } - return Math.round(255 * ret / ((1 << bpc) - 1)); + output[i] = Math.round(255 * ret / ((1 << bpc) - 1)); } } - return getComp; + return output; }, - getOpacityFunction: function getOpacityFunction() { + getOpacity: function getOpacity() { var smask = this.smask; + var width = this.width; + var height = this.height; + var buf = new Uint8Array(width * height); + if (smask) { - var w = smask.width; - var h = smask.height; - if (w != this.width || h != this.height) + var sw = smask.width; + var sh = smask.height; + if (sw != this.width || sh != this.height) error("smask dimensions do not match image dimensions"); - var buf = new Uint8Array(w * h); smask.fillGrayBuffer(buf); - var bufPos = 0; - var opacity = function() { - return buf[bufPos++]; - } + return buf; } else { - var opacity = function() { return 255; } + for (var i = 0, ii = width * height; i < ii; ++i) + buf[i] = 255; } - return opacity; + return buf; }, fillRgbaBuffer: function fillRgbaBuffer(buffer) { var numComps = this.numComps; @@ -4530,26 +4537,28 @@ var PDFImage = (function() { var imgArray = this.image.getBytes(height * rowBytes); var imgPos = 0; - var getComp = this.getCompFunction(bpc, width, numComps, imgArray) - var getOpacity = this.getOpacityFunction(); + var comps = this.getComponents(imgArray); + var compsPos = 0; + var opacity = this.getOpacity(); + var opacityPos = 0; var length = width * height * 4; switch (numComps) { case 1: for (var i = 0; i < length; i += 4) { - var p = getComp(); + var p = comps[compsPos++]; buffer[i] = p; buffer[i+1] = p; buffer[i+2] = p; - buffer[i+3] = getOpacity(); + buffer[i+3] = opacity[opacityPos++]; } break; case 3: for (var i = 0; i < length; i += 4) { - buffer[i] = getComp(); - buffer[i+1] = getComp(); - buffer[i+2] = getComp(); - buffer[i+3] = getOpacity(); + buffer[i] = comps[compsPos++]; + buffer[i+1] = comps[compsPos++]; + buffer[i+2] = comps[compsPos++]; + buffer[i+3] = opacity[opacityPos++]; } break; default: @@ -4569,11 +4578,11 @@ var PDFImage = (function() { var rowBytes = (width * numComps * bpc + 7) >> 3; var imgArray = this.image.getBytes(height * rowBytes); - var getComp = this.getCompFunction(bpc, width, numComps, imgArray) + var comps = this.getComponents(imgArray); var length = width * height; for (var i = 0; i < length; ++i) - buffer[i] = getComp(); + buffer[i] = comps[i]; }, }; return constructor; From 51f3961fa2e89d51e57a626ff088582c7064f9c7 Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 10:51:13 -0700 Subject: [PATCH 417/439] clean up --- pdf.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 0c6f12b50..43514ebf0 100644 --- a/pdf.js +++ b/pdf.js @@ -4535,7 +4535,6 @@ var PDFImage = (function() { // rows start at byte boundary; var rowBytes = (width * numComps * bpc + 7) >> 3; var imgArray = this.image.getBytes(height * rowBytes); - var imgPos = 0; var comps = this.getComponents(imgArray); var compsPos = 0; @@ -4565,7 +4564,7 @@ var PDFImage = (function() { TODO("Images with "+ numComps + " components per pixel"); } }, - fillGrayBuffer: function fillGrayScaleBuffer(buffer) { + fillGrayBuffer: function fillGrayBuffer(buffer) { var numComps = this.numComps; if (numComps != 1) error("Reading gray scale from a color image"); From 8a812e2ec987dea407c305744252b6ae11876f1c Mon Sep 17 00:00:00 2001 From: sbarman Date: Mon, 27 Jun 2011 10:51:13 -0700 Subject: [PATCH 418/439] clean up --- pdf.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 0c6f12b50..43514ebf0 100644 --- a/pdf.js +++ b/pdf.js @@ -4535,7 +4535,6 @@ var PDFImage = (function() { // rows start at byte boundary; var rowBytes = (width * numComps * bpc + 7) >> 3; var imgArray = this.image.getBytes(height * rowBytes); - var imgPos = 0; var comps = this.getComponents(imgArray); var compsPos = 0; @@ -4565,7 +4564,7 @@ var PDFImage = (function() { TODO("Images with "+ numComps + " components per pixel"); } }, - fillGrayBuffer: function fillGrayScaleBuffer(buffer) { + fillGrayBuffer: function fillGrayBuffer(buffer) { var numComps = this.numComps; if (numComps != 1) error("Reading gray scale from a color image"); From 5c5688d494e7ce6c2c0b5b6fb671c8c769f3483e Mon Sep 17 00:00:00 2001 From: Rob Sayre Date: Mon, 27 Jun 2011 12:35:48 -0700 Subject: [PATCH 419/439] Add reftest-analyzer.xhtml --- test/resources/reftest-analyzer.xhtml | 588 ++++++++++++++++++++++++++ 1 file changed, 588 insertions(+) create mode 100644 test/resources/reftest-analyzer.xhtml diff --git a/test/resources/reftest-analyzer.xhtml b/test/resources/reftest-analyzer.xhtml new file mode 100644 index 000000000..c59f5b899 --- /dev/null +++ b/test/resources/reftest-analyzer.xhtml @@ -0,0 +1,588 @@ + + + + + + + Reftest analyzer + + + + + + +
+ +

Reftest analyzer: load reftest log

+ +

Either paste your log into this textarea:
+