diff --git a/fonts.js b/fonts.js index 80651d224..9d8a9e806 100644 --- a/fonts.js +++ b/fonts.js @@ -34,65 +34,89 @@ var kDisableFonts = false; * http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65 */ -var kScalePrecision = 40; -var Fonts = { - _active: null, +var Fonts = (function () { + var kScalePrecision = 40; + var fonts = Object.create(null); + var ctx = document.createElement("canvas").getContext("2d"); + ctx.scale(1 / kScalePrecision, 1); - get active() { - return this._active; - }, + function Font(name, data, properties) { + this.name = name; + this.data = data; + this.properties = properties; + this.loading = true; + this.charsCache = Object.create(null); + this.sizes = []; + } - setActive: function fonts_setActive(name, size) { - this._active = this[name]; - this.ctx.font = (size * kScalePrecision) + 'px "' + name + '"'; - }, + var current; + var charsCache; + var measureCache; - charsToUnicode: function fonts_chars2Unicode(chars) { - var active = this._active; - if (!active) - return chars; + return { + registerFont: function fonts_registerFont(fontName, data, properties) { + fonts[fontName] = new Font(fontName, data, properties); + }, + blacklistFont: function fonts_blacklistFont(fontName) { + registerFont(fontName, null, {}); + markLoaded(fontName); + }, + lookup: function fonts_lookup(fontName) { + return fonts[fontName]; + }, + setActive: function fonts_setActive(fontName, size) { + current = fonts[fontName]; + charsCache = current.charsCache; + var sizes = current.sizes; + if (!(measureCache = sizes[size])) + measureCache = sizes[size] = Object.create(null); + ctx.font = (size * kScalePrecision) + 'px "' + fontName + '"'; + }, + charsToUnicode: function fonts_chars2Unicode(chars) { + if (!charsCache) + return chars; - // if we translated this string before, just grab it from the cache - var str = active.cache[chars]; - if (str) - return str; + // if we translated this string before, just grab it from the cache + var str = charsCache[chars]; + if (str) + return str; - // translate the string using the font's encoding - var encoding = active.properties.encoding; - if (!encoding) - return chars; + // translate the string using the font's encoding + var encoding = current.properties.encoding; + if (!encoding) + return chars; - str = ""; - for (var i = 0; i < chars.length; ++i) { - var charcode = chars.charCodeAt(i); - var unicode = encoding[charcode]; + str = ""; + for (var i = 0; i < chars.length; ++i) { + var charcode = chars.charCodeAt(i); + var unicode = encoding[charcode]; - // Check if the glyph has already been converted - if (!IsNum(unicode)) + // Check if the glyph has already been converted + if (!IsNum(unicode)) unicode = encoding[unicode] = GlyphsUnicode[unicode.name]; - // Handle surrogate pairs - if (unicode > 0xFFFF) { - str += String.fromCharCode(unicode & 0xFFFF); - unicode >>= 16; + // Handle surrogate pairs + if (unicode > 0xFFFF) { + str += String.fromCharCode(unicode & 0xFFFF); + unicode >>= 16; + } + str += String.fromCharCode(unicode); } - str += String.fromCharCode(unicode); + + // Enter the translated string into the cache + return charsCache[chars] = str; + }, + measureText: function fonts_measureText(text) { + var width; + if (measureCache && (width = measureCache[text])) + return width; + width = ctx.measureText(text).width / kScalePrecision; + if (measureCache) + measureCache[text] = width; + return width; } - - // Enter the translated string into the cache - return active.cache[chars] = str; - }, - - get ctx() { - var ctx = document.createElement("canvas").getContext("2d"); - ctx.scale(1 / kScalePrecision, 1); - return shadow(this, "ctx", ctx); - }, - - measureText: function fonts_measureText(text) { - return this.ctx.measureText(text).width / kScalePrecision; } -}; +})(); var FontLoader = { bind: function(fonts, callback) { @@ -101,7 +125,7 @@ var FontLoader = { function checkFontsLoaded() { for (var i = 0; i < fonts.length; i++) { var font = fonts[i]; - if (Fonts[font.name].loading) { + if (Fonts.lookup(font.name).loading) { return false; } } @@ -115,11 +139,11 @@ var FontLoader = { for (var i = 0; i < fonts.length; i++) { var font = fonts[i]; - if (!Fonts[font.name]) { + if (!Fonts.lookup(font.name)) { var obj = new Font(font.name, font.file, font.properties); var str = ""; - var data = Fonts[font.name].data; + var data = Fonts.lookup(font.name).data; var length = data.length; for (var j = 0; j < length; j++) str += String.fromCharCode(data[j]); @@ -152,8 +176,8 @@ var Font = (function () { this.encoding = properties.encoding; // If the font has already been decoded simply return it - if (Fonts[name]) { - this.font = Fonts[name].data; + if (Fonts.lookup(name)) { + this.font = Fonts.lookup(name).data; return; } fontCount++; @@ -162,12 +186,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 || kDisableFonts) { - Fonts[name] = { - data: file, - loading: false, - properties: {}, - cache: Object.create(null) - } + Fonts.blacklistFont(name); return; } @@ -194,13 +213,7 @@ var Font = (function () { break; } this.data = data; - - Fonts[name] = { - data: data, - properties: properties, - loading: true, - cache: Object.create(null) - }; + Fonts.registerFont(name, data, properties); }; function stringToArray(str) { @@ -854,7 +867,7 @@ var Font = (function () { src += ' var fontName="'+ fontName +'";\n'; src += ' window.onload = function () {\n' src += ' var Fonts = top.document.defaultView.Fonts;\n'; - src += ' var font = Fonts[fontName];\n'; + src += ' var font = Fonts.lookup(fontName);\n'; src += ' font.loading = false;\n'; src += ' var doc = top.document;\n'; src += ' var evt = doc.createEvent("Events");\n'; diff --git a/multi_page_viewer.js b/multi_page_viewer.js index d60e96cb2..66357716e 100644 --- a/multi_page_viewer.js +++ b/multi_page_viewer.js @@ -29,11 +29,15 @@ var PDFViewer = { scale: 1.0, pageWidth: function(page) { - return page.mediaBox[2] * PDFViewer.scale; + var pdfToCssUnitsCoef = 96.0 / 72.0; + var width = (page.mediaBox[2] - page.mediaBox[0]); + return width * PDFViewer.scale * pdfToCssUnitsCoef; }, pageHeight: function(page) { - return page.mediaBox[3] * PDFViewer.scale; + var pdfToCssUnitsCoef = 96.0 / 72.0; + var height = (page.mediaBox[3] - page.mediaBox[1]); + return height * PDFViewer.scale * pdfToCssUnitsCoef; }, lastPagesDrawn: [], @@ -106,10 +110,11 @@ var PDFViewer = { 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; + var pageWidth = PDFViewer.pageWidth(page); + var pageHeight = PDFViewer.pageHeight(page); + var thumbScale = Math.min(104 / pageWidth, 134 / pageHeight); + canvas.width = pageWidth * thumbScale; + canvas.height = pageHeight * thumbScale; div.appendChild(canvas); var ctx = canvas.getContext('2d'); @@ -168,8 +173,6 @@ var PDFViewer = { 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(page); canvas.height = PDFViewer.pageHeight(page); div.appendChild(canvas); @@ -260,6 +263,12 @@ var PDFViewer = { openURL: function(url) { PDFViewer.url = url; document.title = url; + + if (this.thumbsLoadingInterval) { + // cancel thumbs loading operations + clearInterval(this.thumbsLoadingInterval); + this.thumbsLoadingInterval = null; + } var req = new XMLHttpRequest(); req.open('GET', url); @@ -276,7 +285,9 @@ var PDFViewer = { req.send(null); }, - + + thumbsLoadingInterval: null, + readPDF: function(data) { while (PDFViewer.element.hasChildNodes()) { PDFViewer.element.removeChild(PDFViewer.element.firstChild); @@ -298,12 +309,22 @@ var PDFViewer = { PDFViewer.drawPage(1); document.location.hash = 1; - setTimeout(function() { - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createThumbnail(i); - PDFViewer.drawThumbnail(i); + // slowly loading the thumbs (few per second) + // first time we are loading more images than subsequent + var currentPageIndex = 1, imagesToLoad = 15; + this.thumbsLoadingInterval = setInterval((function() { + while (imagesToLoad-- > 0) { + if (currentPageIndex > PDFViewer.numberOfPages) { + clearInterval(this.thumbsLoadingInterval); + this.thumbsLoadingInterval = null; + return; + } + PDFViewer.createThumbnail(currentPageIndex); + PDFViewer.drawThumbnail(currentPageIndex); + ++currentPageIndex; } - }, 500); + imagesToLoad = 3; // next time loading less images + }).bind(this), 500); } PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : ''; diff --git a/test/test_slave.html b/test/test_slave.html index 8564b52b4..3180418fa 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -4,6 +4,7 @@ +