Merge remote branch 'upstream/master'
This commit is contained in:
commit
f4e5b2bcfd
12
README
12
README
@ -1,12 +0,0 @@
|
|||||||
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
|
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# pdf.js
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
pdf.js is not currently part of the Mozilla project, and there is no plan
|
||||||
|
yet to integrate it into Firefox. We will explore that possibility once
|
||||||
|
pdf.js is production ready. Until then we aim to publish a Firefox
|
||||||
|
PDF reader extension powered by pdf.js.
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
follow us on twitter: @pdfjs
|
||||||
|
|
||||||
|
http://twitter.com/#!/pdfjs
|
||||||
|
|
||||||
|
join our mailing list:
|
||||||
|
|
||||||
|
dev-pdf-js@lists.mozilla.org
|
||||||
|
|
||||||
|
and talk to us on IRC:
|
||||||
|
|
||||||
|
#pdfjs on irc.mozilla.org
|
10
crypto.js
10
crypto.js
@ -1,5 +1,5 @@
|
|||||||
/* -*- Mode: Java; tab-width: s; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||||
/* vim: set shiftwidth=s tabstop=2 autoindent cindent expandtab: */
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -45,12 +45,12 @@ var ARCFourCipher = (function() {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
var md5 = (function() {
|
var md5 = (function() {
|
||||||
const r = new Uint8Array([
|
var r = new Uint8Array([
|
||||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
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,
|
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,
|
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]);
|
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
|
||||||
const k = new Int32Array([
|
var k = new Int32Array([
|
||||||
-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
|
-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
|
||||||
-1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
|
-1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
|
||||||
1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
|
1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
|
||||||
@ -149,7 +149,7 @@ var CipherTransform = (function() {
|
|||||||
|
|
||||||
var CipherTransformFactory = (function() {
|
var CipherTransformFactory = (function() {
|
||||||
function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength) {
|
function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength) {
|
||||||
const defaultPasswordBytes = new Uint8Array([
|
var defaultPasswordBytes = new Uint8Array([
|
||||||
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
|
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]);
|
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;
|
var hashData = new Uint8Array(88), i = 0, j, n;
|
||||||
|
701
fonts.js
701
fonts.js
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var isWorker = (typeof window == "undefined");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum file size of the font.
|
* Maximum file size of the font.
|
||||||
*/
|
*/
|
||||||
@ -26,69 +28,109 @@ var fontName = "";
|
|||||||
*/
|
*/
|
||||||
var kDisableFonts = false;
|
var kDisableFonts = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
||||||
* their acronyms.
|
* their acronyms.
|
||||||
* TODO Add the standard fourteen Type1 fonts list by default
|
* TODO Add the standard fourteen Type1 fonts list by default
|
||||||
* http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65
|
* http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65
|
||||||
*/
|
*/
|
||||||
var Fonts = {
|
|
||||||
_active: null,
|
|
||||||
|
|
||||||
get active() {
|
var Fonts = (function () {
|
||||||
return this._active;
|
var kScalePrecision = 40;
|
||||||
},
|
var fonts = Object.create(null);
|
||||||
|
|
||||||
set active(name) {
|
if (!isWorker) {
|
||||||
this._active = this[name];
|
var ctx = document.createElement("canvas").getContext("2d");
|
||||||
},
|
ctx.scale(1 / kScalePrecision, 1);
|
||||||
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
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 (unicode instanceof Name)
|
|
||||||
unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
|
|
||||||
|
|
||||||
// Handle surrogate pairs
|
|
||||||
if (unicode > 0xFFFF) {
|
|
||||||
str += String.fromCharCode(unicode & 0xFFFF);
|
|
||||||
unicode >>= 16;
|
|
||||||
}
|
|
||||||
str += String.fromCharCode(unicode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enter the translated string into the cache
|
|
||||||
return active.cache[chars] = str;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
function Font(name, data, properties) {
|
||||||
|
this.name = name;
|
||||||
|
this.data = data;
|
||||||
|
this.properties = properties;
|
||||||
|
this.loading = true;
|
||||||
|
this.charsCache = Object.create(null);
|
||||||
|
this.sizes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var current;
|
||||||
|
var charsCache;
|
||||||
|
var measureCache;
|
||||||
|
|
||||||
|
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 = charsCache[chars];
|
||||||
|
if (str)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
var FontLoader = {
|
var FontLoader = {
|
||||||
bind: function(fonts) {
|
bind: function(fonts) {
|
||||||
var worker = (typeof window == "undefined");
|
|
||||||
var ready = true;
|
var ready = true;
|
||||||
|
|
||||||
for (var i = 0; i < fonts.length; i++) {
|
for (var i = 0; i < fonts.length; i++) {
|
||||||
var font = fonts[i];
|
var font = fonts[i];
|
||||||
if (Fonts[font.name]) {
|
if (Fonts.lookup(font.name)) {
|
||||||
ready = ready && !Fonts[font.name].loading;
|
ready = ready && !Fonts.lookup(font.name).loading;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,18 +139,152 @@ var FontLoader = {
|
|||||||
var obj = new Font(font.name, font.file, font.properties);
|
var obj = new Font(font.name, font.file, font.properties);
|
||||||
|
|
||||||
var str = "";
|
var str = "";
|
||||||
var data = Fonts[font.name].data;
|
var data = Fonts.lookup(font.name).data;
|
||||||
var length = data.length;
|
var length = data.length;
|
||||||
for (var j = 0; j < length; j++)
|
for (var j = 0; j < length; j++)
|
||||||
str += String.fromCharCode(data[j]);
|
str += String.fromCharCode(data[j]);
|
||||||
|
|
||||||
worker ? obj.bindWorker(str) : obj.bindDOM(str);
|
isWorker ? obj.bindWorker(str) : obj.bindDOM(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var UnicodeRanges = [
|
||||||
|
{ "begin": 0x0000, "end": 0x007F }, // Basic Latin
|
||||||
|
{ "begin": 0x0080, "end": 0x00FF }, // Latin-1 Supplement
|
||||||
|
{ "begin": 0x0100, "end": 0x017F }, // Latin Extended-A
|
||||||
|
{ "begin": 0x0180, "end": 0x024F }, // Latin Extended-B
|
||||||
|
{ "begin": 0x0250, "end": 0x02AF }, // IPA Extensions
|
||||||
|
{ "begin": 0x02B0, "end": 0x02FF }, // Spacing Modifier Letters
|
||||||
|
{ "begin": 0x0300, "end": 0x036F }, // Combining Diacritical Marks
|
||||||
|
{ "begin": 0x0370, "end": 0x03FF }, // Greek and Coptic
|
||||||
|
{ "begin": 0x2C80, "end": 0x2CFF }, // Coptic
|
||||||
|
{ "begin": 0x0400, "end": 0x04FF }, // Cyrillic
|
||||||
|
{ "begin": 0x0530, "end": 0x058F }, // Armenian
|
||||||
|
{ "begin": 0x0590, "end": 0x05FF }, // Hebrew
|
||||||
|
{ "begin": 0xA500, "end": 0xA63F }, // Vai
|
||||||
|
{ "begin": 0x0600, "end": 0x06FF }, // Arabic
|
||||||
|
{ "begin": 0x07C0, "end": 0x07FF }, // NKo
|
||||||
|
{ "begin": 0x0900, "end": 0x097F }, // Devanagari
|
||||||
|
{ "begin": 0x0980, "end": 0x09FF }, // Bengali
|
||||||
|
{ "begin": 0x0A00, "end": 0x0A7F }, // Gurmukhi
|
||||||
|
{ "begin": 0x0A80, "end": 0x0AFF }, // Gujarati
|
||||||
|
{ "begin": 0x0B00, "end": 0x0B7F }, // Oriya
|
||||||
|
{ "begin": 0x0B80, "end": 0x0BFF }, // Tamil
|
||||||
|
{ "begin": 0x0C00, "end": 0x0C7F }, // Telugu
|
||||||
|
{ "begin": 0x0C80, "end": 0x0CFF }, // Kannada
|
||||||
|
{ "begin": 0x0D00, "end": 0x0D7F }, // Malayalam
|
||||||
|
{ "begin": 0x0E00, "end": 0x0E7F }, // Thai
|
||||||
|
{ "begin": 0x0E80, "end": 0x0EFF }, // Lao
|
||||||
|
{ "begin": 0x10A0, "end": 0x10FF }, // Georgian
|
||||||
|
{ "begin": 0x1B00, "end": 0x1B7F }, // Balinese
|
||||||
|
{ "begin": 0x1100, "end": 0x11FF }, // Hangul Jamo
|
||||||
|
{ "begin": 0x1E00, "end": 0x1EFF }, // Latin Extended Additional
|
||||||
|
{ "begin": 0x1F00, "end": 0x1FFF }, // Greek Extended
|
||||||
|
{ "begin": 0x2000, "end": 0x206F }, // General Punctuation
|
||||||
|
{ "begin": 0x2070, "end": 0x209F }, // Superscripts And Subscripts
|
||||||
|
{ "begin": 0x20A0, "end": 0x20CF }, // Currency Symbol
|
||||||
|
{ "begin": 0x20D0, "end": 0x20FF }, // Combining Diacritical Marks For Symbols
|
||||||
|
{ "begin": 0x2100, "end": 0x214F }, // Letterlike Symbols
|
||||||
|
{ "begin": 0x2150, "end": 0x218F }, // Number Forms
|
||||||
|
{ "begin": 0x2190, "end": 0x21FF }, // Arrows
|
||||||
|
{ "begin": 0x2200, "end": 0x22FF }, // Mathematical Operators
|
||||||
|
{ "begin": 0x2300, "end": 0x23FF }, // Miscellaneous Technical
|
||||||
|
{ "begin": 0x2400, "end": 0x243F }, // Control Pictures
|
||||||
|
{ "begin": 0x2440, "end": 0x245F }, // Optical Character Recognition
|
||||||
|
{ "begin": 0x2460, "end": 0x24FF }, // Enclosed Alphanumerics
|
||||||
|
{ "begin": 0x2500, "end": 0x257F }, // Box Drawing
|
||||||
|
{ "begin": 0x2580, "end": 0x259F }, // Block Elements
|
||||||
|
{ "begin": 0x25A0, "end": 0x25FF }, // Geometric Shapes
|
||||||
|
{ "begin": 0x2600, "end": 0x26FF }, // Miscellaneous Symbols
|
||||||
|
{ "begin": 0x2700, "end": 0x27BF }, // Dingbats
|
||||||
|
{ "begin": 0x3000, "end": 0x303F }, // CJK Symbols And Punctuation
|
||||||
|
{ "begin": 0x3040, "end": 0x309F }, // Hiragana
|
||||||
|
{ "begin": 0x30A0, "end": 0x30FF }, // Katakana
|
||||||
|
{ "begin": 0x3100, "end": 0x312F }, // Bopomofo
|
||||||
|
{ "begin": 0x3130, "end": 0x318F }, // Hangul Compatibility Jamo
|
||||||
|
{ "begin": 0xA840, "end": 0xA87F }, // Phags-pa
|
||||||
|
{ "begin": 0x3200, "end": 0x32FF }, // Enclosed CJK Letters And Months
|
||||||
|
{ "begin": 0x3300, "end": 0x33FF }, // CJK Compatibility
|
||||||
|
{ "begin": 0xAC00, "end": 0xD7AF }, // Hangul Syllables
|
||||||
|
{ "begin": 0xD800, "end": 0xDFFF }, // Non-Plane 0 *
|
||||||
|
{ "begin": 0x10900, "end": 0x1091F }, // Phoenicia
|
||||||
|
{ "begin": 0x4E00, "end": 0x9FFF }, // CJK Unified Ideographs
|
||||||
|
{ "begin": 0xE000, "end": 0xF8FF }, // Private Use Area (plane 0)
|
||||||
|
{ "begin": 0x31C0, "end": 0x31EF }, // CJK Strokes
|
||||||
|
{ "begin": 0xFB00, "end": 0xFB4F }, // Alphabetic Presentation Forms
|
||||||
|
{ "begin": 0xFB50, "end": 0xFDFF }, // Arabic Presentation Forms-A
|
||||||
|
{ "begin": 0xFE20, "end": 0xFE2F }, // Combining Half Marks
|
||||||
|
{ "begin": 0xFE10, "end": 0xFE1F }, // Vertical Forms
|
||||||
|
{ "begin": 0xFE50, "end": 0xFE6F }, // Small Form Variants
|
||||||
|
{ "begin": 0xFE70, "end": 0xFEFF }, // Arabic Presentation Forms-B
|
||||||
|
{ "begin": 0xFF00, "end": 0xFFEF }, // Halfwidth And Fullwidth Forms
|
||||||
|
{ "begin": 0xFFF0, "end": 0xFFFF }, // Specials
|
||||||
|
{ "begin": 0x0F00, "end": 0x0FFF }, // Tibetan
|
||||||
|
{ "begin": 0x0700, "end": 0x074F }, // Syriac
|
||||||
|
{ "begin": 0x0780, "end": 0x07BF }, // Thaana
|
||||||
|
{ "begin": 0x0D80, "end": 0x0DFF }, // Sinhala
|
||||||
|
{ "begin": 0x1000, "end": 0x109F }, // Myanmar
|
||||||
|
{ "begin": 0x1200, "end": 0x137F }, // Ethiopic
|
||||||
|
{ "begin": 0x13A0, "end": 0x13FF }, // Cherokee
|
||||||
|
{ "begin": 0x1400, "end": 0x167F }, // Unified Canadian Aboriginal Syllabics
|
||||||
|
{ "begin": 0x1680, "end": 0x169F }, // Ogham
|
||||||
|
{ "begin": 0x16A0, "end": 0x16FF }, // Runic
|
||||||
|
{ "begin": 0x1780, "end": 0x17FF }, // Khmer
|
||||||
|
{ "begin": 0x1800, "end": 0x18AF }, // Mongolian
|
||||||
|
{ "begin": 0x2800, "end": 0x28FF }, // Braille Patterns
|
||||||
|
{ "begin": 0xA000, "end": 0xA48F }, // Yi Syllables
|
||||||
|
{ "begin": 0x1700, "end": 0x171F }, // Tagalog
|
||||||
|
{ "begin": 0x10300, "end": 0x1032F }, // Old Italic
|
||||||
|
{ "begin": 0x10330, "end": 0x1034F }, // Gothic
|
||||||
|
{ "begin": 0x10400, "end": 0x1044F }, // Deseret
|
||||||
|
{ "begin": 0x1D000, "end": 0x1D0FF }, // Byzantine Musical Symbols
|
||||||
|
{ "begin": 0x1D400, "end": 0x1D7FF }, // Mathematical Alphanumeric Symbols
|
||||||
|
{ "begin": 0xFF000, "end": 0xFFFFD }, // Private Use (plane 15)
|
||||||
|
{ "begin": 0xFE00, "end": 0xFE0F }, // Variation Selectors
|
||||||
|
{ "begin": 0xE0000, "end": 0xE007F }, // Tags
|
||||||
|
{ "begin": 0x1900, "end": 0x194F }, // Limbu
|
||||||
|
{ "begin": 0x1950, "end": 0x197F }, // Tai Le
|
||||||
|
{ "begin": 0x1980, "end": 0x19DF }, // New Tai Lue
|
||||||
|
{ "begin": 0x1A00, "end": 0x1A1F }, // Buginese
|
||||||
|
{ "begin": 0x2C00, "end": 0x2C5F }, // Glagolitic
|
||||||
|
{ "begin": 0x2D30, "end": 0x2D7F }, // Tifinagh
|
||||||
|
{ "begin": 0x4DC0, "end": 0x4DFF }, // Yijing Hexagram Symbols
|
||||||
|
{ "begin": 0xA800, "end": 0xA82F }, // Syloti Nagri
|
||||||
|
{ "begin": 0x10000, "end": 0x1007F }, // Linear B Syllabary
|
||||||
|
{ "begin": 0x10140, "end": 0x1018F }, // Ancient Greek Numbers
|
||||||
|
{ "begin": 0x10380, "end": 0x1039F }, // Ugaritic
|
||||||
|
{ "begin": 0x103A0, "end": 0x103DF }, // Old Persian
|
||||||
|
{ "begin": 0x10450, "end": 0x1047F }, // Shavian
|
||||||
|
{ "begin": 0x10480, "end": 0x104AF }, // Osmanya
|
||||||
|
{ "begin": 0x10800, "end": 0x1083F }, // Cypriot Syllabary
|
||||||
|
{ "begin": 0x10A00, "end": 0x10A5F }, // Kharoshthi
|
||||||
|
{ "begin": 0x1D300, "end": 0x1D35F }, // Tai Xuan Jing Symbols
|
||||||
|
{ "begin": 0x12000, "end": 0x123FF }, // Cuneiform
|
||||||
|
{ "begin": 0x1D360, "end": 0x1D37F }, // Counting Rod Numerals
|
||||||
|
{ "begin": 0x1B80, "end": 0x1BBF }, // Sundanese
|
||||||
|
{ "begin": 0x1C00, "end": 0x1C4F }, // Lepcha
|
||||||
|
{ "begin": 0x1C50, "end": 0x1C7F }, // Ol Chiki
|
||||||
|
{ "begin": 0xA880, "end": 0xA8DF }, // Saurashtra
|
||||||
|
{ "begin": 0xA900, "end": 0xA92F }, // Kayah Li
|
||||||
|
{ "begin": 0xA930, "end": 0xA95F }, // Rejang
|
||||||
|
{ "begin": 0xAA00, "end": 0xAA5F }, // Cham
|
||||||
|
{ "begin": 0x10190, "end": 0x101CF }, // Ancient Symbols
|
||||||
|
{ "begin": 0x101D0, "end": 0x101FF }, // Phaistos Disc
|
||||||
|
{ "begin": 0x102A0, "end": 0x102DF }, // Carian
|
||||||
|
{ "begin": 0x1F030, "end": 0x1F09F } // Domino Tiles
|
||||||
|
];
|
||||||
|
|
||||||
|
function getUnicodeRangeFor(value) {
|
||||||
|
for (var i = 0; i < UnicodeRanges.length; i++) {
|
||||||
|
var range = UnicodeRanges[i];
|
||||||
|
if (value >= range.begin && value < range.end)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'Font' is the class the outside world should use, it encapsulate all the font
|
* 'Font' is the class the outside world should use, it encapsulate all the font
|
||||||
@ -124,8 +300,8 @@ var Font = (function () {
|
|||||||
this.encoding = properties.encoding;
|
this.encoding = properties.encoding;
|
||||||
|
|
||||||
// If the font has already been decoded simply return it
|
// If the font has already been decoded simply return it
|
||||||
if (Fonts[name]) {
|
if (Fonts.lookup(name)) {
|
||||||
this.font = Fonts[name].data;
|
this.font = Fonts.lookup(name).data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fontCount++;
|
fontCount++;
|
||||||
@ -134,12 +310,7 @@ var Font = (function () {
|
|||||||
// If the font is to be ignored, register it like an already loaded font
|
// 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.
|
// to avoid the cost of waiting for it be be loaded by the platform.
|
||||||
if (properties.ignore || kDisableFonts) {
|
if (properties.ignore || kDisableFonts) {
|
||||||
Fonts[name] = {
|
Fonts.blacklistFont(name);
|
||||||
data: file,
|
|
||||||
loading: false,
|
|
||||||
properties: {},
|
|
||||||
cache: Object.create(null)
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,13 +336,8 @@ var Font = (function () {
|
|||||||
warn("Font " + properties.type + " is not supported");
|
warn("Font " + properties.type + " is not supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.data = data;
|
||||||
Fonts[name] = {
|
Fonts.registerFont(name, data, properties);
|
||||||
data: data,
|
|
||||||
properties: properties,
|
|
||||||
loading: true,
|
|
||||||
cache: Object.create(null)
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function stringToArray(str) {
|
function stringToArray(str) {
|
||||||
@ -221,6 +387,9 @@ var Font = (function () {
|
|||||||
// offset
|
// offset
|
||||||
var offset = offsets.virtualOffset;
|
var offset = offsets.virtualOffset;
|
||||||
|
|
||||||
|
// length
|
||||||
|
var length = data.length;
|
||||||
|
|
||||||
// Per spec tables must be 4-bytes align so add padding as needed
|
// Per spec tables must be 4-bytes align so add padding as needed
|
||||||
while (data.length & 3)
|
while (data.length & 3)
|
||||||
data.push(0x00);
|
data.push(0x00);
|
||||||
@ -228,16 +397,10 @@ var Font = (function () {
|
|||||||
while (offsets.virtualOffset & 3)
|
while (offsets.virtualOffset & 3)
|
||||||
offsets.virtualOffset++;
|
offsets.virtualOffset++;
|
||||||
|
|
||||||
// length
|
|
||||||
var length = data.length;
|
|
||||||
|
|
||||||
// checksum
|
// checksum
|
||||||
var checksum = tag.charCodeAt(0) +
|
var checksum = 0;
|
||||||
tag.charCodeAt(1) +
|
for (var i = 0; i < length; i+=4)
|
||||||
tag.charCodeAt(2) +
|
checksum += FontsUtils.bytesToInteger([data[i], data[i+1], data[i+2], data[i+3]]);
|
||||||
tag.charCodeAt(3) +
|
|
||||||
offset +
|
|
||||||
length;
|
|
||||||
|
|
||||||
var tableEntry = tag + string32(checksum) + string32(offset) + string32(length);
|
var tableEntry = tag + string32(checksum) + string32(offset) + string32(length);
|
||||||
tableEntry = stringToArray(tableEntry);
|
tableEntry = stringToArray(tableEntry);
|
||||||
@ -271,6 +434,7 @@ var Font = (function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createCMapTable(glyphs) {
|
function createCMapTable(glyphs) {
|
||||||
|
glyphs.push({ unicode: 0x0000 });
|
||||||
var ranges = getRanges(glyphs);
|
var ranges = getRanges(glyphs);
|
||||||
|
|
||||||
var headerSize = (12 * 2 + (ranges.length * 4 * 2));
|
var headerSize = (12 * 2 + (ranges.length * 4 * 2));
|
||||||
@ -304,13 +468,13 @@ var Font = (function () {
|
|||||||
var range = ranges[i];
|
var range = ranges[i];
|
||||||
var start = range[0];
|
var start = range[0];
|
||||||
var end = range[1];
|
var end = range[1];
|
||||||
var delta = (((start - 1) - bias) ^ 0xffff) + 1;
|
var delta = (((start - 1) - bias) ^ 0xffff);
|
||||||
bias += (end - start + 1);
|
bias += (end - start + 1);
|
||||||
|
|
||||||
startCount += string16(start);
|
startCount += string16(start);
|
||||||
endCount += string16(end);
|
endCount += string16(end);
|
||||||
idDeltas += string16(delta);
|
idDeltas += string16(delta);
|
||||||
idRangeOffsets += string16(0);
|
idRangeOffsets += string16(0);
|
||||||
|
|
||||||
for (var j = 0; j < range.length; j++)
|
for (var j = 0; j < range.length; j++)
|
||||||
glyphsIds += String.fromCharCode(range[j]);
|
glyphsIds += String.fromCharCode(range[j]);
|
||||||
@ -326,11 +490,43 @@ var Font = (function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createOS2Table(properties) {
|
function createOS2Table(properties) {
|
||||||
|
var ulUnicodeRange1 = 0;
|
||||||
|
var ulUnicodeRange2 = 0;
|
||||||
|
var ulUnicodeRange3 = 0;
|
||||||
|
var ulUnicodeRange4 = 0;
|
||||||
|
|
||||||
|
var charset = properties.charset;
|
||||||
|
if (charset && charset.length) {
|
||||||
|
var firstCharIndex = null;
|
||||||
|
var lastCharIndex = 0;
|
||||||
|
|
||||||
|
for (var i = 1; i < charset.length; i++) {
|
||||||
|
var code = GlyphsUnicode[charset[i]];
|
||||||
|
if (firstCharIndex > code || !firstCharIndex)
|
||||||
|
firstCharIndex = code;
|
||||||
|
if (lastCharIndex < code)
|
||||||
|
lastCharIndex = code;
|
||||||
|
|
||||||
|
var position = getUnicodeRangeFor(code);
|
||||||
|
if (position < 32) {
|
||||||
|
ulUnicodeRange1 |= 1 << position;
|
||||||
|
} else if (position < 64) {
|
||||||
|
ulUnicodeRange2 |= 1 << position - 32;
|
||||||
|
} else if (position < 96) {
|
||||||
|
ulUnicodeRange3 |= 1 << position - 64;
|
||||||
|
} else if (position < 123) {
|
||||||
|
ulUnicodeRange4 |= 1 << position - 96;
|
||||||
|
} else {
|
||||||
|
error("Unicode ranges Bits > 123 are reserved for internal usage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "\x00\x03" + // version
|
return "\x00\x03" + // version
|
||||||
"\x02\x24" + // xAvgCharWidth
|
"\x02\x24" + // xAvgCharWidth
|
||||||
"\x01\xF4" + // usWeightClass
|
"\x01\xF4" + // usWeightClass
|
||||||
"\x00\x05" + // usWidthClass
|
"\x00\x05" + // usWidthClass
|
||||||
"\x00\x00" + // fstype
|
"\x00\x02" + // fstype
|
||||||
"\x02\x8A" + // ySubscriptXSize
|
"\x02\x8A" + // ySubscriptXSize
|
||||||
"\x02\xBB" + // ySubscriptYSize
|
"\x02\xBB" + // ySubscriptYSize
|
||||||
"\x00\x00" + // ySubscriptXOffset
|
"\x00\x00" + // ySubscriptXOffset
|
||||||
@ -342,41 +538,41 @@ var Font = (function () {
|
|||||||
"\x00\x31" + // yStrikeOutSize
|
"\x00\x31" + // yStrikeOutSize
|
||||||
"\x01\x02" + // yStrikeOutPosition
|
"\x01\x02" + // yStrikeOutPosition
|
||||||
"\x00\x00" + // sFamilyClass
|
"\x00\x00" + // sFamilyClass
|
||||||
"\x02\x00\x06\x03\x00\x00\x00\x00\x00\x00" + // Panose
|
"\x00\x00\x06" + String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
|
||||||
"\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 0-31)
|
"\x00\x00\x00\x00\x00\x00" + // Panose
|
||||||
"\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 32-63)
|
string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
|
||||||
"\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 64-95)
|
string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
|
||||||
"\xFF\xFF\xFF\xFF" + // ulUnicodeRange1 (Bits 96-127)
|
string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
|
||||||
|
string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
|
||||||
"\x2A\x32\x31\x2A" + // achVendID
|
"\x2A\x32\x31\x2A" + // achVendID
|
||||||
"\x00\x20" + // fsSelection
|
string16(properties.italicAngle ? 1 : 0) + // fsSelection
|
||||||
"\x00\x2D" + // usFirstCharIndex
|
string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex
|
||||||
"\x00\x7A" + // usLastCharIndex
|
string16(lastCharIndex || properties.lastChar) + // usLastCharIndex
|
||||||
"\x00\x03" + // sTypoAscender
|
string16(properties.ascent) + // sTypoAscender
|
||||||
"\x00\x20" + // sTypeDescender
|
string16(properties.descent) + // sTypoDescender
|
||||||
"\x00\x38" + // sTypoLineGap
|
"\x00\x64" + // sTypoLineGap (7%-10% of the unitsPerEM value)
|
||||||
string16(properties.ascent) + // usWinAscent
|
string16(properties.ascent) + // usWinAscent
|
||||||
string16(properties.descent) + // usWinDescent
|
string16(-properties.descent) + // usWinDescent
|
||||||
"\x00\xCE\x00\x00" + // ulCodePageRange1 (Bits 0-31)
|
"\x00\x00\x00\x00" + // ulCodePageRange1 (Bits 0-31)
|
||||||
"\x00\x01\x00\x00" + // ulCodePageRange2 (Bits 32-63)
|
"\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63)
|
||||||
string16(properties.xHeight) + // sxHeight
|
string16(properties.xHeight) + // sxHeight
|
||||||
string16(properties.capHeight) + // sCapHeight
|
string16(properties.capHeight) + // sCapHeight
|
||||||
"\x00\x01" + // usDefaultChar
|
string16(0) + // usDefaultChar
|
||||||
"\x00\xCD" + // usBreakChar
|
string16(firstCharIndex || properties.firstChar) + // usBreakChar
|
||||||
"\x00\x02"; // usMaxContext
|
"\x00\x03"; // usMaxContext
|
||||||
};
|
};
|
||||||
|
|
||||||
function createPostTable(properties) {
|
function createPostTable(properties) {
|
||||||
TODO("Fill with real values from the font dict");
|
var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
|
||||||
|
return "\x00\x03\x00\x00" + // Version number
|
||||||
return "\x00\x03\x00\x00" + // Version number
|
string32(angle) + // italicAngle
|
||||||
string32(properties.italicAngle) + // italicAngle
|
"\x00\x00" + // underlinePosition
|
||||||
"\x00\x00" + // underlinePosition
|
"\x00\x00" + // underlineThickness
|
||||||
"\x00\x00" + // underlineThickness
|
string32(properties.fixedPitch) + // isFixedPitch
|
||||||
"\x00\x00\x00\x00" + // isFixedPitch
|
"\x00\x00\x00\x00" + // minMemType42
|
||||||
"\x00\x00\x00\x00" + // minMemType42
|
"\x00\x00\x00\x00" + // maxMemType42
|
||||||
"\x00\x00\x00\x00" + // maxMemType42
|
"\x00\x00\x00\x00" + // minMemType1
|
||||||
"\x00\x00\x00\x00" + // minMemType1
|
"\x00\x00\x00\x00"; // maxMemType1
|
||||||
"\x00\x00\x00\x00"; // maxMemType1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
@ -604,44 +800,75 @@ var Font = (function () {
|
|||||||
var otf = new Uint8Array(kMaxFontFileSize);
|
var otf = new Uint8Array(kMaxFontFileSize);
|
||||||
|
|
||||||
function createNameTable(name) {
|
function createNameTable(name) {
|
||||||
var names = [
|
// All the strings of the name table should be an odd number of bytes
|
||||||
"See original licence", // Copyright
|
if (name.length % 2)
|
||||||
fontName, // Font family
|
name = name.slice(0, name.length - 1);
|
||||||
"undefined", // Font subfamily (font weight)
|
|
||||||
"uniqueID", // Unique ID
|
var strings = [
|
||||||
fontName, // Full font name
|
"Original licence", // 0.Copyright
|
||||||
"0.1", // Version
|
name, // 1.Font family
|
||||||
"undefined", // Postscript name
|
"Unknown", // 2.Font subfamily (font weight)
|
||||||
"undefined", // Trademark
|
"uniqueID", // 3.Unique ID
|
||||||
"undefined", // Manufacturer
|
name, // 4.Full font name
|
||||||
"undefined" // Designer
|
"Version 0.11", // 5.Version
|
||||||
|
"Unknown", // 6.Postscript name
|
||||||
|
"Unknown", // 7.Trademark
|
||||||
|
"Unknown", // 8.Manufacturer
|
||||||
|
"Unknown" // 9.Designer
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Mac want 1-byte per character strings while Windows want
|
||||||
|
// 2-bytes per character, so duplicate the names table
|
||||||
|
var stringsUnicode = [];
|
||||||
|
for (var i = 0; i < strings.length; i++) {
|
||||||
|
var str = strings[i];
|
||||||
|
|
||||||
|
var strUnicode = "";
|
||||||
|
for (var j = 0; j < str.length; j++)
|
||||||
|
strUnicode += string16(str.charCodeAt(j));
|
||||||
|
stringsUnicode.push(strUnicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
var names = [strings, stringsUnicode];
|
||||||
|
var platforms = ["\x00\x01", "\x00\x03"];
|
||||||
|
var encodings = ["\x00\x00", "\x00\x01"];
|
||||||
|
var languages = ["\x00\x00", "\x04\x09"];
|
||||||
|
|
||||||
|
var namesRecordCount = strings.length * platforms.length;
|
||||||
var nameTable =
|
var nameTable =
|
||||||
"\x00\x00" + // format
|
"\x00\x00" + // format
|
||||||
"\x00\x0A" + // Number of names Record
|
string16(namesRecordCount) + // Number of names Record
|
||||||
"\x00\x7E"; // Storage
|
string16(namesRecordCount * 12 + 6); // Storage
|
||||||
|
|
||||||
// Build the name records field
|
// Build the name records field
|
||||||
var strOffset = 0;
|
var strOffset = 0;
|
||||||
for (var i = 0; i < names.length; i++) {
|
for (var i = 0; i < platforms.length; i++) {
|
||||||
var str = names[i];
|
var strs = names[i];
|
||||||
|
for (var j = 0; j < strs.length; j++) {
|
||||||
var nameRecord =
|
var str = strs[j];
|
||||||
"\x00\x01" + // platform ID
|
var nameRecord =
|
||||||
"\x00\x00" + // encoding ID
|
platforms[i] + // platform ID
|
||||||
"\x00\x00" + // language ID
|
encodings[i] + // encoding ID
|
||||||
"\x00\x00" + // name ID
|
languages[i] + // language ID
|
||||||
string16(str.length) +
|
string16(i) + // name ID
|
||||||
string16(strOffset);
|
string16(str.length) +
|
||||||
nameTable += nameRecord;
|
string16(strOffset);
|
||||||
|
nameTable += nameRecord;
|
||||||
strOffset += str.length;
|
strOffset += str.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameTable += names.join("");
|
nameTable += strings.join("") + stringsUnicode.join("");
|
||||||
return nameTable;
|
return nameTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isFixedPitch(glyphs) {
|
||||||
|
for (var i = 0; i < glyphs.length - 1; i++) {
|
||||||
|
if (glyphs[i] != glyphs[i+1])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// Required Tables
|
// Required Tables
|
||||||
var CFF =
|
var CFF =
|
||||||
@ -672,30 +899,31 @@ var Font = (function () {
|
|||||||
createTableEntry(otf, offsets, "CFF ", CFF);
|
createTableEntry(otf, offsets, "CFF ", CFF);
|
||||||
|
|
||||||
/** OS/2 */
|
/** OS/2 */
|
||||||
|
var charstrings = font.charstrings;
|
||||||
|
properties.fixedPitch = isFixedPitch(charstrings);
|
||||||
OS2 = stringToArray(createOS2Table(properties));
|
OS2 = stringToArray(createOS2Table(properties));
|
||||||
createTableEntry(otf, offsets, "OS/2", OS2);
|
createTableEntry(otf, offsets, "OS/2", OS2);
|
||||||
|
|
||||||
/** CMAP */
|
/** CMAP */
|
||||||
var charstrings = font.charstrings;
|
cmap = createCMapTable(charstrings.slice());
|
||||||
cmap = createCMapTable(charstrings);
|
|
||||||
createTableEntry(otf, offsets, "cmap", cmap);
|
createTableEntry(otf, offsets, "cmap", cmap);
|
||||||
|
|
||||||
/** HEAD */
|
/** HEAD */
|
||||||
head = stringToArray(
|
head = stringToArray(
|
||||||
"\x00\x01\x00\x00" + // Version number
|
"\x00\x01\x00\x00" + // Version number
|
||||||
"\x00\x00\x50\x00" + // fontRevision
|
"\x00\x00\x10\x00" + // fontRevision
|
||||||
"\x00\x00\x00\x00" + // checksumAdjustement
|
"\x00\x00\x00\x00" + // checksumAdjustement
|
||||||
"\x5F\x0F\x3C\xF5" + // magicNumber
|
"\x5F\x0F\x3C\xF5" + // magicNumber
|
||||||
"\x00\x00" + // Flags
|
"\x00\x00" + // Flags
|
||||||
"\x03\xE8" + // unitsPerEM (defaulting to 1000)
|
"\x03\xE8" + // unitsPerEM (defaulting to 1000)
|
||||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + // creation date
|
"\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // creation date
|
||||||
"\x00\x00\x00\x00\x00\x00\x00\x00" + // modifification date
|
"\x00\x00\x00\x00\x9e\x0b\x7e\x27" + // modifification date
|
||||||
"\x00\x00" + // xMin
|
"\x00\x00" + // xMin
|
||||||
"\x00\x00" + // yMin
|
string16(properties.descent) + // yMin
|
||||||
"\x00\x00" + // xMax
|
"\x0F\xFF" + // xMax
|
||||||
"\x00\x00" + // yMax
|
string16(properties.ascent) + // yMax
|
||||||
"\x00\x00" + // macStyle
|
string16(properties.italicAngle ? 2 : 0) + // macStyle
|
||||||
"\x00\x00" + // lowestRecPPEM
|
"\x00\x11" + // lowestRecPPEM
|
||||||
"\x00\x00" + // fontDirectionHint
|
"\x00\x00" + // fontDirectionHint
|
||||||
"\x00\x00" + // indexToLocFormat
|
"\x00\x00" + // indexToLocFormat
|
||||||
"\x00\x00" // glyphDataFormat
|
"\x00\x00" // glyphDataFormat
|
||||||
@ -705,22 +933,22 @@ var Font = (function () {
|
|||||||
/** HHEA */
|
/** HHEA */
|
||||||
hhea = stringToArray(
|
hhea = stringToArray(
|
||||||
"\x00\x01\x00\x00" + // Version number
|
"\x00\x01\x00\x00" + // Version number
|
||||||
"\x00\x00" + // Typographic Ascent
|
string16(properties.ascent) + // Typographic Ascent
|
||||||
"\x00\x00" + // Typographic Descent
|
string16(properties.descent) + // Typographic Descent
|
||||||
"\x00\x00" + // Line Gap
|
"\x00\x00" + // Line Gap
|
||||||
"\xFF\xFF" + // advanceWidthMax
|
"\xFF\xFF" + // advanceWidthMax
|
||||||
"\x00\x00" + // minLeftSidebearing
|
"\x00\x00" + // minLeftSidebearing
|
||||||
"\x00\x00" + // minRightSidebearing
|
"\x00\x00" + // minRightSidebearing
|
||||||
"\x00\x00" + // xMaxExtent
|
"\x00\x00" + // xMaxExtent
|
||||||
"\x00\x00" + // caretSlopeRise
|
string16(properties.capHeight) + // caretSlopeRise
|
||||||
"\x00\x00" + // caretSlopeRun
|
string16(Math.tan(properties.italicAngle) * properties.xHeight) + // caretSlopeRun
|
||||||
"\x00\x00" + // caretOffset
|
"\x00\x00" + // caretOffset
|
||||||
"\x00\x00" + // -reserved-
|
"\x00\x00" + // -reserved-
|
||||||
"\x00\x00" + // -reserved-
|
"\x00\x00" + // -reserved-
|
||||||
"\x00\x00" + // -reserved-
|
"\x00\x00" + // -reserved-
|
||||||
"\x00\x00" + // -reserved-
|
"\x00\x00" + // -reserved-
|
||||||
"\x00\x00" + // metricDataFormat
|
"\x00\x00" + // metricDataFormat
|
||||||
string16(charstrings.length)
|
string16(charstrings.length + 1) // Number of HMetrics
|
||||||
);
|
);
|
||||||
createTableEntry(otf, offsets, "hhea", hhea);
|
createTableEntry(otf, offsets, "hhea", hhea);
|
||||||
|
|
||||||
@ -730,23 +958,21 @@ var Font = (function () {
|
|||||||
* while Windows use this data. So be careful if you hack on Linux and
|
* while Windows use this data. So be careful if you hack on Linux and
|
||||||
* have to touch the 'hmtx' table
|
* have to touch the 'hmtx' table
|
||||||
*/
|
*/
|
||||||
hmtx = "\x01\xF4\x00\x00"; // Fake .notdef
|
hmtx = "\x00\x00\x00\x00"; // Fake .notdef
|
||||||
var width = 0, lsb = 0;
|
|
||||||
for (var i = 0; i < charstrings.length; i++) {
|
for (var i = 0; i < charstrings.length; i++) {
|
||||||
width = charstrings[i].charstring[1];
|
hmtx += string16(charstrings[i].width) + string16(0);
|
||||||
hmtx += string16(width) + string16(lsb);
|
|
||||||
}
|
}
|
||||||
hmtx = stringToArray(hmtx);
|
hmtx = stringToArray(hmtx);
|
||||||
createTableEntry(otf, offsets, "hmtx", hmtx);
|
createTableEntry(otf, offsets, "hmtx", hmtx);
|
||||||
|
|
||||||
/** MAXP */
|
/** MAXP */
|
||||||
maxp = "\x00\x00\x50\x00" + // Version number
|
maxp = "\x00\x00\x50\x00" + // Version number
|
||||||
string16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...)
|
string16(charstrings.length + 1); // Num of glyphs
|
||||||
maxp = stringToArray(maxp);
|
maxp = stringToArray(maxp);
|
||||||
createTableEntry(otf, offsets, "maxp", maxp);
|
createTableEntry(otf, offsets, "maxp", maxp);
|
||||||
|
|
||||||
/** NAME */
|
/** NAME */
|
||||||
name = stringToArray(createNameTable(name));
|
name = stringToArray(createNameTable(fontName));
|
||||||
createTableEntry(otf, offsets, "name", name);
|
createTableEntry(otf, offsets, "name", name);
|
||||||
|
|
||||||
/** POST */
|
/** POST */
|
||||||
@ -778,9 +1004,18 @@ var Font = (function () {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
bindDOM: function font_bindDom(data) {
|
bindDOM: function font_bindDom(data, callback) {
|
||||||
var fontName = this.name;
|
var fontName = this.name;
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
var style = 'font-family:"' + name +
|
||||||
|
'";position: absolute;top:-99999;left:-99999;z-index:-99999';
|
||||||
|
div.setAttribute("style", style);
|
||||||
|
document.body.appendChild(div);
|
||||||
|
|
||||||
/** Hack begin */
|
/** Hack begin */
|
||||||
// Actually there is not event when a font has finished downloading so
|
// 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
|
// the following code are a dirty hack to 'guess' when a font is ready
|
||||||
@ -800,15 +1035,19 @@ var Font = (function () {
|
|||||||
|
|
||||||
// For some reasons the font has not loaded, so mark it loaded for the
|
// For some reasons the font has not loaded, so mark it loaded for the
|
||||||
// page to proceed but cry
|
// page to proceed but cry
|
||||||
if ((Date.now() - this.start) >= kMaxWaitForFontFace) {
|
if (textWidth == ctx.measureText(testString).width) {
|
||||||
window.clearInterval(interval);
|
if ((Date.now() - this.start) < kMaxWaitForFontFace) {
|
||||||
Fonts[fontName].loading = false;
|
return;
|
||||||
warn("Is " + fontName + " loaded?");
|
} else {
|
||||||
this.start = 0;
|
warn("Is " + fontName + " loaded?");
|
||||||
} else if (textWidth != ctx.measureText(testString).width) {
|
}
|
||||||
window.clearInterval(interval);
|
}
|
||||||
Fonts[fontName].loading = false;
|
|
||||||
this.start = 0;
|
window.clearInterval(interval);
|
||||||
|
Fonts.lookup(fontName).loading = false;
|
||||||
|
this.start = 0;
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
}, 30, this);
|
}, 30, this);
|
||||||
|
|
||||||
@ -839,7 +1078,7 @@ var FontsUtils = {
|
|||||||
bytes.set([value]);
|
bytes.set([value]);
|
||||||
return bytes[0];
|
return bytes[0];
|
||||||
} else if (bytesCount == 2) {
|
} else if (bytesCount == 2) {
|
||||||
bytes.set([value >> 8, value]);
|
bytes.set([value >> 8, value & 0xff]);
|
||||||
return [bytes[0], bytes[1]];
|
return [bytes[0], bytes[1]];
|
||||||
} else if (bytesCount == 4) {
|
} else if (bytesCount == 4) {
|
||||||
bytes.set([value >> 24, value >> 16, value >> 8, value]);
|
bytes.set([value >> 24, value >> 16, value >> 8, value]);
|
||||||
@ -980,16 +1219,8 @@ var Type1Parser = function() {
|
|||||||
"12": "div",
|
"12": "div",
|
||||||
|
|
||||||
// callothersubr is a mechanism to make calls on the postscript
|
// callothersubr is a mechanism to make calls on the postscript
|
||||||
// interpreter.
|
// interpreter, this is not supported by Type2 charstring but hopefully
|
||||||
// TODO When decodeCharstring encounter such a command it should
|
// most of the default commands can be ignored safely.
|
||||||
// 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",
|
"16": "callothersubr",
|
||||||
|
|
||||||
"17": "pop",
|
"17": "pop",
|
||||||
@ -1009,8 +1240,13 @@ var Type1Parser = function() {
|
|||||||
"31": "hvcurveto"
|
"31": "hvcurveto"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var kEscapeCommand = 12;
|
||||||
|
|
||||||
function decodeCharString(array) {
|
function decodeCharString(array) {
|
||||||
var charString = [];
|
var charstring = [];
|
||||||
|
var lsb = 0;
|
||||||
|
var width = 0;
|
||||||
|
var used = false;
|
||||||
|
|
||||||
var value = "";
|
var value = "";
|
||||||
var count = array.length;
|
var count = array.length;
|
||||||
@ -1019,10 +1255,48 @@ var Type1Parser = function() {
|
|||||||
|
|
||||||
if (value < 32) {
|
if (value < 32) {
|
||||||
var command = null;
|
var command = null;
|
||||||
if (value == 12) {
|
if (value == kEscapeCommand) {
|
||||||
var escape = array[++i];
|
var escape = array[++i];
|
||||||
|
|
||||||
|
// TODO Clean this code
|
||||||
|
if (escape == 16) {
|
||||||
|
var index = charstring.pop();
|
||||||
|
var argc = charstring.pop();
|
||||||
|
var data = charstring.pop();
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the same things about hint replacement, if it is not used
|
||||||
|
// entry 3 can be replaced by {3}
|
||||||
|
if (index == 3) {
|
||||||
|
charstring.push(3);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
command = charStringDictionary["12"][escape];
|
command = charStringDictionary["12"][escape];
|
||||||
} else {
|
} else {
|
||||||
|
// TODO Clean this code
|
||||||
|
if (value == 13) {
|
||||||
|
if (charstring.length == 2) {
|
||||||
|
width = charstring[1];
|
||||||
|
} else if (charstring.length == 4 && charstring[3] == "div") {
|
||||||
|
width = charstring[1] / charstring[2];
|
||||||
|
} else {
|
||||||
|
error("Unsupported hsbw format: " + charstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
lsb = charstring[0];
|
||||||
|
charstring.push(lsb, "hmoveto");
|
||||||
|
charstring.splice(0, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
command = charStringDictionary[value];
|
command = charStringDictionary[value];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,16 +1318,14 @@ var Type1Parser = function() {
|
|||||||
} else if (value <= 254) {
|
} else if (value <= 254) {
|
||||||
value = -((value - 251) * 256) - parseInt(array[++i]) - 108;
|
value = -((value - 251) * 256) - parseInt(array[++i]) - 108;
|
||||||
} else {
|
} else {
|
||||||
var byte = array[++i];
|
value = (array[++i] & 0xff) << 24 | (array[++i] & 0xff) << 16 |
|
||||||
var high = (byte >> 1);
|
(array[++i] & 0xff) << 8 | (array[++i] & 0xff) << 0;
|
||||||
value = (byte - high) << 24 | array[++i] << 16 |
|
|
||||||
array[++i] << 8 | array[++i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
charString.push(value);
|
charstring.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return charString;
|
return { charstring: charstring, width: width, lsb: lsb };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1080,19 +1352,21 @@ var Type1Parser = function() {
|
|||||||
length = parseInt(length);
|
length = parseInt(length);
|
||||||
var data = eexecString.slice(i + 3, i + 3 + length);
|
var data = eexecString.slice(i + 3, i + 3 + length);
|
||||||
var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4);
|
var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4);
|
||||||
var subr = decodeCharString(encodedSubr);
|
var str = decodeCharString(encodedSubr);
|
||||||
|
|
||||||
subrs.push(subr);
|
subrs.push(str.charstring);
|
||||||
i += 3 + length;
|
i += 3 + length;
|
||||||
} else if (inGlyphs && c == 0x52) {
|
} else if (inGlyphs && c == 0x52) {
|
||||||
length = parseInt(length);
|
length = parseInt(length);
|
||||||
var data = eexecString.slice(i + 3, i + 3 + length);
|
var data = eexecString.slice(i + 3, i + 3 + length);
|
||||||
var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4);
|
var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4);
|
||||||
var subr = decodeCharString(encodedCharstring);
|
var str = decodeCharString(encodedCharstring);
|
||||||
|
|
||||||
glyphs.push({
|
glyphs.push({
|
||||||
glyph: glyph,
|
glyph: glyph,
|
||||||
data: subr
|
data: str.charstring,
|
||||||
|
lsb: str.lsb,
|
||||||
|
width: str.width
|
||||||
});
|
});
|
||||||
i += 3 + length;
|
i += 3 + length;
|
||||||
} else if (inGlyphs && c == 0x2F) {
|
} else if (inGlyphs && c == 0x2F) {
|
||||||
@ -1254,16 +1528,18 @@ CFF.prototype = {
|
|||||||
var charstrings = [];
|
var charstrings = [];
|
||||||
|
|
||||||
for (var i = 0; i < glyphs.length; i++) {
|
for (var i = 0; i < glyphs.length; i++) {
|
||||||
var glyph = glyphs[i].glyph;
|
var glyph = glyphs[i];
|
||||||
var unicode = GlyphsUnicode[glyph];
|
var unicode = GlyphsUnicode[glyph.glyph];
|
||||||
if (!unicode) {
|
if (!unicode) {
|
||||||
if (glyph != ".notdef")
|
if (glyph.glyph != ".notdef")
|
||||||
warn(glyph + " does not have an entry in the glyphs unicode dictionary");
|
warn(glyph + " does not have an entry in the glyphs unicode dictionary");
|
||||||
} else {
|
} else {
|
||||||
charstrings.push({
|
charstrings.push({
|
||||||
glyph: glyph,
|
glyph: glyph,
|
||||||
unicode: unicode,
|
unicode: unicode,
|
||||||
charstring: glyphs[i].data
|
charstring: glyph.data,
|
||||||
|
width: glyph.width,
|
||||||
|
lsb: glyph.lsb
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1305,46 +1581,11 @@ CFF.prototype = {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
var obj = charstring[i];
|
var obj = charstring[i];
|
||||||
if (obj == null)
|
if (obj == undefined) {
|
||||||
return [];
|
error("unknow charstring command for " + i + " in " + charstring);
|
||||||
|
}
|
||||||
if (obj.charAt) {
|
if (obj.charAt) {
|
||||||
switch (obj) {
|
switch (obj) {
|
||||||
case "callothersubr":
|
|
||||||
var index = charstring[i - 1];
|
|
||||||
var count = charstring[i - 2];
|
|
||||||
var data = charstring[i - 3];
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, 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;
|
|
||||||
|
|
||||||
case "hsbw":
|
|
||||||
var charWidthVector = charstring[1];
|
|
||||||
var leftSidebearing = charstring[0];
|
|
||||||
|
|
||||||
charstring.splice(i, 1, leftSidebearing, "hmoveto");
|
|
||||||
charstring.splice(0, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "endchar":
|
case "endchar":
|
||||||
case "return":
|
case "return":
|
||||||
// CharString is ready to be re-encode to commands number at this point
|
// CharString is ready to be re-encode to commands number at this point
|
||||||
@ -1356,7 +1597,7 @@ CFF.prototype = {
|
|||||||
} else if (command.charAt) {
|
} else if (command.charAt) {
|
||||||
var cmd = this.commandsMap[command];
|
var cmd = this.commandsMap[command];
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
error(command);
|
error("Unknow command: " + command);
|
||||||
|
|
||||||
if (IsArray(cmd)) {
|
if (IsArray(cmd)) {
|
||||||
charstring.splice(j, 1, cmd[0], cmd[1]);
|
charstring.splice(j, 1, cmd[0], cmd[1]);
|
||||||
@ -1428,7 +1669,7 @@ CFF.prototype = {
|
|||||||
charset.push(bytes[1]);
|
charset.push(bytes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var charstringsIndex = this.createCFFIndexHeader([[0x40, 0x0E]].concat(glyphs), true);
|
var charstringsIndex = this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true);
|
||||||
|
|
||||||
//Top Dict Index
|
//Top Dict Index
|
||||||
var topDictIndex = [
|
var topDictIndex = [
|
||||||
|
@ -181,7 +181,7 @@ span {
|
|||||||
width: 200px;
|
width: 200px;
|
||||||
top: 62px;
|
top: 62px;
|
||||||
bottom: 18px;
|
bottom: 18px;
|
||||||
left: -170px;
|
left: -140px;
|
||||||
transition: left 0.25s ease-in-out 1s;
|
transition: left 0.25s ease-in-out 1s;
|
||||||
-moz-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;
|
-webkit-transition: left 0.25s ease-in-out 1s;
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
<select id="scaleSelect">
|
<select id="scaleSelect">
|
||||||
<option value="50">50%</option>
|
<option value="50">50%</option>
|
||||||
<option value="75">75%</option>
|
<option value="75">75%</option>
|
||||||
<option value="100" selected="selected">100%</option>
|
<option value="100">100%</option>
|
||||||
<option value="125">125%</option>
|
<option value="125">125%</option>
|
||||||
<option value="150">150%</option>
|
<option value="150" selected="selected">150%</option>
|
||||||
<option value="200">200%</option>
|
<option value="200">200%</option>
|
||||||
</select>
|
</select>
|
||||||
<span class="label">Zoom</span>
|
<span class="label">Zoom</span>
|
||||||
|
@ -29,11 +29,15 @@ var PDFViewer = {
|
|||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
|
|
||||||
pageWidth: function(page) {
|
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) {
|
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: [],
|
lastPagesDrawn: [],
|
||||||
@ -106,10 +110,11 @@ var PDFViewer = {
|
|||||||
canvas.id = 'thumbnail' + num;
|
canvas.id = 'thumbnail' + num;
|
||||||
canvas.mozOpaque = true;
|
canvas.mozOpaque = true;
|
||||||
|
|
||||||
// Canvas dimensions must be specified in CSS pixels. CSS pixels
|
var pageWidth = PDFViewer.pageWidth(page);
|
||||||
// are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi.
|
var pageHeight = PDFViewer.pageHeight(page);
|
||||||
canvas.width = 104;
|
var thumbScale = Math.min(104 / pageWidth, 134 / pageHeight);
|
||||||
canvas.height = 134;
|
canvas.width = pageWidth * thumbScale;
|
||||||
|
canvas.height = pageHeight * thumbScale;
|
||||||
div.appendChild(canvas);
|
div.appendChild(canvas);
|
||||||
|
|
||||||
var ctx = canvas.getContext('2d');
|
var ctx = canvas.getContext('2d');
|
||||||
@ -175,8 +180,6 @@ var PDFViewer = {
|
|||||||
canvas.id = 'page' + num;
|
canvas.id = 'page' + num;
|
||||||
canvas.mozOpaque = true;
|
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.width = PDFViewer.pageWidth(page);
|
||||||
canvas.height = PDFViewer.pageHeight(page);
|
canvas.height = PDFViewer.pageHeight(page);
|
||||||
div.appendChild(canvas);
|
div.appendChild(canvas);
|
||||||
@ -216,7 +219,6 @@ var PDFViewer = {
|
|||||||
|
|
||||||
if (PDFViewer.pdf) {
|
if (PDFViewer.pdf) {
|
||||||
for (i = 1; i <= PDFViewer.numberOfPages; i++) {
|
for (i = 1; i <= PDFViewer.numberOfPages; i++) {
|
||||||
PDFViewer.createThumbnail(i);
|
|
||||||
PDFViewer.createPage(i);
|
PDFViewer.createPage(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +251,10 @@ var PDFViewer = {
|
|||||||
PDFViewer.pageNumber = num;
|
PDFViewer.pageNumber = num;
|
||||||
PDFViewer.pageNumberInput.value = PDFViewer.pageNumber;
|
PDFViewer.pageNumberInput.value = PDFViewer.pageNumber;
|
||||||
PDFViewer.willJumpToPage = true;
|
PDFViewer.willJumpToPage = true;
|
||||||
|
|
||||||
|
if (document.location.hash.substr(1) == PDFViewer.pageNumber)
|
||||||
|
// Force a "scroll event" to redraw
|
||||||
|
setTimeout(window.onscroll, 0);
|
||||||
document.location.hash = PDFViewer.pageNumber;
|
document.location.hash = PDFViewer.pageNumber;
|
||||||
|
|
||||||
PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
|
PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
|
||||||
@ -272,6 +277,12 @@ var PDFViewer = {
|
|||||||
openURL: function(url) {
|
openURL: function(url) {
|
||||||
PDFViewer.url = url;
|
PDFViewer.url = url;
|
||||||
document.title = url;
|
document.title = url;
|
||||||
|
|
||||||
|
if (this.thumbsLoadingInterval) {
|
||||||
|
// cancel thumbs loading operations
|
||||||
|
clearInterval(this.thumbsLoadingInterval);
|
||||||
|
this.thumbsLoadingInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.open('GET', url);
|
req.open('GET', url);
|
||||||
@ -288,7 +299,9 @@ var PDFViewer = {
|
|||||||
|
|
||||||
req.send(null);
|
req.send(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
thumbsLoadingInterval: null,
|
||||||
|
|
||||||
readPDF: function(data) {
|
readPDF: function(data) {
|
||||||
while (PDFViewer.element.hasChildNodes()) {
|
while (PDFViewer.element.hasChildNodes()) {
|
||||||
PDFViewer.element.removeChild(PDFViewer.element.firstChild);
|
PDFViewer.element.removeChild(PDFViewer.element.firstChild);
|
||||||
@ -310,12 +323,22 @@ var PDFViewer = {
|
|||||||
PDFViewer.drawPage(1);
|
PDFViewer.drawPage(1);
|
||||||
document.location.hash = 1;
|
document.location.hash = 1;
|
||||||
|
|
||||||
setTimeout(function() {
|
// slowly loading the thumbs (few per second)
|
||||||
for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
|
// first time we are loading more images than subsequent
|
||||||
PDFViewer.createThumbnail(i);
|
var currentPageIndex = 1, imagesToLoad = 15;
|
||||||
PDFViewer.drawThumbnail(i);
|
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' : '';
|
PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
|
||||||
|
24
pdf.js
24
pdf.js
@ -641,7 +641,7 @@ var PredictorStream = (function() {
|
|||||||
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3;
|
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3;
|
||||||
// add an extra pixByte to represent the pixel left of column 0
|
// add an extra pixByte to represent the pixel left of column 0
|
||||||
var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3;
|
var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3;
|
||||||
|
|
||||||
DecodeStream.call(this);
|
DecodeStream.call(this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -3440,6 +3440,7 @@ var CanvasGraphics = (function() {
|
|||||||
if (charset) {
|
if (charset) {
|
||||||
assertWellFormed(IsString(charset), "invalid charset");
|
assertWellFormed(IsString(charset), "invalid charset");
|
||||||
charset = charset.split("/");
|
charset = charset.split("/");
|
||||||
|
charset.shift();
|
||||||
}
|
}
|
||||||
} else if (IsName(encoding)) {
|
} else if (IsName(encoding)) {
|
||||||
var encoding = Encodings[encoding.name];
|
var encoding = Encodings[encoding.name];
|
||||||
@ -3534,13 +3535,16 @@ var CanvasGraphics = (function() {
|
|||||||
type: subType.name,
|
type: subType.name,
|
||||||
encoding: encodingMap,
|
encoding: encodingMap,
|
||||||
charset: charset,
|
charset: charset,
|
||||||
|
firstChar: fontDict.get("FirstChar"),
|
||||||
|
lastChar: fontDict.get("LastChar"),
|
||||||
bbox: descriptor.get("FontBBox"),
|
bbox: descriptor.get("FontBBox"),
|
||||||
ascent: descriptor.get("Ascent"),
|
ascent: descriptor.get("Ascent"),
|
||||||
descent: descriptor.get("Descent"),
|
descent: descriptor.get("Descent"),
|
||||||
xHeight: descriptor.get("XHeight"),
|
xHeight: descriptor.get("XHeight"),
|
||||||
capHeight: descriptor.get("CapHeight"),
|
capHeight: descriptor.get("CapHeight"),
|
||||||
flags: descriptor.get("Flags"),
|
flags: descriptor.get("Flags"),
|
||||||
italicAngle: descriptor.get("ItalicAngle")
|
italicAngle: descriptor.get("ItalicAngle"),
|
||||||
|
fixedPitch: false
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -3807,18 +3811,22 @@ var CanvasGraphics = (function() {
|
|||||||
if (fontDescriptor && fontDescriptor.num) {
|
if (fontDescriptor && fontDescriptor.num) {
|
||||||
var fontDescriptor = this.xref.fetchIfRef(fontDescriptor);
|
var fontDescriptor = this.xref.fetchIfRef(fontDescriptor);
|
||||||
fontName = fontDescriptor.get("FontName").name.replace("+", "_");
|
fontName = fontDescriptor.get("FontName").name.replace("+", "_");
|
||||||
Fonts.active = fontName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fontName) {
|
if (!fontName) {
|
||||||
// TODO: fontDescriptor is not available, fallback to default font
|
// TODO: fontDescriptor is not available, fallback to default font
|
||||||
this.current.fontSize = size;
|
fontName = "sans-serif";
|
||||||
this.ctx.font = this.current.fontSize + 'px sans-serif';
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.current.fontName = fontName;
|
||||||
this.current.fontSize = size;
|
this.current.fontSize = size;
|
||||||
this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol';
|
|
||||||
|
if (this.ctx.$setFont) {
|
||||||
|
this.ctx.$setFont(fontName, size);
|
||||||
|
} else {
|
||||||
|
this.ctx.font = size + 'px "' + fontName + '"';
|
||||||
|
Fonts.setActive(fontName, size);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setTextRenderingMode: function(mode) {
|
setTextRenderingMode: function(mode) {
|
||||||
TODO("text rendering mode");
|
TODO("text rendering mode");
|
||||||
@ -3862,7 +3870,7 @@ var CanvasGraphics = (function() {
|
|||||||
text = Fonts.charsToUnicode(text);
|
text = Fonts.charsToUnicode(text);
|
||||||
this.ctx.translate(this.current.x, -1 * this.current.y);
|
this.ctx.translate(this.current.x, -1 * this.current.y);
|
||||||
this.ctx.fillText(text, 0, 0);
|
this.ctx.fillText(text, 0, 0);
|
||||||
this.current.x += this.ctx.measureText(text).width;
|
this.current.x += Fonts.measureText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<style type="text/css"></style>
|
<style type="text/css"></style>
|
||||||
<script type="text/javascript" src="/pdf.js"></script>
|
<script type="text/javascript" src="/pdf.js"></script>
|
||||||
<script type="text/javascript" src="/fonts.js"></script>
|
<script type="text/javascript" src="/fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="/crypto.js"></script>
|
||||||
<script type="text/javascript" src="/glyphlist.js"></script>
|
<script type="text/javascript" src="/glyphlist.js"></script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
var appPath, browser, canvas, currentTask, currentTaskIdx, failure, manifest, numPages, pdfDoc, stdout;
|
var appPath, browser, canvas, currentTask, currentTaskIdx, failure, manifest, numPages, pdfDoc, stdout;
|
||||||
@ -103,11 +104,12 @@ function nextPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||||
// using mediaBox for the canvas size
|
// using mediaBox for the canvas size
|
||||||
var wTwips = (currentPage.mediaBox[2] - currentPage.mediaBox[0]);
|
var pageWidth = (currentPage.mediaBox[2] - currentPage.mediaBox[0]);
|
||||||
var hTwips = (currentPage.mediaBox[3] - currentPage.mediaBox[1]);
|
var pageHeight = (currentPage.mediaBox[3] - currentPage.mediaBox[1]);
|
||||||
canvas.width = wTwips * 96.0 / 72.0;
|
canvas.width = pageWidth * pdfToCssUnitsCoef;
|
||||||
canvas.height = hTwips * 96.0 / 72.0;
|
canvas.height = pageHeight * pdfToCssUnitsCoef;
|
||||||
clear(ctx);
|
clear(ctx);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
failure = 'page setup: '+ e.toString();
|
failure = 'page setup: '+ e.toString();
|
||||||
|
@ -24,10 +24,11 @@ span#info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#viewer {
|
#viewer {
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border: 1px solid black;
|
display: block;
|
||||||
width: 12.75in;
|
|
||||||
height: 16.5in;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pageNumber {
|
#pageNumber {
|
||||||
|
@ -25,9 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="viewer">
|
<div id="viewer">
|
||||||
<!-- Canvas dimensions must be specified in CSS pixels. CSS pixels
|
<canvas id="canvas"></canvas>
|
||||||
are always 96 dpi. 816x1056 is 8.5x11in at 96dpi. -->
|
|
||||||
<canvas id="canvas" width="816" height="1056" defaultwidth="816" defaultheight="1056"></canvas>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
10
viewer.js
10
viewer.js
@ -60,12 +60,12 @@ function displayPage(num) {
|
|||||||
var t0 = Date.now();
|
var t0 = Date.now();
|
||||||
|
|
||||||
var page = pdfDocument.getPage(pageNum = num);
|
var page = pdfDocument.getPage(pageNum = num);
|
||||||
canvas.width = parseInt(canvas.getAttribute("defaultwidth")) * pageScale;
|
|
||||||
canvas.height = parseInt(canvas.getAttribute("defaultheight")) * pageScale;
|
|
||||||
|
|
||||||
// scale canvas by 2
|
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||||
canvas.width = 2 * page.mediaBox[2];
|
var pageWidth = (page.mediaBox[2] - page.mediaBox[0]);
|
||||||
canvas.hieght = 2 * page.mediaBox[3];
|
var pageHeight = (page.mediaBox[3] - page.mediaBox[1]);
|
||||||
|
canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef;
|
||||||
|
canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef;
|
||||||
|
|
||||||
var t1 = Date.now();
|
var t1 = Date.now();
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Simple pdf.js page worker viewer</title>
|
<title>Simple pdf.js page worker viewer</title>
|
||||||
<script type="text/javascript" src="worker_client.js"></script>
|
<script type="text/javascript" src="fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="glyphlist.js"></script>
|
||||||
|
<script type="text/javascript" src="pdf.js"></script>
|
||||||
|
<script type="text/javascript" src="worker/client.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
@ -36,10 +39,7 @@ window.onload = function() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="viewer">
|
<div id="viewer">
|
||||||
<!-- Canvas dimensions must be specified in CSS pixels. CSS pixels
|
<canvas id="canvas"></canvas>
|
||||||
are always 96 dpi. 816x1056 is 8.5x11in at 96dpi. -->
|
|
||||||
<!-- We're rendering here at 1.5x scale. -->
|
|
||||||
<canvas id="canvas" width="1224" height="1584"></canvas>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -119,7 +119,8 @@ function CanvasProxy(width, height) {
|
|||||||
"$addCurrentX",
|
"$addCurrentX",
|
||||||
"$saveCurrentX",
|
"$saveCurrentX",
|
||||||
"$restoreCurrentX",
|
"$restoreCurrentX",
|
||||||
"$showText"
|
"$showText",
|
||||||
|
"$setFont"
|
||||||
];
|
];
|
||||||
|
|
||||||
function buildFuncCall(name) {
|
function buildFuncCall(name) {
|
@ -18,12 +18,115 @@ if (typeof console.time == "undefined") {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FontWorker() {
|
||||||
|
this.worker = new Worker("worker/font.js");
|
||||||
|
this.fontsWaiting = 0;
|
||||||
|
this.fontsWaitingCallbacks = [];
|
||||||
|
|
||||||
|
// Listen to the WebWorker for data and call actionHandler on it.
|
||||||
|
this.worker.onmessage = function(event) {
|
||||||
|
var data = event.data;
|
||||||
|
var actionHandler = this.actionHandler
|
||||||
|
if (data.action in actionHandler) {
|
||||||
|
actionHandler[data.action].call(this, data.data);
|
||||||
|
} else {
|
||||||
|
throw "Unkown action from worker: " + data.action;
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
this.$handleFontLoadedCallback = this.handleFontLoadedCallback.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontWorker.prototype = {
|
||||||
|
handleFontLoadedCallback: function() {
|
||||||
|
// Decrease the number of fonts wainting to be loaded.
|
||||||
|
this.fontsWaiting--;
|
||||||
|
// If all fonts are available now, then call all the callbacks.
|
||||||
|
if (this.fontsWaiting == 0) {
|
||||||
|
var callbacks = this.fontsWaitingCallbacks;
|
||||||
|
for (var i = 0; i < callbacks.length; i++) {
|
||||||
|
callbacks[i]();
|
||||||
|
}
|
||||||
|
this.fontsWaitingCallbacks.length = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actionHandler: {
|
||||||
|
"log": function(data) {
|
||||||
|
console.log.apply(console, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
"fonts": function(data) {
|
||||||
|
// console.log("got processed fonts from worker", Object.keys(data));
|
||||||
|
for (name in data) {
|
||||||
|
// Update the encoding property.
|
||||||
|
var font = Fonts.lookup(name);
|
||||||
|
font.properties = {
|
||||||
|
encoding: data[name].encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call `Font.prototype.bindDOM` to make the font get loaded on the page.
|
||||||
|
Font.prototype.bindDOM.call(
|
||||||
|
font,
|
||||||
|
data[name].str,
|
||||||
|
// IsLoadedCallback.
|
||||||
|
this.$handleFontLoadedCallback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ensureFonts: function(data, callback) {
|
||||||
|
var font;
|
||||||
|
var notLoaded = [];
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
font = data[i];
|
||||||
|
if (Fonts[font.name]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the font but don't pass in any real data. The idea is to
|
||||||
|
// store as less data as possible to reduce memory usage.
|
||||||
|
Fonts.registerFont(font.name, Object.create(null), Object.create(null));
|
||||||
|
|
||||||
|
// Mark this font to be handled later.
|
||||||
|
notLoaded.push(font);
|
||||||
|
// Increate the number of fonts to wait for.
|
||||||
|
this.fontsWaiting++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.time("ensureFonts");
|
||||||
|
// If there are fonts, that need to get loaded, tell the FontWorker to get
|
||||||
|
// started and push the callback on the waiting-callback-stack.
|
||||||
|
if (notLoaded.length != 0) {
|
||||||
|
console.log("fonts -> FontWorker");
|
||||||
|
// Send the worker the fonts to work on.
|
||||||
|
this.worker.postMessage({
|
||||||
|
action: "fonts",
|
||||||
|
data: notLoaded
|
||||||
|
});
|
||||||
|
if (callback) {
|
||||||
|
this.fontsWaitingCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All fonts are present? Well, then just call the callback if there is one.
|
||||||
|
else {
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
function WorkerPDFDoc(canvas) {
|
function WorkerPDFDoc(canvas) {
|
||||||
var timer = null
|
var timer = null
|
||||||
|
|
||||||
this.ctx = canvas.getContext("2d");
|
this.ctx = canvas.getContext("2d");
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.worker = new Worker('pdf_worker.js');
|
this.worker = new Worker('worker/pdf.js');
|
||||||
|
this.fontWorker = new FontWorker();
|
||||||
|
this.waitingForFonts = false;
|
||||||
|
this.waitingForFontsCallback = [];
|
||||||
|
|
||||||
this.numPage = 1;
|
this.numPage = 1;
|
||||||
this.numPages = null;
|
this.numPages = null;
|
||||||
@ -56,6 +159,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
"$showText": function(y, text) {
|
"$showText": function(y, text) {
|
||||||
|
text = Fonts.charsToUnicode(text);
|
||||||
this.translate(currentX, -1 * y);
|
this.translate(currentX, -1 * y);
|
||||||
this.fillText(text, 0, 0);
|
this.fillText(text, 0, 0);
|
||||||
currentX += this.measureText(text).width;
|
currentX += this.measureText(text).width;
|
||||||
@ -136,6 +240,11 @@ function WorkerPDFDoc(canvas) {
|
|||||||
throw "Pattern not found";
|
throw "Pattern not found";
|
||||||
}
|
}
|
||||||
this.strokeStyle = pattern;
|
this.strokeStyle = pattern;
|
||||||
|
},
|
||||||
|
|
||||||
|
"$setFont": function(name, size) {
|
||||||
|
this.font = size + 'px "' + name + '"';
|
||||||
|
Fonts.setActive(name, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +296,25 @@ function WorkerPDFDoc(canvas) {
|
|||||||
div.setAttribute("style", style);
|
div.setAttribute("style", style);
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"setup_page": function(data) {
|
||||||
|
var size = data.split(",");
|
||||||
|
var canvas = this.canvas, ctx = this.ctx;
|
||||||
|
canvas.width = parseInt(size[0]);
|
||||||
|
canvas.height = parseInt(size[1]);
|
||||||
|
},
|
||||||
|
|
||||||
|
"fonts": function(data) {
|
||||||
|
this.waitingForFonts = true;
|
||||||
|
this.fontWorker.ensureFonts(data, function() {
|
||||||
|
this.waitingForFonts = false;
|
||||||
|
var callbacks = this.waitingForFontsCallback;
|
||||||
|
for (var i = 0; i < callbacks.length; i++) {
|
||||||
|
callbacks[i]();
|
||||||
|
}
|
||||||
|
this.waitingForFontsCallback.length = 0;
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
"jpeg_stream": function(data) {
|
"jpeg_stream": function(data) {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
@ -207,11 +335,9 @@ function WorkerPDFDoc(canvas) {
|
|||||||
canvasList[id] = newCanvas;
|
canvasList[id] = newCanvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There might be fonts that need to get loaded. Shedule the
|
var renderData = function() {
|
||||||
// rendering at the end of the event queue ensures this.
|
|
||||||
setTimeout(function() {
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
console.time("canvas rendering");
|
console.time("main canvas rendering");
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||||
@ -219,12 +345,27 @@ function WorkerPDFDoc(canvas) {
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
renderProxyCanvas(canvasList[id], cmdQueue);
|
renderProxyCanvas(canvasList[id], cmdQueue);
|
||||||
if (id == 0) console.timeEnd("canvas rendering")
|
if (id == 0) {
|
||||||
}, 0, this);
|
console.timeEnd("main canvas rendering");
|
||||||
|
console.timeEnd(">>> total page display time:");
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
if (this.waitingForFonts) {
|
||||||
|
if (id == 0) {
|
||||||
|
console.log("want to render, but not all fonts are there", id);
|
||||||
|
this.waitingForFontsCallback.push(renderData);
|
||||||
|
} else {
|
||||||
|
// console.log("assume canvas doesn't have fonts", id);
|
||||||
|
renderData();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
renderData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List to the WebWorker for data and call actionHandler on it.
|
// Listen to the WebWorker for data and call actionHandler on it.
|
||||||
this.worker.onmessage = function(event) {
|
this.worker.onmessage = function(event) {
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
if (data.action in actionHandler) {
|
if (data.action in actionHandler) {
|
||||||
@ -232,7 +373,7 @@ function WorkerPDFDoc(canvas) {
|
|||||||
} else {
|
} else {
|
||||||
throw "Unkown action from worker: " + data.action;
|
throw "Unkown action from worker: " + data.action;
|
||||||
}
|
}
|
||||||
}
|
}.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkerPDFDoc.prototype.open = function(url, callback) {
|
WorkerPDFDoc.prototype.open = function(url, callback) {
|
||||||
@ -255,6 +396,8 @@ WorkerPDFDoc.prototype.open = function(url, callback) {
|
|||||||
|
|
||||||
WorkerPDFDoc.prototype.showPage = function(numPage) {
|
WorkerPDFDoc.prototype.showPage = function(numPage) {
|
||||||
this.numPage = parseInt(numPage);
|
this.numPage = parseInt(numPage);
|
||||||
|
console.log("=== start rendering page " + numPage + " ===");
|
||||||
|
console.time(">>> total page display time:");
|
||||||
this.worker.postMessage(numPage);
|
this.worker.postMessage(numPage);
|
||||||
if (this.onChangePage) {
|
if (this.onChangePage) {
|
||||||
this.onChangePage(numPage);
|
this.onChangePage(numPage);
|
27
worker/console.js
Normal file
27
worker/console.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* -*- 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 consoleTimer = {};
|
||||||
|
var console = {
|
||||||
|
log: function log() {
|
||||||
|
var args = Array.prototype.slice.call(arguments);
|
||||||
|
postMessage({
|
||||||
|
action: "log",
|
||||||
|
data: args
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
time: function(name) {
|
||||||
|
consoleTimer[name] = Date.now();
|
||||||
|
},
|
||||||
|
|
||||||
|
timeEnd: function(name) {
|
||||||
|
var time = consoleTimer[name];
|
||||||
|
if (time == null) {
|
||||||
|
throw "Unkown timer name " + name;
|
||||||
|
}
|
||||||
|
this.log("Timer:", name, Date.now() - time);
|
||||||
|
}
|
||||||
|
}
|
65
worker/font.js
Normal file
65
worker/font.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
importScripts("console.js");
|
||||||
|
|
||||||
|
importScripts("../pdf.js");
|
||||||
|
importScripts("../fonts.js");
|
||||||
|
importScripts("../glyphlist.js")
|
||||||
|
|
||||||
|
function fontDataToString(font) {
|
||||||
|
// Doing postMessage on objects make them lose their "shape". This adds the
|
||||||
|
// "shape" for all required objects agains, such that the encoding works as
|
||||||
|
// expected.
|
||||||
|
var fontFileDict = new Dict();
|
||||||
|
fontFileDict.map = font.file.dict.map;
|
||||||
|
|
||||||
|
var fontFile = new Stream(font.file.bytes, font.file.start, font.file.end - font.file.start, fontFileDict);
|
||||||
|
font.file = new FlateStream(fontFile);
|
||||||
|
|
||||||
|
// This will encode the font.
|
||||||
|
var fontObj = new Font(font.name, font.file, font.properties);
|
||||||
|
|
||||||
|
// Create string that is used for css later.
|
||||||
|
var str = "";
|
||||||
|
var data = fontObj.data;
|
||||||
|
var length = data.length;
|
||||||
|
for (var j = 0; j < length; j++)
|
||||||
|
str += String.fromCharCode(data[j]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
str: str,
|
||||||
|
encoding: font.properties.encoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to handle data sent by the MainThread.
|
||||||
|
*/
|
||||||
|
var actionHandler = {
|
||||||
|
"fonts": function(data) {
|
||||||
|
var fontData;
|
||||||
|
var result = {};
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
fontData = data[i];
|
||||||
|
result[fontData.name] = fontDataToString(fontData);
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage({
|
||||||
|
action: "fonts",
|
||||||
|
data: result
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen to the MainThread for data and call actionHandler on it.
|
||||||
|
this.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;
|
||||||
|
}
|
||||||
|
}
|
@ -27,10 +27,12 @@ var console = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
importScripts("canvas_proxy.js");
|
importScripts("console.js")
|
||||||
importScripts("pdf.js");
|
importScripts("canvas.js");
|
||||||
importScripts("fonts.js");
|
importScripts("../pdf.js");
|
||||||
importScripts("glyphlist.js")
|
importScripts("../fonts.js");
|
||||||
|
importScripts("../crypto.js");
|
||||||
|
importScripts("../glyphlist.js")
|
||||||
|
|
||||||
// Use the JpegStreamProxy proxy.
|
// Use the JpegStreamProxy proxy.
|
||||||
JpegStream = JpegStreamProxy;
|
JpegStream = JpegStreamProxy;
|
||||||
@ -58,6 +60,18 @@ onmessage = function(event) {
|
|||||||
// Let's try to render the first page...
|
// Let's try to render the first page...
|
||||||
var page = pdfDocument.getPage(parseInt(data));
|
var page = pdfDocument.getPage(parseInt(data));
|
||||||
|
|
||||||
|
var pdfToCssUnitsCoef = 96.0 / 72.0;
|
||||||
|
var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
|
||||||
|
var pageHeight = (page.mediaBox[3] - page.mediaBox[1]) * pdfToCssUnitsCoef;
|
||||||
|
postMessage({
|
||||||
|
action: "setup_page",
|
||||||
|
data: pageWidth + "," + pageHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set canvas size.
|
||||||
|
canvas.width = pageWidth;
|
||||||
|
canvas.height = pageHeight;
|
||||||
|
|
||||||
// page.compile will collect all fonts for us, once we have loaded them
|
// page.compile will collect all fonts for us, once we have loaded them
|
||||||
// we can trigger the actual page rendering with page.display
|
// we can trigger the actual page rendering with page.display
|
||||||
var fonts = [];
|
var fonts = [];
|
||||||
@ -65,21 +79,14 @@ onmessage = function(event) {
|
|||||||
page.compile(gfx, fonts);
|
page.compile(gfx, fonts);
|
||||||
console.timeEnd("compile");
|
console.timeEnd("compile");
|
||||||
|
|
||||||
|
// Send fonts to the main thread.
|
||||||
console.time("fonts");
|
console.time("fonts");
|
||||||
// Inspect fonts and translate the missing one.
|
postMessage({
|
||||||
var count = fonts.length;
|
action: "fonts",
|
||||||
for (var i = 0; i < count; i++) {
|
data: fonts
|
||||||
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);
|
|
||||||
}
|
|
||||||
console.timeEnd("fonts");
|
console.timeEnd("fonts");
|
||||||
|
|
||||||
console.time("display");
|
console.time("display");
|
||||||
page.display(gfx);
|
page.display(gfx);
|
||||||
canvas.flush();
|
canvas.flush();
|
Loading…
x
Reference in New Issue
Block a user