From 71d0f0d55c4584e2731a9f0e573c183a87f39ea9 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 8 Sep 2011 13:03:30 +0200 Subject: [PATCH 1/4] Remove a useless check in charsToUnicode --- fonts.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fonts.js b/fonts.js index bfdbb0b4a..5622e84e4 100755 --- a/fonts.js +++ b/fonts.js @@ -444,7 +444,6 @@ var Font = (function Font() { var constructor = function font_constructor(name, file, properties) { this.name = name; this.encoding = properties.encoding; - this.glyphs = properties.glyphs; this.sizes = []; var names = name.split("+"); @@ -1368,10 +1367,6 @@ var Font = (function Font() { unicode = charcode; } - // Check if the glyph has already been converted - if (!IsNum(unicode)) - unicode = encoding[charcode].unicode = this.glyphs[unicode].unicode; - // Handle surrogate pairs if (unicode > 0xFFFF) { str += String.fromCharCode(unicode & 0xFFFF); From 81d7d1a72515450b25b07eaf482a3591820db46f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 8 Sep 2011 17:57:37 +0200 Subject: [PATCH 2/4] Add widths information for the most common fonts cases --- fonts.js | 28 +++++++++++++++++-------- pdf.js | 64 ++++++++++++++++++++++++++------------------------------ 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/fonts.js b/fonts.js index 5622e84e4..cca1d816c 100755 --- a/fonts.js +++ b/fonts.js @@ -140,11 +140,21 @@ var FontMeasure = (function FontMeasure() { ctx.font = rule; current = font; }, - measureText: function fonts_measureText(text) { + measureText: function fonts_measureText(text, encoding, size) { var width; if (measureCache && (width = measureCache[text])) return width; - width = ctx.measureText(text).width / kScalePrecision; + + try { + width = 0.0; + for (var i = 0; i < text.length; i++) { + var charWidth = encoding[text.charCodeAt(i)].width; + width += parseFloat(charWidth); + } + width = width * size / 1000; + } catch(e) { + width = ctx.measureText(text).width / kScalePrecision; + } if (measureCache) measureCache[text] = width; return width; @@ -468,8 +478,7 @@ var Font = (function Font() { (fontName.indexOf('Italic') != -1); // Use 'name' instead of 'fontName' here because the original - // name ArialNarrow for example will be replaced by Helvetica. - this.narrow = (name.indexOf("Narrow") != -1) + // name ArialBlack for example will be replaced by Helvetica. this.black = (name.indexOf("Black") != -1) this.loadedName = fontName.split('-')[0]; @@ -1018,7 +1027,9 @@ var Font = (function Font() { var index = firstCode; for (var j = start; j <= end; j++) { var code = j - firstCode - 1; - encoding[index++] = { unicode: glyphs[code].unicode }; + var mapping = encoding[index + 1] || {}; + mapping.unicode = glyphs[code].unicode; + encoding[index++] = mapping; } return cmap.data = createCMapTable(glyphs); } @@ -2329,12 +2340,11 @@ var Type2CFF = (function() { } } - if (code == -1) { - var mapping = properties.glyphs[glyph] || {}; + var mapping = properties.glyphs[glyph] || {}; + if (code == -1) index = code = mapping.unicode || index; - } - var width = widths[code] || defaultWidth; + var width = mapping.width || defaultWidth; if (code <= 0x1f || (code >= 127 && code <= 255)) code += kCmapGlyphOffset; diff --git a/pdf.js b/pdf.js index 40ffde688..7fff8ae62 100644 --- a/pdf.js +++ b/pdf.js @@ -4273,22 +4273,23 @@ var PartialEvaluator = (function() { var glyphs = {}; for (var i = firstChar; i <= lastChar; i++) { var glyph = differences[i] || baseEncoding[i]; - if (glyph) { - var index = GlyphsUnicode[glyph] || i; - glyphs[glyph] = map[i] = { - unicode: index, - width: properties.widths[i - firstChar] || properties.defaultWidth - }; + var index = GlyphsUnicode[glyph] || i; + map[i] = { + unicode: index, + width: properties.widths[i] || properties.defaultWidth + }; - // If there is no file, the character mapping can't be modified - // but this is unlikely that there is any standard encoding with - // chars below 0x1f, so that's fine. - if (!properties.file) - continue; + if (glyph) + glyphs[glyph] = map[i]; - if (index <= 0x1f || (index >= 127 && index <= 255)) - map[i].unicode += kCmapGlyphOffset; - } + // If there is no file, the character mapping can't be modified + // but this is unlikely that there is any standard encoding with + // chars below 0x1f, so that's fine. + if (!properties.file) + continue; + + if (index <= 0x1f || (index >= 127 && index <= 255)) + map[i].unicode += kCmapGlyphOffset; } if (type == 'TrueType' && dict.has('ToUnicode') && differences) { @@ -4325,10 +4326,9 @@ var PartialEvaluator = (function() { var endRange = tokens[j + 1]; var code = tokens[j + 2]; while (startRange < endRange) { - map[startRange] = { - unicode: code++, - width: 0 - } + var mapping = map[startRange] || {}; + mapping.unicode = code++; + map[startRange] = mapping; ++startRange; } } @@ -4339,10 +4339,9 @@ var PartialEvaluator = (function() { for (var j = 0; j < tokens.length; j += 2) { var index = tokens[j]; var code = tokens[j + 1]; - map[index] = { - unicode: code, - width: 0 - }; + var mapping = map[index] || {}; + mapping.unicode = code; + map[index] = mapping; } break; @@ -4494,13 +4493,13 @@ var PartialEvaluator = (function() { descent: descriptor.get('Descent'), xHeight: descriptor.get('XHeight'), capHeight: descriptor.get('CapHeight'), - defaultWidth: descriptor.get('MissingWidth') || 0, + defaultWidth: parseFloat(descriptor.get('MissingWidth')) || 0, flags: descriptor.get('Flags'), italicAngle: descriptor.get('ItalicAngle'), differences: [], widths: (function() { var glyphWidths = {}; - for (var i = 0; i <= widths.length; i++) + for (var i = 0; i < widths.length; i++) glyphWidths[firstChar++] = widths[i]; return glyphWidths; })(), @@ -4898,6 +4897,7 @@ var CanvasGraphics = (function() { var scaleFactorX = 1, scaleFactorY = 1; var font = current.font; + var baseText= text; if (font) { if (current.fontSize <= kRasterizerMin) { scaleFactorX = scaleFactorY = kScalePrecision; @@ -4907,26 +4907,22 @@ var CanvasGraphics = (function() { text = font.charsToUnicode(text); } + var encoding = current.font.encoding; + var size = current.fontSize; var charSpacing = current.charSpacing; var wordSpacing = current.wordSpacing; var textHScale = current.textHScale; - // This is a poor simulation for Arial Narrow while font-stretch - // is not implemented (bug 3512) - if (current.font.narrow) { - textHScale += 0.2; - charSpacing -= (0.09 * current.fontSize); - } - if (charSpacing != 0 || wordSpacing != 0 || textHScale != 1) { scaleFactorX *= textHScale; ctx.scale(1 / textHScale, 1); var width = 0; for (var i = 0, ii = text.length; i < ii; ++i) { - var c = text.charAt(i); + var c = baseText.charAt(i); ctx.fillText(c, 0, 0); - var charWidth = FontMeasure.measureText(c) + charSpacing; + var charWidth = FontMeasure.measureText(c, encoding, size); + charWidth += charSpacing; if (c.charCodeAt(0) == 32) charWidth += wordSpacing; ctx.translate(charWidth * scaleFactorX, 0); @@ -4935,7 +4931,7 @@ var CanvasGraphics = (function() { current.x += width; } else { ctx.fillText(text, 0, 0); - current.x += FontMeasure.measureText(text); + current.x += FontMeasure.measureText(baseText, encoding, size); } this.ctx.restore(); From b7796f123afef8f72fa68443640c4b6fadf98e34 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 22 Sep 2011 00:32:36 +0200 Subject: [PATCH 3/4] Support CropBox attribute --- pdf.js | 25 +++++++++++++++++++++++++ web/viewer.css | 10 ++++++---- web/viewer.js | 45 ++++++++++++++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/pdf.js b/pdf.js index 224becdf1..001257af0 100644 --- a/pdf.js +++ b/pdf.js @@ -3319,6 +3319,31 @@ var Page = (function() { return shadow(this, 'mediaBox', ((IsArray(obj) && obj.length == 4) ? obj : null)); }, + get view() { + var obj = this.inheritPageProp('CropBox'); + var view = { + x: 0, + y: 0, + width: this.width, + height: this.height + }; + if (IsArray(obj) && obj.length == 4) { + var rotate = this.rotate; + if (rotate == 0 || rotate == 180) { + view.x = obj[0]; + view.y = obj[1]; + view.width = obj[2] - view.x; + view.height = obj[3] - view.y; + } else { + view.x = obj[1]; + view.y = obj[0]; + view.width = obj[3] - view.x; + view.height = obj[2] - view.y; + } + } + + return shadow(this, 'cropBox', view); + }, get annotations() { return shadow(this, 'annotations', this.inheritPageProp('Annots')); }, diff --git a/web/viewer.css b/web/viewer.css index cda191a76..e72bdc286 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -119,6 +119,7 @@ span#info { margin-right:auto; line-height: 134px; text-align: center; + overflow: hidden; } .thumbnail:not([data-loaded]) { @@ -195,16 +196,17 @@ span#info { canvas { margin: auto; display: block; - box-shadow: 0px 4px 10px #000; - -moz-box-shadow: 0px 4px 10px #000; - -webkit-box-shadow: 0px 4px 10px #000; } .page { width: 816px; height: 1056px; margin: 10px auto; - position:relative; + position: relative; + overflow: hidden; + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; } .page > a { diff --git a/web/viewer.js b/web/viewer.js index 72b540664..f4f28b8ab 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -58,9 +58,9 @@ var PDFView = { var currentPage = this.pages[this.page - 1]; var pageWidthScale = (window.innerWidth - kScrollbarPadding) / - currentPage.width / kCssUnits; + currentPage.width / kCssUnits; var pageHeightScale = (window.innerHeight - kScrollbarPadding) / - currentPage.height / kCssUnits; + currentPage.height / kCssUnits; if ('page-width' == value) this.setScale(pageWidthScale, resetAutoSettings); if ('page-height' == value) @@ -170,7 +170,7 @@ var PDFView = { var page = pdf.getPage(i); pages.push(new PageView(container, page, i, page.width, page.height, page.stats, this.navigateTo.bind(this))); - thumbnails.push(new ThumbnailView(sidebar, pages[i - 1], + thumbnails.push(new ThumbnailView(sidebar, page, i, page.width / page.height)); var pageRef = page.ref; pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; @@ -237,13 +237,17 @@ var PDFView = { } }; -var PageView = function(container, content, id, width, height, +var PageView = function(container, content, id, pageWidth, pageHeight, stats, navigateTo) { - this.width = width; - this.height = height; this.id = id; this.content = content; + var view = this.content.view; + this.x = view.x; + this.y = view.y; + this.width = view.width; + this.height = view.height; + var anchor = document.createElement('a'); anchor.name = '' + this.id; @@ -272,11 +276,12 @@ var PageView = function(container, content, id, width, height, return false; }; } + var links = content.getLinks(); for (var i = 0; i < links.length; i++) { var link = document.createElement('a'); - link.style.left = Math.floor(links[i].x * scale) + 'px'; - link.style.top = Math.floor(links[i].y * scale) + 'px'; + link.style.left = (Math.floor(links[i].x - this.x) * scale) + 'px'; + link.style.top = (Math.floor(links[i].y - this.y) * scale) + 'px'; link.style.width = Math.ceil(links[i].width * scale) + 'px'; link.style.height = Math.ceil(links[i].height * scale) + 'px'; link.href = links[i].url || ''; @@ -364,8 +369,9 @@ var PageView = function(container, content, id, width, height, canvas.id = 'page' + this.id; canvas.mozOpaque = true; - canvas.width = this.width * this.scale; - canvas.height = this.height * this.scale; + var scale = this.scale; + canvas.width = pageWidth * scale; + canvas.height = pageHeight * scale; div.appendChild(canvas); var ctx = canvas.getContext('2d'); @@ -373,6 +379,7 @@ var PageView = function(container, content, id, width, height, ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); + ctx.translate(-this.x * scale, -this.y * scale); stats.begin = Date.now(); this.content.startRendering(ctx, this.updateStats); @@ -391,12 +398,12 @@ var PageView = function(container, content, id, width, height, }; }; -var ThumbnailView = function(container, page, pageRatio) { +var ThumbnailView = function(container, page, id, pageRatio) { var anchor = document.createElement('a'); - anchor.href = '#' + page.id; + anchor.href = '#' + id; var div = document.createElement('div'); - div.id = 'thumbnailContainer' + page.id; + div.id = 'thumbnailContainer' + id; div.className = 'thumbnail'; anchor.appendChild(div); @@ -407,7 +414,7 @@ var ThumbnailView = function(container, page, pageRatio) { return; var canvas = document.createElement('canvas'); - canvas.id = 'thumbnail' + page.id; + canvas.id = 'thumbnail' + id; canvas.mozOpaque = true; var maxThumbSize = 134; @@ -425,7 +432,15 @@ var ThumbnailView = function(container, page, pageRatio) { ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); - page.content.startRendering(ctx, function() { }); + var view = page.view; + var scaleX = (canvas.width / page.width); + var scaleY = (canvas.height / page.height); + ctx.translate(-view.x * scaleX, -view.y * scaleY); + div.style.width = (view.width * scaleX) + 'px'; + div.style.height = (view.height * scaleY) + 'px'; + div.style.lineHeight = (view.height * scaleY) + 'px'; + + page.startRendering(ctx, function() { }); }; }; From d8905b524d2ff3d7590b56ed990e6602de526793 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 22 Sep 2011 00:44:51 +0200 Subject: [PATCH 4/4] Fix a lint error --- web/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index f4f28b8ab..fb3af2ad4 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -281,7 +281,7 @@ var PageView = function(container, content, id, pageWidth, pageHeight, for (var i = 0; i < links.length; i++) { var link = document.createElement('a'); link.style.left = (Math.floor(links[i].x - this.x) * scale) + 'px'; - link.style.top = (Math.floor(links[i].y - this.y) * scale) + 'px'; + link.style.top = (Math.floor(links[i].y - this.y) * scale) + 'px'; link.style.width = Math.ceil(links[i].width * scale) + 'px'; link.style.height = Math.ceil(links[i].height * scale) + 'px'; link.href = links[i].url || '';