diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js
index 17adc3ce1cbc..60aff695be90 100644
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -645,3 +645,5 @@ pref("memory_info_dumper.watch_fifo.directory", "/data/local");
// implementation is not complete. We have to disable the
// type to web content to help them do feature detection.
pref("dom.disable_input_file", true);
+
+pref("general.useragent.enable_overrides", true);
diff --git a/b2g/chrome/content/UAO_child.js b/b2g/chrome/content/UAO_child.js
deleted file mode 100644
index 5f270d1d24c2..000000000000
--- a/b2g/chrome/content/UAO_child.js
+++ /dev/null
@@ -1,2 +0,0 @@
-Components.utils.import('resource://gre/modules/UserAgentOverrides.jsm');
-UserAgentOverrides.init();
diff --git a/b2g/chrome/jar.mn b/b2g/chrome/jar.mn
index 08f90bebfd0d..4c68df0de38f 100644
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -25,8 +25,6 @@ chrome.jar:
content/payment.js (content/payment.js)
content/identity.js (content/identity.js)
- content/UAO_child.js (content/UAO_child.js)
-
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
% override chrome://global/skin/netError.css chrome://browser/content/netError.css
% override chrome://global/skin/media/videocontrols.css chrome://browser/content/touchcontrols.css
diff --git a/b2g/components/ProcessGlobal.js b/b2g/components/ProcessGlobal.js
index df905bc80a2a..516998a26cd8 100644
--- a/b2g/components/ProcessGlobal.js
+++ b/b2g/components/ProcessGlobal.js
@@ -57,17 +57,6 @@ ProcessGlobal.prototype = {
' '));
break;
}
- case 'remote-browser-frame-shown': {
- let frameLoader = subject.QueryInterface(Ci.nsIFrameLoader);
- let mm = frameLoader.messageManager;
-
- const kFrameScript = "chrome://browser/content/UAO_child.js";
- try {
- mm.loadFrameScript(kFrameScript, true);
- } catch (e) {
- dump('Error loading ' + kFrameScript + ' as frame script: ' + e + '\n');
- }
- }
}
},
};
diff --git a/b2g/config/panda/releng-pandaboard.tt b/b2g/config/panda/releng-pandaboard.tt
index 935ed92b5a07..29f74be872ec 100644
--- a/b2g/config/panda/releng-pandaboard.tt
+++ b/b2g/config/panda/releng-pandaboard.tt
@@ -4,5 +4,11 @@
"digest": "e0b98a75831313171781d91ab4c3b8ae66e3af7fcec433a33d75fbc647cb3bba311f790ccb9cd9c8be8c5549210b759d6b85afe7395ada74c2c319a29556fd8e",
"algorithm": "sha512",
"filename": "gonk.tar.xz"
+},
+{
+"size": 2116507,
+"digest": "be67a012963a5c162834f9fcb989bcebd2d047dcb4e17ee23031b694dcf7cdfd6d7a6545d7a1f5e7293b6d24415403972f4ea1ab8c6c78fefcabfaf3f6875214",
+"algorithm": "sha512",
+"filename": "download-panda.tar.bz2"
}
]
diff --git a/browser/base/Makefile.in b/browser/base/Makefile.in
index ff343c440eed..fe129711f373 100644
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -36,7 +36,7 @@ ifneq (,$(filter windows cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
DEFINES += -DCONTEXT_COPY_IMAGE_CONTENTS=1
endif
-ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+ifneq (,$(filter windows cocoa, $(MOZ_WIDGET_TOOLKIT)))
DEFINES += -DCAN_DRAW_IN_TITLEBAR=1
endif
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index a1b1ebe18556..f684e9e6de75 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -489,6 +489,7 @@
#ifdef CAN_DRAW_IN_TITLEBAR
+#ifdef MENUBAR_CAN_AUTOHIDE
+#endif
diff --git a/browser/base/content/test/social/browser_social_chatwindow.js b/browser/base/content/test/social/browser_social_chatwindow.js
index a41263088d5b..17a7e96c0825 100644
--- a/browser/base/content/test/social/browser_social_chatwindow.js
+++ b/browser/base/content/test/social/browser_social_chatwindow.js
@@ -456,18 +456,17 @@ var tests = {
ok(!window.SocialChatBar.hasChats, "first window should start with no chats");
openChat(function() {
ok(window.SocialChatBar.hasChats, "first window has the chat");
- // create a second window - although this will be the "most recent",
- // the fact the first window has a chat open means the first will be targetted.
+ // create a second window - this will be the "most recent" and will
+ // therefore be the window that hosts the new chat (see bug 835111)
let secondWindow = OpenBrowserWindow();
secondWindow.addEventListener("load", function loadListener() {
secondWindow.removeEventListener("load", loadListener);
ok(!secondWindow.SocialChatBar.hasChats, "second window has no chats");
openChat(function() {
- ok(!secondWindow.SocialChatBar.hasChats, "second window still has no chats");
- is(window.SocialChatBar.chatbar.childElementCount, 2, "first window now has 2 chats");
+ ok(secondWindow.SocialChatBar.hasChats, "second window now has chats");
+ is(window.SocialChatBar.chatbar.childElementCount, 1, "first window still has 1 chat");
window.SocialChatBar.chatbar.removeAll();
- // now open another chat - it should open in the second window (as
- // it is the "most recent" and no other windows have chats)
+ // now open another chat - it should still open in the second.
openChat(function() {
ok(!window.SocialChatBar.hasChats, "first window has no chats");
ok(secondWindow.SocialChatBar.hasChats, "second window has a chat");
diff --git a/browser/components/downloads/content/allDownloadsViewOverlay.js b/browser/components/downloads/content/allDownloadsViewOverlay.js
index 1cd349492920..fb1fb15eb920 100644
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -1037,8 +1037,8 @@ DownloadsPlacesView.prototype = {
else {
shell.dataItem = null;
// Move it below the session-download items;
- if (this._lastSessionDownloadElement == shell.dataItem) {
- this._lastSessionDownloadElement = shell.dataItem.previousSibling;
+ if (this._lastSessionDownloadElement == shell.element) {
+ this._lastSessionDownloadElement = shell.element.previousSibling;
}
else {
let before = this._lastSessionDownloadElement ?
diff --git a/browser/config/mozconfigs/linux32/debug-asan b/browser/config/mozconfigs/linux32/debug-asan
index 34e6f9995376..4766ce2fe701 100644
--- a/browser/config/mozconfigs/linux32/debug-asan
+++ b/browser/config/mozconfigs/linux32/debug-asan
@@ -14,4 +14,7 @@ ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
+# Need this to prevent name conflicts with the normal nightly build packages
+export MOZ_PKG_SPECIAL=asan
+
. "$topsrcdir/build/mozconfig.common.override"
diff --git a/browser/config/mozconfigs/linux32/nightly-asan b/browser/config/mozconfigs/linux32/nightly-asan
index da5a39d41932..c67f0658445b 100644
--- a/browser/config/mozconfigs/linux32/nightly-asan
+++ b/browser/config/mozconfigs/linux32/nightly-asan
@@ -16,4 +16,7 @@ ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
+# Need this to prevent name conflicts with the normal nightly build packages
+export MOZ_PKG_SPECIAL=asan
+
. "$topsrcdir/build/mozconfig.common.override"
diff --git a/browser/config/mozconfigs/linux64/debug-asan b/browser/config/mozconfigs/linux64/debug-asan
index 34e6f9995376..4766ce2fe701 100644
--- a/browser/config/mozconfigs/linux64/debug-asan
+++ b/browser/config/mozconfigs/linux64/debug-asan
@@ -14,4 +14,7 @@ ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
+# Need this to prevent name conflicts with the normal nightly build packages
+export MOZ_PKG_SPECIAL=asan
+
. "$topsrcdir/build/mozconfig.common.override"
diff --git a/browser/config/mozconfigs/linux64/nightly-asan b/browser/config/mozconfigs/linux64/nightly-asan
index da5a39d41932..c67f0658445b 100644
--- a/browser/config/mozconfigs/linux64/nightly-asan
+++ b/browser/config/mozconfigs/linux64/nightly-asan
@@ -16,4 +16,7 @@ ac_add_options --enable-stdcxx-compat
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
+# Need this to prevent name conflicts with the normal nightly build packages
+export MOZ_PKG_SPECIAL=asan
+
. "$topsrcdir/build/mozconfig.common.override"
diff --git a/browser/config/mozconfigs/macosx64/debug-asan b/browser/config/mozconfigs/macosx64/debug-asan
index 846615c64fd8..97ced38c45f5 100644
--- a/browser/config/mozconfigs/macosx64/debug-asan
+++ b/browser/config/mozconfigs/macosx64/debug-asan
@@ -10,4 +10,7 @@ export MOZ_PACKAGE_JSSHELL=1
ac_add_options --with-macbundlename-prefix=Firefox
+# Need this to prevent name conflicts with the normal nightly build packages
+export MOZ_PKG_SPECIAL=asan
+
. "$topsrcdir/build/mozconfig.common.override"
diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla
index 1febf64dd150..1493ab286289 100644
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
-Current extension version is: 0.7.82
+Current extension version is: 0.7.180
diff --git a/browser/extensions/pdfjs/components/PdfStreamConverter.js b/browser/extensions/pdfjs/components/PdfStreamConverter.js
index 3a25f0df5dab..79e6a0aac61c 100644
--- a/browser/extensions/pdfjs/components/PdfStreamConverter.js
+++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js
@@ -201,9 +201,10 @@ PdfDataListener.prototype = {
};
// All the priviledged actions.
-function ChromeActions(domWindow, dataListener) {
+function ChromeActions(domWindow, dataListener, contentDispositionFilename) {
this.domWindow = domWindow;
this.dataListener = dataListener;
+ this.contentDispositionFilename = contentDispositionFilename;
}
ChromeActions.prototype = {
@@ -232,6 +233,7 @@ ChromeActions.prototype = {
return docIsPrivate;
},
download: function(data, sendResponse) {
+ var self = this;
var originalUrl = data.originalUrl;
// The data may not be downloaded so we need just retry getting the pdf with
// the original url.
@@ -259,9 +261,13 @@ ChromeActions.prototype = {
// so the filename will be correct.
let channel = Cc['@mozilla.org/network/input-stream-channel;1'].
createInstance(Ci.nsIInputStreamChannel);
+ channel.QueryInterface(Ci.nsIChannel);
+ channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
+ if (self.contentDispositionFilename) {
+ channel.contentDispositionFilename = self.contentDispositionFilename;
+ }
channel.setURI(originalUri);
channel.contentStream = aInputStream;
- channel.QueryInterface(Ci.nsIChannel);
if ('nsIPrivateBrowsingChannel' in Ci &&
channel instanceof Ci.nsIPrivateBrowsingChannel) {
channel.setPrivate(docIsPrivate);
@@ -583,6 +589,10 @@ PdfStreamConverter.prototype = {
// Creating storage for PDF data
var contentLength = aRequest.contentLength;
var dataListener = new PdfDataListener(contentLength);
+ var contentDispositionFilename;
+ try {
+ contentDispositionFilename = aRequest.contentDispositionFilename;
+ } catch (e) {}
this.dataListener = dataListener;
this.binaryStream = Cc['@mozilla.org/binaryinputstream;1']
.createInstance(Ci.nsIBinaryInputStream);
@@ -613,7 +623,8 @@ PdfStreamConverter.prototype = {
var domWindow = getDOMWindow(channel);
// Double check the url is still the correct one.
if (domWindow.document.documentURIObject.equals(aRequest.URI)) {
- let actions = new ChromeActions(domWindow, dataListener);
+ let actions = new ChromeActions(domWindow, dataListener,
+ contentDispositionFilename);
let requestListener = new RequestListener(actions);
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
requestListener.receive(event);
diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js
index 18456051b632..f9365429dbf5 100644
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -16,8 +16,8 @@
*/
var PDFJS = {};
-PDFJS.version = '0.7.82';
-PDFJS.build = 'd467790';
+PDFJS.version = '0.7.180';
+PDFJS.build = '3699c31';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -39,6 +39,10 @@ PDFJS.build = 'd467790';
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/* globals assertWellFormed, calculateMD5, Catalog, error, info, isArray,
+ isArrayBuffer, isDict, isName, isStream, isString, Lexer,
+ Linearization, NullStream, PartialEvaluator, shadow, Stream,
+ StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef */
'use strict';
@@ -97,7 +101,7 @@ function getPdf(arg, callback) {
calledErrorBack = true;
params.error();
}
- }
+ };
}
xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
@@ -177,7 +181,7 @@ var Page = (function PageClosure() {
get rotate() {
var rotate = this.inheritPageProp('Rotate') || 0;
// Normalize rotation so it's a multiple of 90 and between 0 and 270
- if (rotate % 90 != 0) {
+ if (rotate % 90 !== 0) {
rotate = 0;
} else if (rotate >= 360) {
rotate = rotate % 360;
@@ -556,7 +560,8 @@ var PDFDocument = (function PDFDocumentClosure() {
},
getDocumentInfo: function PDFDocument_getDocumentInfo() {
var docInfo = {
- PDFFormatVersion: this.pdfFormatVersion
+ PDFFormatVersion: this.pdfFormatVersion,
+ IsAcroFormPresent: !!this.acroForm
};
if (this.xref.trailer.has('Info')) {
var infoDict = this.xref.trailer.get('Info');
@@ -767,6 +772,18 @@ var InvalidPDFException = (function InvalidPDFExceptionClosure() {
return InvalidPDFException;
})();
+var MissingPDFException = (function MissingPDFExceptionClosure() {
+ function MissingPDFException(msg) {
+ this.name = 'MissingPDFException';
+ this.message = msg;
+ }
+
+ MissingPDFException.prototype = new Error();
+ MissingPDFException.constructor = MissingPDFException;
+
+ return MissingPDFException;
+})();
+
function bytesToString(bytes) {
var str = '';
var length = bytes.length;
@@ -833,7 +850,7 @@ var Util = PDFJS.Util = (function UtilClosure() {
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
];
- }
+ };
// Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
// For coordinate systems whose origin lies in the bottom-left, this
@@ -850,7 +867,7 @@ var Util = PDFJS.Util = (function UtilClosure() {
r[3] = rect[1];
}
return r;
- }
+ };
// Returns a rectangle [x1, y1, x2, y2] corresponding to the
// intersection of rect1 and rect2. If no intersection, returns 'false'
@@ -858,7 +875,7 @@ var Util = PDFJS.Util = (function UtilClosure() {
Util.intersect = function Util_intersect(rect1, rect2) {
function compare(a, b) {
return a - b;
- };
+ }
// Order points along the axes
var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
@@ -918,15 +935,15 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
case 270:
rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
break;
- case 360:
- case 0:
+ //case 360:
+ //case 0:
default:
rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
break;
}
var offsetCanvasX, offsetCanvasY;
var width, height;
- if (rotateA == 0) {
+ if (rotateA === 0) {
offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
width = Math.abs(viewBox[3] - viewBox[1]) * scale;
@@ -1048,11 +1065,13 @@ function isArray(v) {
}
function isStream(v) {
- return typeof v == 'object' && v != null && ('getChar' in v);
+ return typeof v == 'object' && v !== null && v !== undefined &&
+ ('getChar' in v);
}
function isArrayBuffer(v) {
- return typeof v == 'object' && v != null && ('byteLength' in v);
+ return typeof v == 'object' && v !== null && v !== undefined &&
+ ('byteLength' in v);
}
function isRef(v) {
@@ -1095,8 +1114,9 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
this.name = name;
this.isRejected = false;
this.error = null;
+ this.exception = null;
// If you build a promise and pass in some data it's already resolved.
- if (data != null) {
+ if (data !== null && data !== undefined) {
this.isResolved = true;
this._data = data;
this.hasData = true;
@@ -1107,7 +1127,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
this.callbacks = [];
this.errbacks = [];
this.progressbacks = [];
- };
+ }
/**
* Builds a promise that is resolved when all the passed in promises are
* resolved.
@@ -1203,6 +1223,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
this.isRejected = true;
this.error = reason || null;
+ this.exception = exception || null;
var errbacks = this.errbacks;
for (var i = 0, ii = errbacks.length; i < ii; i++) {
@@ -1221,7 +1242,8 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
callback.call(null, data);
} else if (this.isRejected && errback) {
var error = this.error;
- errback.call(null, error);
+ var exception = this.exception;
+ errback.call(null, error, exception);
} else {
this.callbacks.push(callback);
if (errback)
@@ -1564,7 +1586,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
promise.reject(error);
else
promise.resolve();
- };
+ }
var continueCallback = params.continueCallback;
// Once the operatorList and fonts are loaded, do the actual rendering.
@@ -1576,7 +1598,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
}
var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
- this.objs, params.textLayer);
+ this.objs, !this.pageInfo.disableTextLayer && params.textLayer);
try {
this.display(gfx, params.viewport, complete, continueCallback);
} catch (e) {
@@ -1665,7 +1687,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
var continueWrapper;
if (continueCallback)
- continueWrapper = function() { continueCallback(next); }
+ continueWrapper = function() { continueCallback(next); };
else
continueWrapper = next;
@@ -1829,6 +1851,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.workerReadyPromise.reject(data.exception.name, data.exception);
}, this);
+ messageHandler.on('MissingPDF', function transportMissingPDF(data) {
+ this.workerReadyPromise.reject(data.exception.message, data.exception);
+ }, this);
+
messageHandler.on('UnknownError', function transportUnknownError(data) {
this.workerReadyPromise.reject(data.exception.message, data.exception);
}, this);
@@ -2022,6 +2048,8 @@ function addContextCurrentTransform(ctx) {
// If the context doesn't expose a `mozCurrentTransform`, add a JS based on.
if (!ctx.mozCurrentTransform) {
// Store the original context
+ ctx._scaleX = ctx._scaleX || 1.0;
+ ctx._scaleY = ctx._scaleY || 1.0;
ctx._originalSave = ctx.save;
ctx._originalRestore = ctx.restore;
ctx._originalRotate = ctx.rotate;
@@ -2029,7 +2057,7 @@ function addContextCurrentTransform(ctx) {
ctx._originalTranslate = ctx.translate;
ctx._originalTransform = ctx.transform;
- ctx._transformMatrix = [1, 0, 0, 1, 0, 0];
+ ctx._transformMatrix = [ctx._scaleX, 0, 0, ctx._scaleY, 0, 0];
ctx._transformStack = [];
Object.defineProperty(ctx, 'mozCurrentTransform', {
@@ -2212,7 +2240,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
buf = imgArray[imgArrayPos++];
mask = 128;
}
- if (!(buf & mask) == inverseDecode) {
+ if (!(buf & mask) === inverseDecode) {
buffer[bufferPos] = 0;
}
bufferPos += 4;
@@ -2906,7 +2934,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var lineWidth = current.lineWidth;
var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
var scale = Math.sqrt(a1 * a1 + b1 * b1);
- if (scale == 0 || lineWidth == 0)
+ if (scale === 0 || lineWidth === 0)
lineWidth = this.getSinglePixelWidth();
else
lineWidth /= scale;
@@ -3521,7 +3549,7 @@ var Dict = (function DictClosure() {
callback(key, this.get(key));
}
};
- };
+ }
return Dict;
})();
@@ -3863,7 +3891,7 @@ var XRef = (function XRefClosure() {
for (j = 0; j < typeFieldWidth; ++j)
type = (type << 8) | stream.getByte();
// if type field is absent, its default value = 1
- if (typeFieldWidth == 0)
+ if (typeFieldWidth === 0)
type = 1;
for (j = 0; j < offsetFieldWidth; ++j)
offset = (offset << 8) | stream.getByte();
@@ -4099,7 +4127,7 @@ var XRef = (function XRefClosure() {
}
if (!isCmd(obj3, 'obj')) {
// some bad pdfs use "obj1234" and really mean 1234
- if (obj3.cmd.indexOf('obj') == 0) {
+ if (obj3.cmd.indexOf('obj') === 0) {
num = parseInt(obj3.cmd.substring(3), 10);
if (!isNaN(num))
return num;
@@ -4353,7 +4381,7 @@ var PDFFunction = (function PDFFunctionClosure() {
return this.constructInterpolatedFromIR(IR);
case CONSTRUCT_STICHED:
return this.constructStichedFromIR(IR);
- case CONSTRUCT_POSTSCRIPT:
+ //case CONSTRUCT_POSTSCRIPT:
default:
return this.constructPostScriptFromIR(IR);
}
@@ -4506,7 +4534,7 @@ var PDFFunction = (function PDFFunctionClosure() {
}
return y;
- }
+ };
},
constructInterpolated: function PDFFunction_constructInterpolated(str,
@@ -4543,7 +4571,7 @@ var PDFFunction = (function PDFFunctionClosure() {
return out;
- }
+ };
},
constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
@@ -5278,7 +5306,8 @@ var CIDToUnicodeMaps = {
174, 0, 0, {f: 2, c: 178}, 181, 185, {f: 3, c: 188}, {f: 6, c: 192},
{f: 16, c: 199}, 0, {f: 6, c: 217}, {f: 6, c: 224}, {f: 16, c: 231}, 0,
{f: 7, c: 249}, 352, 376, 381, [773, 8254], 353, 8482, 382, 0, 8194,
- {s: 91}, 65512, {s: 3}, {f: 63, c: 65377}, {s: 243}, [8195, 12288],
+ {f: 59, c: 33}, 165, {f: 31, c: 93}, 65512, {f: 2, c: 125}, 0,
+ {f: 63, c: 65377}, {s: 243}, [8195, 12288],
{f: 2, c: 12289}, 65292, 65294, 12539, {f: 2, c: 65306}, 65311, 65281,
{f: 2, c: 12443}, 180, 65344, 168, 65342, 65507, 65343, {f: 2, c: 12541},
{f: 2, c: 12445}, 12291, 20189, {f: 3, c: 12293}, 12540, 8213, 8208, 65295,
@@ -6030,9 +6059,9 @@ var CIDToUnicodeMaps = {
37854, 37880, 37937, 37957, 37960, 38290, 0, 64041, 38557, 38575, 38707,
38715, 38723, 38733, 38735, [12205, 38737], 0, 38999, 39013,
{f: 2, c: 64042}, 39207, 64044, 39326, 39502, 39641, 39644, 39797, 39794,
- 39823, 39857, 39867, 39936, 40304, 40299, 64045, 40473, 40657, {s: 636},
- 8364, 8486, 0, 0, 64256, {f: 2, c: 64259}, 257, 299, 363, 275, 333, 256,
- 298, 362, 274, 332, {f: 4, c: 8539}, {f: 2, c: 8531}, 8304,
+ 39823, 39857, 39867, 39936, 40304, 40299, 64045, 40473, 40657, 0, 92,
+ {s: 634}, 8364, 8486, 0, 0, 64256, {f: 2, c: 64259}, 257, 299, 363, 275,
+ 333, 256, 298, 362, 274, 332, {f: 4, c: 8539}, {f: 2, c: 8531}, 8304,
{f: 6, c: 8308}, {f: 10, c: 8320}, 461, 282, 0, 7868, 463, 0, 296, 465, 0,
467, 366, 360, 462, 283, 0, 7869, 464, 0, 297, 466, 0, 468, 367, 361, 593,
8049, 8048, 509, 0, 596, 0, 0, 601, 0, 0, 602, 0, 0, 603, 8051, 8050, 0,
@@ -12420,7 +12449,7 @@ var ColorSpace = (function ColorSpaceClosure() {
return true;
}
for (var i = 0, ii = decode.length; i < ii; i += 2) {
- if (decode[i] != 0 || decode[i + 1] != 1)
+ if (decode[i] !== 0 || decode[i + 1] != 1)
return false;
}
return true;
@@ -13468,7 +13497,7 @@ var LabCS = (function LabCSClosure() {
this.bmin = -100;
this.bmax = 100;
}
- };
+ }
// Function g(x) from spec
function fn_g(x) {
@@ -13902,7 +13931,7 @@ var AES128Cipher = (function AES128CipherClosure() {
this.buffer = buffer;
this.bufferLength = bufferLength;
this.iv = iv;
- if (result.length == 0)
+ if (result.length === 0)
return new Uint8Array([]);
if (result.length == 1)
return result[0];
@@ -14082,12 +14111,13 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
this.algorithm = algorithm;
var keyLength = dict.get('Length') || 40;
if (!isInt(keyLength) ||
- keyLength < 40 || (keyLength % 8) != 0)
+ keyLength < 40 || (keyLength % 8) !== 0)
error('invalid key length');
// prepare keys
var ownerPassword = stringToBytes(dict.get('O'));
var userPassword = stringToBytes(dict.get('U'));
var flags = dict.get('P');
+ this.disableTextLayer = !(flags & 16);
var revision = dict.get('R');
var encryptMetadata = algorithm == 4 && // meaningful when V is 4
dict.get('EncryptMetadata') !== false; // makes true as default value
@@ -14147,7 +14177,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
function buildCipherConstructor(cf, name, num, gen, key) {
var cryptFilter = cf.get(name.name);
var cfm;
- if (cryptFilter != null)
+ if (cryptFilter !== null && cryptFilter !== undefined)
cfm = cryptFilter.get('CFM');
if (!cfm || cfm.name == 'None') {
return function cipherTransformFactoryBuildCipherConstructorNone() {
@@ -14718,7 +14748,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
fnArray.push(fn);
argsArray.push(args);
args = [];
- } else if (obj != null) {
+ } else if (obj !== null && obj !== undefined) {
args.push(obj instanceof Dict ? obj.getAll() : obj);
assertWellFormed(args.length <= 33, 'Too many arguments');
}
@@ -14904,7 +14934,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case 'Tj':
chunk += fontCharsToUnicode(args[0], font);
break;
- case "'":
+ case '\'':
// For search, adding a extra white space for line breaks would be
// better here, but that causes too much spaces in the
// text-selection divs.
@@ -14972,7 +15002,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
args = [];
- } else if (obj != null) {
+ } else if (obj !== null && obj !== undefined) {
assertWellFormed(args.length <= 33, 'Too many arguments');
args.push(obj);
}
@@ -15186,7 +15216,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var result = [];
for (var j = 0, jj = glyphsData.length; j < jj; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
- if (glyphID == 0)
+ if (glyphID === 0)
continue;
var code = j >> 1;
@@ -15206,20 +15236,16 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var widths = dict.get('W');
if (widths) {
- var start = 0, end = 0;
for (var i = 0, ii = widths.length; i < ii; i++) {
+ var start = widths[i++];
var code = xref.fetchIfRef(widths[i]);
if (isArray(code)) {
for (var j = 0, jj = code.length; j < jj; j++)
glyphsWidths[start++] = code[j];
- start = 0;
- } else if (start) {
+ } else {
var width = widths[++i];
for (var j = start; j <= code; j++)
glyphsWidths[j] = width;
- start = 0;
- } else {
- start = code;
}
}
}
@@ -15389,6 +15415,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var fontNameStr = fontName && fontName.name;
+ // 9.7.6.1
+ if (type.name == 'CIDFontType0') {
+ var cidEncoding = baseDict.get('Encoding');
+ if (isName(cidEncoding)) {
+ fontNameStr = fontNameStr + '-' + cidEncoding.name;
+ }
+ }
var baseFontStr = baseFont && baseFont.name;
if (fontNameStr !== baseFontStr) {
warn('The FontDescriptor\'s FontName is "' + fontNameStr +
@@ -15482,7 +15515,8 @@ var SYMBOLIC_FONT_GLYPH_OFFSET = 0xF000;
// except for Type 3 fonts
var PDF_GLYPH_SPACE_UNITS = 1000;
-// Until hinting is fully supported this constant can be used
+// Hinting is currently disabled due to unknown problems on windows
+// in tracemonkey and various other pdfs with type1 fonts.
var HINTING_ENABLED = false;
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
@@ -15865,11 +15899,27 @@ var CMapConverterList = {
'90ms-RKSJ-H': sjisToUnicode,
'90ms-RKSJ-V': sjisToUnicode,
'90msp-RKSJ-H': sjisToUnicode,
- '90msp-RKSJ-V': sjisToUnicode
+ '90msp-RKSJ-V': sjisToUnicode,
+ 'GBK-EUC-H': gbkToUnicode
+};
+
+// CMaps using Hankaku (Halfwidth) Latin glyphs instead of proportional one.
+// We need to distinguish them to get correct widths from CIDFont dicts.
+var HalfwidthCMaps = {
+ 'H': true,
+ 'V': true,
+ 'EUC-H': true,
+ 'EUC-V': true,
+ '90ms-RKSJ-H': true,
+ '90ms-RKSJ-V': true,
+ 'UniJIS-UCS2-HW-H': true,
+ 'UniJIS-UCS2-HW-V': true
};
var decodeBytes;
if (typeof TextDecoder !== 'undefined') {
+ // The encodings supported by TextDecoder can be found at:
+ // http://encoding.spec.whatwg.org/#concept-encoding-get
decodeBytes = function(bytes, encoding) {
return new TextDecoder(encoding).decode(bytes);
};
@@ -15899,6 +15949,10 @@ function sjisToUnicode(str) {
return decodeBytes(stringToBytes(str), 'shift_jis');
}
+function gbkToUnicode(str) {
+ return decodeBytes(stringToBytes(str), 'gbk');
+}
+
// Some characters, e.g. copyrightserif, mapped to the private use area and
// might not be displayed using standard fonts. Mapping/hacking well-known chars
// to the similar equivalents in the normal characters range.
@@ -17674,7 +17728,7 @@ var Font = (function FontClosure() {
this.encoding = properties.baseEncoding;
this.loading = true;
- };
+ }
var numFonts = 0;
function getUniqueName() {
@@ -17687,7 +17741,7 @@ var Font = (function FontClosure() {
array[i] = str.charCodeAt(i);
return array;
- };
+ }
function arrayToString(arr) {
var str = '';
@@ -17695,16 +17749,16 @@ var Font = (function FontClosure() {
str += String.fromCharCode(arr[i]);
return str;
- };
+ }
function int16(bytes) {
return (bytes[0] << 8) + (bytes[1] & 0xff);
- };
+ }
function int32(bytes) {
return (bytes[0] << 24) + (bytes[1] << 16) +
(bytes[2] << 8) + (bytes[3] & 0xff);
- };
+ }
function getMaxPower2(number) {
var maxPower = 0;
@@ -17718,26 +17772,26 @@ var Font = (function FontClosure() {
for (var i = 1; i < maxPower; i++)
value *= 2;
return value;
- };
+ }
function string16(value) {
return String.fromCharCode((value >> 8) & 0xff) +
String.fromCharCode(value & 0xff);
- };
+ }
function safeString16(value) {
// clamp value to the 16-bit int range
value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value;
return String.fromCharCode((value >> 8) & 0xff) +
String.fromCharCode(value & 0xff);
- };
+ }
function string32(value) {
return String.fromCharCode((value >> 24) & 0xff) +
String.fromCharCode((value >> 16) & 0xff) +
String.fromCharCode((value >> 8) & 0xff) +
String.fromCharCode(value & 0xff);
- };
+ }
function createOpenTypeHeader(sfnt, file, numTables) {
// Windows hates the Mac TrueType sfnt version number
@@ -17763,7 +17817,7 @@ var Font = (function FontClosure() {
file.file += header;
file.virtualOffset += header.length;
- };
+ }
function createTableEntry(file, tag, data) {
// offset
@@ -17789,7 +17843,7 @@ var Font = (function FontClosure() {
string32(offset) + string32(length));
file.file += tableEntry;
file.virtualOffset += data.length;
- };
+ }
function getRanges(glyphs) {
// Array.sort() sorts by characters, not numerically, so convert to an
@@ -17818,9 +17872,9 @@ var Font = (function FontClosure() {
}
return ranges;
- };
+ }
- function createCMapTable(glyphs, deltas) {
+ function createCmapTable(glyphs, deltas) {
var ranges = getRanges(glyphs);
var numTables = 1;
@@ -17895,7 +17949,7 @@ var Font = (function FontClosure() {
'\x00\x04' + // format
string16(format314.length + 4) + // length
format314);
- };
+ }
function validateOS2Table(os2) {
var stream = new Stream(os2.data);
@@ -18018,7 +18072,7 @@ var Font = (function FontClosure() {
string16(0) + // usDefaultChar
string16(firstCharIndex || properties.firstChar) + // usBreakChar
'\x00\x03'; // usMaxContext
- };
+ }
function createPostTable(properties) {
var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
@@ -18031,7 +18085,7 @@ var Font = (function FontClosure() {
'\x00\x00\x00\x00' + // maxMemType42
'\x00\x00\x00\x00' + // minMemType1
'\x00\x00\x00\x00'; // maxMemType1
- };
+ }
function createNameTable(name, proto) {
if (!proto) {
@@ -18096,6 +18150,37 @@ var Font = (function FontClosure() {
return nameTable;
}
+ // Normalize the charcodes in the cmap table into unicode values
+ // that will work with the (3, 1) cmap table we will write out.
+ function cmapCharcodeToUnicode(charcode, symbolic, platformId, encodingId) {
+ var unicode;
+ if (symbolic) {
+ // These codes will be shifted into the range
+ // SYMBOLIC_FONT_GLYPH_OFFSET to (SYMBOLIC_FONT_GLYPH_OFFSET + 0xFF)
+ // so that they are not in the control character range that could
+ // be displayed as spaces by browsers.
+ if (platformId === 3 && encodingId === 0 ||
+ platformId === 1 && encodingId === 0) {
+ unicode = SYMBOLIC_FONT_GLYPH_OFFSET | (charcode & 0xFF);
+ }
+ } else {
+ if (platformId === 3 && encodingId === 1) {
+ // A (3, 1) table is alredy unicode (Microsoft Unicode format)
+ unicode = charcode;
+ } else if (platformId === 1 && encodingId === 0) {
+ // TODO(mack): Should apply the changes to convert the
+ // MacRomanEncoding to Mac OS Roman encoding in 9.6.6.4
+ // table 115 of the pdf spec
+ var glyphName = Encodings.MacRomanEncoding[charcode];
+ if (glyphName) {
+ unicode = GlyphsUnicode[glyphName];
+ }
+ }
+ }
+ return unicode;
+ }
+
+
Font.prototype = {
name: null,
font: null,
@@ -18143,7 +18228,7 @@ var Font = (function FontClosure() {
offset: offset,
data: data
};
- };
+ }
function readOpenTypeHeader(ttf) {
return {
@@ -18153,7 +18238,7 @@ var Font = (function FontClosure() {
entrySelector: int16(ttf.getBytes(2)),
rangeShift: int16(ttf.getBytes(2))
};
- };
+ }
function createGlyphNameMap(glyphs, ids, properties) {
var glyphNames = properties.glyphNames;
@@ -18178,177 +18263,218 @@ var Font = (function FontClosure() {
properties.baseEncoding = encoding;
}
- function readCMapTable(cmap, font) {
+ /**
+ * Read the appropriate subtable from the cmap according to 9.6.6.4 from
+ * PDF spec
+ */
+ function readCmapTable(cmap, font, hasEncoding, isSymbolicFont) {
var start = (font.start ? font.start : 0) + cmap.offset;
font.pos = start;
var version = int16(font.getBytes(2));
- var numRecords = int16(font.getBytes(2));
+ var numTables = int16(font.getBytes(2));
- var records = [];
- for (var i = 0; i < numRecords; i++) {
- records.push({
- platformID: int16(font.getBytes(2)),
- encodingID: int16(font.getBytes(2)),
- offset: int32(font.getBytes(4))
- });
- }
+ var potentialTable;
+ var foundPreferredTable;
+ // There's an order of preference in terms of which cmap subtable we
+ // want to use. So scan through them to find our preferred table.
+ for (var i = 0; i < numTables; i++) {
+ var platformId = int16(font.getBytes(2));
+ var encodingId = int16(font.getBytes(2));
+ var offset = int32(font.getBytes(4));
+ var useTable = false;
+ var canBreak = false;
- // Check that table are sorted by platformID then encodingID,
- records.sort(function fontReadCMapTableSort(a, b) {
- return ((a.platformID << 16) + a.encodingID) -
- ((b.platformID << 16) + b.encodingID);
- });
-
- var tables = [records[0]];
- for (var i = 1; i < numRecords; i++) {
- // The sanitizer will drop the font if 2 tables have the same
- // platformID and the same encodingID, this will be correct for
- // most cases but if the font has been made for Mac it could
- // exist a few platformID: 1, encodingID: 0 but with a different
- // language field and that's correct. But the sanitizer does not
- // seem to support this case.
- var current = records[i];
- var previous = records[i - 1];
- if (((current.platformID << 16) + current.encodingID) <=
- ((previous.platformID << 16) + previous.encodingID))
- continue;
- tables.push(current);
- }
-
- var missing = numRecords - tables.length;
- if (missing) {
- numRecords = tables.length;
- var data = string16(version) + string16(numRecords);
-
- for (var i = 0; i < numRecords; i++) {
- var table = tables[i];
- data += string16(table.platformID) +
- string16(table.encodingID) +
- string32(table.offset);
+ // The following block implements the following from the spec:
+ //
+ // When the font has no Encoding entry, or the font descriptor’s
+ // Symbolic flag is set (in which case the Encoding entry
+ // is ignored), this shall occur:
+ // - If the font contains a (3, 0) subtable, the range of
+ // - Otherwise, the (1, 0) subtable will be used.
+ // Otherwise, if the font does have an encoding:
+ // - Use the (3, 1) cmap subtable
+ // - Otherwise, use the (1, 0) subtable if present
+ //
+ // The following diverges slightly from the above spec in order
+ // to handle the case that hasEncoding and isSymbolicFont are both
+ // true. In this, based on the ordering of the rules in the spec,
+ // my interpretation is that we should be acting as if the font is
+ // symbolic.
+ //
+ // However, in this case, the test pdf 'preistabelle.pdf'
+ // is interpreting this case as a non-symbolic font. In this case
+ // though, 'presitabelle.pdf' does contain a (3, 1) table and does
+ // not contain a (3, 0) table which indicates it is non-symbolic.
+ //
+ // Thus, I am using this heurisitic of looking at which table is
+ // found to truly determine whether or not the font is symbolic.
+ // That is, if the specific symbolic/non-symbolic font specific
+ // tables (3, 0) or (3, 1) is found, that information is used for
+ // deciding if the font is symbolic or not.
+ //
+ // TODO(mack): This section needs some more thought on whether the
+ // heuristic is good enough. For now, it passes all the regression
+ // tests.
+ if (isSymbolicFont && platformId === 3 && encodingId === 0) {
+ useTable = true;
+ canBreak = true;
+ foundPreferredTable = true;
+ } else if (hasEncoding && platformId === 3 && encodingId === 1) {
+ useTable = true;
+ canBreak = true;
+ foundPreferredTable = true;
+ // Update the isSymbolicFont based on this heuristic
+ isSymbolicFont = false;
+ } else if (platformId === 1 && encodingId === 0 &&
+ !foundPreferredTable) {
+ useTable = true;
+ foundPreferredTable = true;
+ } else if (!potentialTable) {
+ // We will use an arbitrary table if we cannot find a preferred
+ // table
+ useTable = true;
}
- for (var i = 0, ii = data.length; i < ii; i++)
- cmap.data[i] = data.charCodeAt(i);
+ if (useTable) {
+ potentialTable = {
+ platformId: platformId,
+ encodingId: encodingId,
+ offset: offset,
+ isSymbolicFont: isSymbolicFont
+ };
+ }
+ if (canBreak) {
+ break;
+ }
}
- for (var i = 0; i < numRecords; i++) {
- var table = tables[i];
- font.pos = start + table.offset;
+ if (!potentialTable) {
+ error('Could not find a cmap table');
+ return;
+ }
- var format = int16(font.getBytes(2));
- var length = int16(font.getBytes(2));
- var language = int16(font.getBytes(2));
+ if (!foundPreferredTable) {
+ warn('Did not find a cmap of suitable format. Interpreting (' +
+ potentialTable.platformId + ', ' + potentialTable.encodingId +
+ ') as (3, 1) table');
+ potentialTable.platformId = 3;
+ potentialTable.encodingId = 1;
+ }
- if (format == 0) {
- // Characters below 0x20 are controls characters that are hardcoded
- // into the platform so if some characters in the font are assigned
- // under this limit they will not be displayed so let's rewrite the
- // CMap.
- var glyphs = [];
- var ids = [];
- for (var j = 0; j < 256; j++) {
- var index = font.getByte();
- if (index) {
- glyphs.push({ unicode: j, code: j });
- ids.push(index);
- }
+ font.pos = start + potentialTable.offset;
+ var format = int16(font.getBytes(2));
+ var length = int16(font.getBytes(2));
+ var language = int16(font.getBytes(2));
+
+ var hasShortCmap = false;
+ var mappings = [];
+
+ // TODO(mack): refactor this cmap subtable reading logic out
+ if (format === 0) {
+ for (var j = 0; j < 256; j++) {
+ var index = font.getByte();
+ if (!index) {
+ continue;
}
- return {
- glyphs: glyphs,
- ids: ids,
- hasShortCmap: true
- };
- } else if (format == 4) {
- // re-creating the table in format 4 since the encoding
- // might be changed
- var segCount = (int16(font.getBytes(2)) >> 1);
- font.getBytes(6); // skipping range fields
- var segIndex, segments = [];
- for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments.push({ end: int16(font.getBytes(2)) });
- }
- font.getBytes(2);
- for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].start = int16(font.getBytes(2));
+ mappings.push({
+ charcode: j,
+ glyphId: index
+ });
+ }
+ hasShortCmap = true;
+ } else if (format === 4) {
+ // re-creating the table in format 4 since the encoding
+ // might be changed
+ var segCount = (int16(font.getBytes(2)) >> 1);
+ font.getBytes(6); // skipping range fields
+ var segIndex, segments = [];
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments.push({ end: int16(font.getBytes(2)) });
+ }
+ font.getBytes(2);
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments[segIndex].start = int16(font.getBytes(2));
+ }
+
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments[segIndex].delta = int16(font.getBytes(2));
+ }
+
+ var offsetsCount = 0;
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ var segment = segments[segIndex];
+ var rangeOffset = int16(font.getBytes(2));
+ if (!rangeOffset) {
+ segment.offsetIndex = -1;
+ continue;
}
- for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].delta = int16(font.getBytes(2));
- }
+ var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
+ segment.offsetIndex = offsetIndex;
+ offsetsCount = Math.max(offsetsCount, offsetIndex +
+ segment.end - segment.start + 1);
+ }
- var offsetsCount = 0;
- for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var rangeOffset = int16(font.getBytes(2));
- if (!rangeOffset) {
- segment.offsetIndex = -1;
+ var offsets = [];
+ for (var j = 0; j < offsetsCount; j++) {
+ offsets.push(int16(font.getBytes(2)));
+ }
+
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ var segment = segments[segIndex];
+ var start = segment.start, end = segment.end;
+ var delta = segment.delta, offsetIndex = segment.offsetIndex;
+
+ for (var j = start; j <= end; j++) {
+ if (j == 0xFFFF) {
continue;
}
- var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
- segment.offsetIndex = offsetIndex;
- offsetsCount = Math.max(offsetsCount, offsetIndex +
- segment.end - segment.start + 1);
- }
-
- var offsets = [];
- for (var j = 0; j < offsetsCount; j++)
- offsets.push(int16(font.getBytes(2)));
-
- var glyphs = [], ids = [];
-
- for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var start = segment.start, end = segment.end;
- var delta = segment.delta, offsetIndex = segment.offsetIndex;
-
- for (var j = start; j <= end; j++) {
- if (j == 0xFFFF)
- continue;
-
- var glyphCode = offsetIndex < 0 ? j :
- offsets[offsetIndex + j - start];
- glyphCode = (glyphCode + delta) & 0xFFFF;
- if (glyphCode == 0)
- continue;
-
- glyphs.push({ unicode: j, code: j });
- ids.push(glyphCode);
+ var glyphId = offsetIndex < 0 ? j :
+ offsets[offsetIndex + j - start];
+ glyphId = (glyphId + delta) & 0xFFFF;
+ if (glyphId === 0) {
+ continue;
}
+ mappings.push({
+ charcode: j,
+ glyphId: glyphId
+ });
}
-
- return {
- glyphs: glyphs,
- ids: ids
- };
- } else if (format == 6) {
- // Format 6 is a 2-bytes dense mapping, which means the font data
- // lives glue together even if they are pretty far in the unicode
- // table. (This looks weird, so I can have missed something), this
- // works on Linux but seems to fails on Mac so let's rewrite the
- // cmap table to a 3-1-4 style
- var firstCode = int16(font.getBytes(2));
- var entryCount = int16(font.getBytes(2));
-
- var glyphs = [];
- var ids = [];
- for (var j = 0; j < entryCount; j++) {
- var glyphCode = int16(font.getBytes(2));
- var code = firstCode + j;
-
- glyphs.push({ unicode: code, code: code });
- ids.push(glyphCode);
- }
-
- return {
- glyphs: glyphs,
- ids: ids
- };
}
+ } else if (format == 6) {
+ // Format 6 is a 2-bytes dense mapping, which means the font data
+ // lives glue together even if they are pretty far in the unicode
+ // table. (This looks weird, so I can have missed something), this
+ // works on Linux but seems to fails on Mac so let's rewrite the
+ // cmap table to a 3-1-4 style
+ var firstCode = int16(font.getBytes(2));
+ var entryCount = int16(font.getBytes(2));
+
+ var glyphs = [];
+ var ids = [];
+ for (var j = 0; j < entryCount; j++) {
+ var glyphId = int16(font.getBytes(2));
+ var charcode = firstCode + j;
+
+ mappings.push({
+ charcode: charcode,
+ glyphId: glyphId
+ });
+ }
+ } else {
+ error('cmap table has unsupported format: ' + format);
}
- error('Unsupported cmap table format');
- };
+
+ return {
+ platformId: potentialTable.platformId,
+ encodingId: potentialTable.encodingId,
+ isSymbolicFont: potentialTable.isSymbolicFont,
+ mappings: mappings,
+ hasShortCmap: hasShortCmap
+ };
+ }
function sanitizeMetrics(font, header, metrics, numGlyphs) {
if (!header) {
@@ -18362,19 +18488,29 @@ var Font = (function FontClosure() {
font.pos += header.length - 2;
var numOfMetrics = int16(font.getBytes(2));
+ if (numOfMetrics > numGlyphs) {
+ info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
+ 'greater than the numGlyphs (' + numGlyphs + ')');
+ // Reduce numOfMetrics if it is greater than numGlyphs
+ numOfMetrics = numGlyphs;
+ header.data[34] = (numOfMetrics & 0xff00) >> 8;
+ header.data[35] = numOfMetrics & 0x00ff;
+ }
+
var numOfSidebearings = numGlyphs - numOfMetrics;
var numMissing = numOfSidebearings -
- ((hmtx.length - numOfMetrics * 4) >> 1);
+ ((metrics.length - numOfMetrics * 4) >> 1);
+
if (numMissing > 0) {
font.pos = (font.start ? font.start : 0) + metrics.offset;
var entries = '';
- for (var i = 0, ii = hmtx.length; i < ii; i++)
+ for (var i = 0, ii = metrics.length; i < ii; i++)
entries += String.fromCharCode(font.getByte());
for (var i = 0; i < numMissing; i++)
entries += '\x00\x00';
metrics.data = stringToArray(entries);
}
- };
+ }
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
if (sourceEnd - sourceStart <= 12) {
@@ -18431,6 +18567,50 @@ var Font = (function FontClosure() {
return glyf.length;
}
+ function sanitizeHead(head, numGlyphs, locaLength) {
+ var data = head.data;
+
+ // Validate version:
+ // Should always be 0x00010000
+ var version = int32([data[0], data[1], data[2], data[3]]);
+ if (version >> 16 !== 1) {
+ info('Attempting to fix invalid version in head table: ' + version);
+ data[0] = 0;
+ data[1] = 1;
+ data[2] = 0;
+ data[3] = 0;
+ }
+
+ var indexToLocFormat = int16([data[50], data[51]]);
+ if (indexToLocFormat < 0 || indexToLocFormat > 1) {
+ info('Attempting to fix invalid indexToLocFormat in head table: ' +
+ indexToLocFormat);
+
+ // The value of indexToLocFormat should be 0 if the loca table
+ // consists of short offsets, and should be 1 if the loca table
+ // consists of long offsets.
+ //
+ // The number of entries in the loca table should be numGlyphs + 1.
+ //
+ // Using this information, we can work backwards to deduce if the
+ // size of each offset in the loca table, and thus figure out the
+ // appropriate value for indexToLocFormat.
+
+ var numGlyphsPlusOne = numGlyphs + 1;
+ if (locaLength === numGlyphsPlusOne << 1) {
+ // 0x0000 indicates the loca table consists of short offsets
+ data[50] = 0;
+ data[51] = 0;
+ } else if (locaLength === numGlyphsPlusOne << 2) {
+ // 0x0001 indicates the loca table consists of long offsets
+ data[50] = 0;
+ data[51] = 1;
+ } else {
+ warn('Could not fix indexToLocFormat: ' + indexToLocFormat);
+ }
+ }
+ }
+
function sanitizeGlyphLocations(loca, glyf, numGlyphs,
isGlyphLocationsLong) {
var itemSize, itemDecode, itemEncode;
@@ -18480,7 +18660,7 @@ var Font = (function FontClosure() {
startOffset = endOffset;
}
- if (writeOffset == 0) {
+ if (writeOffset === 0) {
// glyf table cannot be empty -- redoing the glyf and loca tables
// to have single glyph with one point
var simpleGlyph = new Uint8Array(
@@ -18607,7 +18787,7 @@ var Font = (function FontClosure() {
offset: int16(font.getBytes(2))
};
// using only Macintosh and Windows platform/encoding names
- if ((r.platform == 1 && r.encoding == 0 && r.language == 0) ||
+ if ((r.platform == 1 && r.encoding === 0 && r.language === 0) ||
(r.platform == 3 && r.encoding == 1 && r.language == 0x409)) {
records.push(r);
}
@@ -18639,7 +18819,7 @@ var Font = (function FontClosure() {
var data = os2Table.data;
// usWinAscent == 0 makes font unreadable by windows
var usWinAscent = (data[74] << 8) | data[75];
- if (usWinAscent == 0)
+ if (usWinAscent === 0)
return false;
return true;
@@ -18855,6 +19035,10 @@ var Font = (function FontClosure() {
sanitizeTTPrograms(fpgm, prep);
+ if (head) {
+ sanitizeHead(head, numGlyphs, loca.length);
+ }
+
var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
if (head && loca && glyf) {
sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
@@ -18866,7 +19050,7 @@ var Font = (function FontClosure() {
// Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
// Sometimes it's 0. That needs to be fixed
- if (hhea.data[10] == 0 && hhea.data[11] == 0) {
+ if (hhea.data[10] === 0 && hhea.data[11] === 0) {
hhea.data[10] = 0xFF;
hhea.data[11] = 0xFF;
}
@@ -18948,175 +19132,131 @@ var Font = (function FontClosure() {
ids.push(i);
}
} else {
- var cmapTable = readCMapTable(cmap, font);
+ this.useToFontChar = true;
+ // Most of the following logic in this code branch is based on the
+ // 9.6.6.4 of the PDF spec.
- glyphs = cmapTable.glyphs;
- ids = cmapTable.ids;
+ // TODO(mack):
+ // We are using this.hasEncoding to mean that the encoding is either
+ // MacRomanEncoding or WinAnsiEncoding (following spec in 9.6.6.4),
+ // but this.hasEncoding is currently true for any encodings on the
+ // Encodings object (e.g. MacExpertEncoding). So should consider using
+ // better check for this.
+ var cmapTable = readCmapTable(cmap, font, this.hasEncoding,
+ this.isSymbolicFont);
- var hasShortCmap = !!cmapTable.hasShortCmap;
+ // TODO(mack): If the (3, 0) cmap table used, then the font is
+ // symbolic. The range of charcodes in the cmap table should be
+ // one of the following:
+ // -> 0x0000 - 0x00FF
+ // -> 0xF000 - 0xF0FF
+ // -> 0xF100 - 0xF1FF
+ // -> 0xF200 - 0xF2FF
+ // If it is not, we should change not consider this a symbolic font
+ this.isSymbolicFont = cmapTable.isSymbolicFont;
+
+ var cmapPlatformId = cmapTable.platformId;
+ var cmapEncodingId = cmapTable.encodingId;
+ var cmapMappings = cmapTable.mappings;
+ var cmapMappingsLength = cmapMappings.length;
+ var glyphs = [];
+ var ids = [];
+ for (var i = 0; i < cmapMappingsLength; ++i) {
+ var cmapMapping = cmapMappings[i];
+ var charcode = cmapMapping.charcode;
+ var unicode = cmapCharcodeToUnicode(charcode, this.isSymbolicFont,
+ cmapPlatformId, cmapEncodingId);
+
+ if (!unicode) {
+ // TODO(mack): gotta check if skipping mappings where we cannot find
+ // a unicode is the correct behaviour
+ continue;
+ }
+ glyphs.push({
+ code: charcode,
+ unicode: unicode
+ });
+ ids.push(cmapMapping.glyphId);
+ }
+
+ var hasShortCmap = cmapTable.hasShortCmap;
var toFontChar = this.toFontChar;
if (hasShortCmap && ids.length == numGlyphs) {
// Fixes the short cmap tables -- some generators use incorrect
// glyph id.
- for (var i = 0, ii = ids.length; i < ii; i++)
+ for (var i = 0, ii = ids.length; i < ii; i++) {
ids[i] = i;
- }
-
- var unusedUnicode = CMAP_GLYPH_OFFSET;
- var glyphNames = properties.glyphNames || [];
- var encoding = properties.baseEncoding;
- var differences = properties.differences;
- if (toFontChar && toFontChar.length > 0) {
- // checking if cmap is just identity map
- var isIdentity = true;
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- if (glyphs[i].unicode != i + 1) {
- isIdentity = false;
- break;
- }
- }
- // if it is, replacing with meaningful toUnicode values
- if (isIdentity && !this.isSymbolicFont) {
- var usedUnicodes = [], unassignedUnicodeItems = [];
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var unicode = toFontChar[i + 1];
- if (!unicode || typeof unicode !== 'number' ||
- unicode in usedUnicodes) {
- unassignedUnicodeItems.push(i);
- continue;
- }
- glyphs[i].unicode = unicode;
- usedUnicodes[unicode] = true;
- }
- for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; j++) {
- var i = unassignedUnicodeItems[j];
- while (unusedUnicode in usedUnicodes)
- unusedUnicode++;
- var cid = i + 1;
- // override only if unicode mapping is not specified
- if (!(cid in toFontChar))
- toFontChar[cid] = unusedUnicode;
- glyphs[i].unicode = unusedUnicode++;
- }
- this.useToFontChar = true;
}
}
- // remove glyph references outside range of avaialable glyphs or empty
- var glyphsRemoved = 0;
- for (var i = ids.length - 1; i >= 0; i--) {
- if (ids[i] < numGlyphs &&
- (!emptyGlyphIds[ids[i]] || this.isSymbolicFont))
- continue;
- ids.splice(i, 1);
- glyphs.splice(i, 1);
- glyphsRemoved++;
- }
-
- // checking if it's a "true" symbolic font
+ // Rewrite the whole toFontChar dictionary with a new one using the
+ // information from the mappings in the cmap table.
+ var newToFontChar = [];
if (this.isSymbolicFont) {
- var minUnicode = 0xFFFF, maxUnicode = 0;
for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var unicode = glyphs[i].unicode;
- minUnicode = Math.min(minUnicode, unicode);
- maxUnicode = Math.max(maxUnicode, unicode);
+ var glyph = glyphs[i];
+ // For (3, 0) cmap tables:
+ // The charcode key being stored in toFontChar is the lower byte
+ // of the two-byte charcodes of the cmap table since according to
+ // the spec: 'each byte from the string shall be prepended with the
+ // high byte of the range [of charcodes in the cmap table], to form
+ // a two-byte character, which shall be used to select the
+ // associated glyph description from the subtable'.
+ //
+ // For (1, 0) cmap tables:
+ // 'single bytes from the string shall be used to look up the
+ // associated glyph descriptions from the subtable'. This means
+ // charcodes in the cmap will be single bytes, so no-op since
+ // glyph.code & 0xFF === glyph.code
+ newToFontChar[glyph.code & 0xFF] = glyph.unicode;
}
- // high byte must be the same for min and max unicodes
- if ((maxUnicode & 0xFF00) != (minUnicode & 0xFF00))
- this.isSymbolicFont = false;
- }
+ } else {
- // heuristics: if removed more than 5 glyphs encoding WinAnsiEncoding
- // does not set properly (broken PDFs have about 100 removed glyphs)
- if (glyphsRemoved > 5) {
- warn('Switching TrueType encoding to MacRomanEncoding for ' +
- this.name + ' font');
- encoding = Encodings.MacRomanEncoding;
- }
+ var encoding = properties.baseEncoding;
+ var differences = properties.differences;
- if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
- // Re-encode short map encoding to unicode -- that simplifies the
- // resolution of MacRoman encoded glyphs logic for TrueType fonts:
- // copying all characters to private use area, all mapping all known
- // glyphs to the unicodes. The glyphs and ids arrays will grow.
- var usedUnicodes = [];
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var code = glyphs[i].unicode;
- var gid = ids[i];
- glyphs[i].unicode += CMAP_GLYPH_OFFSET;
- toFontChar[code] = glyphs[i].unicode;
+ // TODO(mack): check if it is necessary to shift control characters
+ // for non-symbolic fonts so that browsers dont't render them using
+ // space characters
- var glyphName = glyphNames[gid] || encoding[code];
- if (glyphName in GlyphsUnicode) {
- var unicode = GlyphsUnicode[glyphName];
- if (unicode in usedUnicodes)
- continue;
-
- usedUnicodes[unicode] = true;
- glyphs.push({
- unicode: unicode,
- code: glyphs[i].code
- });
- ids.push(gid);
- toFontChar[code] = unicode;
+ var glyphCodeMapping = cmapTable.glyphCodeMapping;
+ for (var charcode = 0; charcode < encoding.length; ++charcode) {
+ if (!encoding.hasOwnProperty(charcode)) {
+ continue;
}
- }
- this.useToFontChar = true;
- } else if (!this.isSymbolicFont && (this.hasEncoding ||
- properties.glyphNames || differences.length > 0)) {
- // Re-encode cmap encoding to unicode, based on the 'post' table data
- // diffrence array or base encoding
- var reverseMap = [];
- for (var i = 0, ii = glyphs.length; i < ii; i++)
- reverseMap[glyphs[i].unicode] = i;
- var newGlyphUnicodes = [];
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var code = glyphs[i].unicode;
- var changeCode = false;
- var gid = ids[i];
+ // Since the cmap table that we will be writing out is a (3, 1)
+ // unicode table, in this section we will rewrites the charcodes
+ // in the pdf into unicodes
- var glyphName = glyphNames[gid];
+ var glyphName = encoding[charcode];
+ // A nonsymbolic font should not have a Differences array, but
+ // if it does have one, we should still use it
+ if (charcode in differences) {
+ glyphName = differences[charcode];
+ }
+
+ // Finally, any undefined entries in the table shall be filled
+ // using StandardEncoding
if (!glyphName) {
- glyphName = differences[code] || encoding[code];
- changeCode = true;
+ glyphName = Encodings.StandardEncoding[charcode];
}
- if (glyphName in GlyphsUnicode) {
- var unicode = GlyphsUnicode[glyphName];
- if (!unicode || reverseMap[unicode] === i)
- continue; // unknown glyph name or in its own place
- newGlyphUnicodes[i] = unicode;
- if (changeCode)
- toFontChar[code] = unicode;
- delete reverseMap[code];
- }
- }
- for (var index in newGlyphUnicodes) {
- if (newGlyphUnicodes.hasOwnProperty(index)) {
- var unicode = newGlyphUnicodes[index];
- if (reverseMap[unicode]) {
- // avoiding assigning to the same unicode
- glyphs[index].unicode = unusedUnicode++;
- continue;
- }
- glyphs[index].unicode = unicode;
- reverseMap[unicode] = index;
- }
- }
- this.useToFontChar = true;
- }
+ // TODO(mack): Handle the case that the glyph name cannot be
+ // mapped as specified, in which case the glyph name shall be
+ // looked up in the font program's 'post' table (if one is
+ // present) and the associated glyph id shall be used.
+ //
+ // For now, we're just using the '.notdef' glyph name in this
+ // case.
+ glyphName = glyphName || '.notdef';
- // Moving all symbolic font glyphs into 0xF000 - 0xF0FF range.
- if (this.isSymbolicFont) {
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var code = glyphs[i].unicode & 0xFF;
- var fontCharCode = SYMBOLIC_FONT_GLYPH_OFFSET | code;
- glyphs[i].unicode = toFontChar[code] = fontCharCode;
+ var unicode = GlyphsUnicode[glyphName];
+ newToFontChar[charcode] = unicode;
}
- this.useToFontChar = true;
}
+ this.toFontChar = toFontChar = newToFontChar;
createGlyphNameMap(glyphs, ids, properties);
this.glyphNameMap = properties.glyphNameMap;
@@ -19129,7 +19269,7 @@ var Font = (function FontClosure() {
}
// Converting glyphs and ids into font's cmap table
- cmap.data = createCMapTable(glyphs, ids);
+ cmap.data = createCmapTable(glyphs, ids);
var unicodeIsEnabled = [];
for (var i = 0, ii = glyphs.length; i < ii; i++) {
unicodeIsEnabled[glyphs[i].unicode] = true;
@@ -19273,7 +19413,7 @@ var Font = (function FontClosure() {
'OS/2': stringToArray(createOS2Table(properties, charstrings)),
// Character to glyphs mapping
- 'cmap': createCMapTable(charstrings.slice(),
+ 'cmap': createCmapTable(charstrings.slice(),
('glyphIds' in font) ? font.glyphIds : null),
// Font header
@@ -19374,7 +19514,7 @@ var Font = (function FontClosure() {
var firstChar = properties.firstChar, lastChar = properties.lastChar;
var map = [];
if (properties.composite) {
- var isIdentityMap = this.cidToUnicode.length == 0;
+ var isIdentityMap = this.cidToUnicode.length === 0;
for (var i = firstChar, ii = lastChar; i <= ii; i++) {
// TODO missing map the character according font's CMap
var cid = i;
@@ -19410,14 +19550,18 @@ var Font = (function FontClosure() {
if (!cidToUnicode)
return; // identity encoding
+ var cidEncoding = properties.cidEncoding;
+ var overwrite = HalfwidthCMaps[cidEncoding];
var cid = 1, i, j, k, ii;
for (i = 0, ii = cidToUnicode.length; i < ii; ++i) {
var unicode = cidToUnicode[i];
if (isArray(unicode)) {
var length = unicode.length;
for (j = 0; j < length; j++) {
- cidToUnicodeMap[cid] = unicode[j];
- unicodeToCIDMap[unicode[j]] = cid;
+ cidToUnicodeMap[cid] = k = unicode[j];
+ if (!unicodeToCIDMap[k] || overwrite) {
+ unicodeToCIDMap[k] = cid;
+ }
}
cid++;
} else if (typeof unicode === 'object') {
@@ -19426,7 +19570,9 @@ var Font = (function FontClosure() {
k = unicode.c;
for (j = 0; j < fillLength; ++j) {
cidToUnicodeMap[cid] = k;
- unicodeToCIDMap[k] = cid;
+ if (!unicodeToCIDMap[k] || overwrite) {
+ unicodeToCIDMap[k] = cid;
+ }
cid++;
k++;
}
@@ -19434,19 +19580,24 @@ var Font = (function FontClosure() {
cid += unicode.s;
} else if (unicode) {
cidToUnicodeMap[cid] = unicode;
- unicodeToCIDMap[unicode] = cid;
+ if (!unicodeToCIDMap[unicode] || overwrite) {
+ unicodeToCIDMap[unicode] = cid;
+ }
cid++;
} else
cid++;
}
- var cidEncoding = properties.cidEncoding;
- if (cidEncoding && cidEncoding.indexOf('Identity-') !== 0) {
+ if (!cidEncoding) {
+ return;
+ }
+ if (cidEncoding.indexOf('Identity-') !== 0) {
// input is already Unicode for non-Identity CMap encodings.
- // However, Unicode-to-CID conversion is needed
- // regardless of the CMap encoding. So we can't reset
- // unicodeToCID.
this.cidToUnicode = [];
+ } else {
+ // We don't have to do reverse conversions if the string is
+ // already CID.
+ this.unicodeToCID = [];
}
},
@@ -19460,7 +19611,7 @@ var Font = (function FontClosure() {
// Add the font-face rule to the document
var url = ('url(data:' + this.mimetype + ';base64,' +
window.btoa(data) + ');');
- var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}';
+ var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
if (!styleElement) {
@@ -19504,7 +19655,7 @@ var Font = (function FontClosure() {
if (!charcode && 'toUnicode' in this)
charcode = this.toUnicode.indexOf(glyphUnicode);
// setting it to unicode if negative or undefined
- if (!(charcode > 0))
+ if (charcode <= 0)
charcode = glyphUnicode;
// trying to get width via charcode
width = this.widths[charcode];
@@ -19681,12 +19832,323 @@ var ErrorFont = (function ErrorFontClosure() {
return ErrorFont;
})();
-var CallothersubrCmd = (function CallothersubrCmdClosure() {
- function CallothersubrCmd(index) {
- this.index = index;
+/*
+ * CharStrings are encoded following the the CharString Encoding sequence
+ * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
+ * The value in a byte indicates a command, a number, or subsequent bytes
+ * that are to be interpreted in a special way.
+ *
+ * CharString Number Encoding:
+ * A CharString byte containing the values from 32 through 255 inclusive
+ * indicate an integer. These values are decoded in four ranges.
+ *
+ * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
+ * indicate the integer v - 139. Thus, the integer values from -107 through
+ * 107 inclusive may be encoded in single byte.
+ *
+ * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
+ * indicates an integer involving the next byte, w, according to the formula:
+ * [(v - 247) x 256] + w + 108
+ *
+ * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
+ * indicates an integer involving the next byte, w, according to the formula:
+ * -[(v - 251) * 256] - w - 108
+ *
+ * 4. A CharString containing the value 255 indicates that the next 4 bytes
+ * are a two complement signed integer. The first of these bytes contains the
+ * highest order bits, the second byte contains the next higher order bits
+ * and the fourth byte contain the lowest order bits.
+ *
+ *
+ * CharString Command Encoding:
+ * CharStrings commands are encoded in 1 or 2 bytes.
+ *
+ * Single byte commands are encoded in 1 byte that contains a value between
+ * 0 and 31 inclusive.
+ * If a command byte contains the value 12, then the value in the next byte
+ * indicates a command. This "escape" mechanism allows many extra commands
+ * to be encoded and this encoding technique helps to minimize the length of
+ * the charStrings.
+ */
+var Type1CharString = (function Type1CharStringClosure() {
+ var COMMAND_MAP = {
+ 'hstem': [1],
+ 'vstem': [3],
+ 'vmoveto': [4],
+ 'rlineto': [5],
+ 'hlineto': [6],
+ 'vlineto': [7],
+ 'rrcurveto': [8],
+ 'callsubr': [10],
+ 'flex': [12, 35],
+ 'drop' : [12, 18],
+ 'endchar': [14],
+ 'rmoveto': [21],
+ 'hmoveto': [22],
+ 'vhcurveto': [30],
+ 'hvcurveto': [31]
+ };
+
+ function Type1CharString() {
+ this.width = 0;
+ this.lsb = 0;
+ this.flexing = false;
+ this.output = [];
+ this.stack = [];
}
- return CallothersubrCmd;
+ Type1CharString.prototype = {
+ convert: function Type1CharString_convert(encoded, subrs) {
+ var count = encoded.length;
+ var error = false;
+ for (var i = 0; i < count; i++) {
+ var value = encoded[i];
+ if (value < 32) {
+ if (value === 12) {
+ value = (value << 8) + encoded[++i];
+ }
+ switch (value) {
+ case 1: // hstem
+ if (!HINTING_ENABLED) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.hstem);
+ break;
+ case 3: // vstem
+ if (!HINTING_ENABLED) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.vstem);
+ break;
+ case 4: // vmoveto
+ if (this.flexing) {
+ if (this.stack.length < 1) {
+ error = true;
+ break;
+ }
+ // Add the dx for flex and but also swap the values so they are
+ // the right order.
+ var dy = this.stack.pop();
+ this.stack.push(0, dy);
+ break;
+ }
+ error = this.executeCommand(1, COMMAND_MAP.vmoveto);
+ break;
+ case 5: // rlineto
+ error = this.executeCommand(2, COMMAND_MAP.rlineto);
+ break;
+ case 6: // hlineto
+ error = this.executeCommand(1, COMMAND_MAP.hlineto);
+ break;
+ case 7: // vlineto
+ error = this.executeCommand(1, COMMAND_MAP.vlineto);
+ break;
+ case 8: // rrcurveto
+ error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
+ break;
+ case 9: // closepath
+ // closepath is a Type1 command that does not take argument and is
+ // useless in Type2 and it can simply be ignored.
+ this.stack = [];
+ break;
+ case 10: // callsubr
+ if (this.stack.length < 1) {
+ error = true;
+ break;
+ }
+ var subrNumber = this.stack.pop();
+ error = this.convert(subrs[subrNumber], subrs);
+ break;
+ case 11: // return
+ return error;
+ case 13: // hsbw
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ // To convert to type2 we have to move the width value to the
+ // first part of the charstring and then use hmoveto with lsb.
+ var wx = this.stack.pop();
+ var sbx = this.stack.pop();
+ this.lsb = sbx;
+ this.width = wx;
+ this.stack.push(sbx);
+ error = this.executeCommand(1, COMMAND_MAP.hmoveto);
+ break;
+ case 14: // endchar
+ this.output.push(COMMAND_MAP.endchar[0]);
+ break;
+ case 21: // rmoveto
+ if (this.flexing) {
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.rmoveto);
+ break;
+ case 22: // hmoveto
+ if (this.flexing) {
+ // Add the dy for flex.
+ this.stack.push(0);
+ break;
+ }
+ error = this.executeCommand(1, COMMAND_MAP.hmoveto);
+ break;
+ case 30: // vhcurveto
+ error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
+ break;
+ case 31: // hvcurveto
+ error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
+ break;
+ case (12 << 8) + 0: // dotsection
+ // dotsection is a Type1 command to specify some hinting feature
+ // for dots that do not take a parameter and it can safely be
+ // ignored for Type2.
+ this.stack = [];
+ break;
+ case (12 << 8) + 1: // vstem3
+ if (!HINTING_ENABLED) {
+ this.stack = [];
+ break;
+ }
+ // [vh]stem3 are Type1 only and Type2 supports [vh]stem with
+ // multiple parameters, so instead of returning [vh]stem3 take a
+ // shortcut and return [vhstem] instead.
+ error = this.executeCommand(2, COMMAND_MAP.vstem);
+ break;
+ case (12 << 8) + 2: // hstem3
+ if (!HINTING_ENABLED) {
+ this.stack = [];
+ break;
+ }
+ // See vstem3.
+ error = this.executeCommand(2, COMMAND_MAP.hstem);
+ break;
+ case (12 << 8) + 6: // seac
+ // seac is like type 2's special endchar but it doesn't use the
+ // first argument asb, so remove it.
+ error = this.executeCommand(4, COMMAND_MAP.endchar);
+ break;
+ case (12 << 8) + 7: // sbw
+ if (this.stack.length < 4) {
+ error = true;
+ break;
+ }
+ // To convert to type2 we have to move the width value to the
+ // first part of the charstring and then use rmoveto with
+ // (dx, dy). The height argument will not be used for vmtx and
+ // vhea tables reconstruction -- ignoring it.
+ var wy = this.stack.pop();
+ var wx = this.stack.pop();
+ var sby = this.stack.pop();
+ var sbx = this.stack.pop();
+ this.lsb = sbx;
+ this.width = wx;
+ this.stack.push(sbx, sby);
+ error = this.executeCommand(2, COMMAND_MAP.rmoveto);
+ break;
+ case (12 << 8) + 12: // div
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ var num2 = this.stack.pop();
+ var num1 = this.stack.pop();
+ this.stack.push(num1 / num2);
+ break;
+ case (12 << 8) + 16: // callothersubr
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ var subrNumber = this.stack.pop();
+ var numArgs = this.stack.pop();
+ if (subrNumber === 0 && numArgs === 3) {
+ var flexArgs = this.stack.splice(this.stack.length - 17, 17);
+ this.stack.push(
+ flexArgs[2] + flexArgs[0], // bcp1x + rpx
+ flexArgs[3] + flexArgs[1], // bcp1y + rpy
+ flexArgs[4], // bcp2x
+ flexArgs[5], // bcp2y
+ flexArgs[6], // p2x
+ flexArgs[7], // p2y
+ flexArgs[8], // bcp3x
+ flexArgs[9], // bcp3y
+ flexArgs[10], // bcp4x
+ flexArgs[11], // bcp4y
+ flexArgs[12], // p3x
+ flexArgs[13], // p3y
+ flexArgs[14] // flexDepth
+ // 15 = finalx unused by flex
+ // 16 = finaly unused by flex
+ );
+ error = this.executeCommand(13, COMMAND_MAP.flex, true);
+ this.flexing = false;
+ this.stack.push(flexArgs[15], flexArgs[16]);
+ } else if (subrNumber === 1 && numArgs === 0) {
+ this.flexing = true;
+ }
+ break;
+ case (12 << 8) + 17: // pop
+ // Ignore this since it is only used with othersubr.
+ break;
+ case (12 << 8) + 33: // setcurrentpoint
+ // Ignore for now.
+ this.stack = [];
+ break;
+ default:
+ warn('Unknown type 1 charstring command of "' + value + '"');
+ break;
+ }
+ if (error) {
+ break;
+ }
+ continue;
+ } else if (value <= 246) {
+ value = value - 139;
+ } else if (value <= 250) {
+ value = ((value - 247) * 256) + encoded[++i] + 108;
+ } else if (value <= 254) {
+ value = -((value - 251) * 256) - encoded[++i] - 108;
+ } else {
+ value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
+ (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
+ }
+ this.stack.push(value);
+ }
+ return error;
+ },
+
+ executeCommand: function(howManyArgs, command, keepStack) {
+ var stackLength = this.stack.length;
+ if (howManyArgs > stackLength) {
+ return true;
+ }
+ var start = stackLength - howManyArgs;
+ for (var i = start; i < stackLength; i++) {
+ var value = this.stack[i];
+ if (value === (value | 0)) { // int
+ this.output.push(28, (value >> 8) & 0xff, value & 0xff);
+ } else { // fixed point
+ value = (65536 * value) | 0;
+ this.output.push(255,
+ (value >> 24) & 0xFF,
+ (value >> 16) & 0xFF,
+ (value >> 8) & 0xFF,
+ value & 0xFF);
+ }
+ }
+ this.output.push.apply(this.output, command);
+ if (keepStack) {
+ this.stack.splice(start, howManyArgs);
+ } else {
+ this.stack = [];
+ }
+ return false;
+ }
+ };
+
+ return Type1CharString;
})();
/*
@@ -19717,338 +20179,6 @@ var Type1Parser = function type1Parser() {
return decryptedString.slice(discardNumber);
}
- /*
- * CharStrings are encoded following the the CharString Encoding sequence
- * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
- * The value in a byte indicates a command, a number, or subsequent bytes
- * that are to be interpreted in a special way.
- *
- * CharString Number Encoding:
- * A CharString byte containing the values from 32 through 255 inclusive
- * indicate an integer. These values are decoded in four ranges.
- *
- * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
- * indicate the integer v - 139. Thus, the integer values from -107 through
- * 107 inclusive may be encoded in single byte.
- *
- * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
- * indicates an integer involving the next byte, w, according to the formula:
- * [(v - 247) x 256] + w + 108
- *
- * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
- * indicates an integer involving the next byte, w, according to the formula:
- * -[(v - 251) * 256] - w - 108
- *
- * 4. A CharString containing the value 255 indicates that the next 4 bytes
- * are a two complement signed integer. The first of these bytes contains the
- * highest order bits, the second byte contains the next higher order bits
- * and the fourth byte contain the lowest order bits.
- *
- *
- * CharString Command Encoding:
- * CharStrings commands are encoded in 1 or 2 bytes.
- *
- * Single byte commands are encoded in 1 byte that contains a value between
- * 0 and 31 inclusive.
- * If a command byte contains the value 12, then the value in the next byte
- * indicates a command. This "escape" mechanism allows many extra commands
- * to be encoded and this encoding technique helps to minimize the length of
- * the charStrings.
- */
- var charStringDictionary = {
- '1': 'hstem',
- '3': 'vstem',
- '4': 'vmoveto',
- '5': 'rlineto',
- '6': 'hlineto',
- '7': 'vlineto',
- '8': 'rrcurveto',
-
- // closepath is a Type1 command that do not take argument and is useless
- // in Type2 and it can simply be ignored.
- '9': null, // closepath
-
- '10': 'callsubr',
-
- // return is normally used inside sub-routines to tells to the execution
- // flow that it can be back to normal.
- // During the translation process Type1 charstrings will be flattened and
- // sub-routines will be embedded directly into the charstring directly, so
- // this can be ignored safely.
- '11': 'return',
-
- '12': {
- // dotsection is a Type1 command to specify some hinting feature for dots
- // that do not take a parameter and it can safely be ignored for Type2.
- '0': null, // dotsection
-
- // [vh]stem3 are Type1 only and Type2 supports [vh]stem with multiple
- // parameters, so instead of returning [vh]stem3 take a shortcut and
- // return [vhstem] instead.
- '1': 'vstem',
- '2': 'hstem',
-
- '6': 'endchar', // seac
- // Type1 only command with command not (yet) built-in ,throw an error
- '7': -1, // sbw
-
- '10': 'add',
- '11': 'sub',
- '12': 'div',
-
- // callothersubr is a mechanism to make calls on the postscript
- // interpreter, this is not supported by Type2 charstring but hopefully
- // most of the default commands can be ignored safely.
- '16': 'callothersubr',
-
- '17': 'pop',
-
- // setcurrentpoint sets the current point to x, y without performing a
- // moveto (this is a one shot positionning command). This is used only
- // with the return of an OtherSubrs call.
- // TODO Implement the OtherSubrs charstring embedding and replace this
- // call by a no-op, like 2 'pop' commands for example.
- '33': null // setcurrentpoint
- },
- '13': 'hsbw',
- '14': 'endchar',
- '21': 'rmoveto',
- '22': 'hmoveto',
- '30': 'vhcurveto',
- '31': 'hvcurveto'
- };
-
- var ESCAPE_CMD = 12;
-
- // Breaks up the stack by arguments and also calculates the value.
- function breakUpArgs(stack, numArgs) {
- var args = [];
- var index = stack.length - 1;
- for (var i = 0; i < numArgs; i++) {
- if (index < 0) {
- args.unshift({ arg: [0],
- value: 0,
- offset: 0 });
- warn('Malformed charstring stack: not enough values on stack.');
- continue;
- }
- var token = stack[index];
- if (token === 'div') {
- var a = stack[index - 2];
- var b = stack[index - 1];
- if (!isInt(a) || !isInt(b)) {
- warn('Malformed charsting stack: expected ints on stack for div.');
- a = 0;
- b = 1;
- }
- args.unshift({ arg: [a, b, 'div'],
- value: a / b,
- offset: index - 2 });
- index -= 3;
- } else if (isInt(token)) {
- args.unshift({ arg: stack.slice(index, index + 1),
- value: token,
- offset: index });
- index--;
- } else {
- warn('Malformed charsting stack: found bad token ' + token + '.');
- }
- }
- return args;
- }
-
- function decodeCharString(array) {
- var charstring = [];
- var lsb = 0;
- var width = 0;
- var flexing = false;
-
- var value = '';
- var count = array.length;
- for (var i = 0; i < count; i++) {
- value = array[i];
-
- if (value < 32) {
- var command = null;
- if (value == ESCAPE_CMD) {
- var escape = array[++i];
-
- // TODO Clean this code
- if (escape == 16) {
- var index = charstring.pop();
- var argc = charstring.pop();
- for (var j = 0; j < argc; j++)
- charstring.push('drop');
-
- // If the flex mechanism is not used in a font program, Adobe
- // states that entries 0, 1 and 2 can simply be replaced 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}
- // TODO support hint replacment
- if (index == 3) {
- charstring.push(3);
- i++;
- continue;
- }
-
- assert(argc == 0, 'callothersubr with arguments is not supported');
- charstring.push(new CallothersubrCmd(index));
- continue;
- } else if (escape == 7) { // sbw
- var args = breakUpArgs(charstring, 4);
- var arg0 = args[0];
- var arg1 = args[1];
- var arg2 = args[2];
- lsb = arg0.value;
- width = arg2.value;
- // To convert to type2 we have to move the width value to the first
- // part of the charstring and then use rmoveto with (dx, dy).
- // The height argument will not be used for vmtx and vhea tables
- // reconstruction -- ignoring it.
- charstring = arg2.arg;
- charstring = charstring.concat(arg0.arg, arg1.arg);
- charstring.push('rmoveto');
- continue;
- } else if (escape == 17 || escape == 33) {
- // pop or setcurrentpoint commands can be ignored
- // since we are not doing callothersubr
- continue;
- } else if (escape == 6) {
- // seac is like type 2's special endchar but it doesn't use the
- // first argument asb, so remove it.
- var args = breakUpArgs(charstring, 5);
- var arg0 = args[0];
- charstring.splice(arg0.offset, arg0.arg.length);
- } else if (!HINTING_ENABLED && (escape == 1 || escape == 2)) {
- charstring.push('drop', 'drop', 'drop', 'drop', 'drop', 'drop');
- continue;
- }
-
- command = charStringDictionary['12'][escape];
- } else {
- if (value == 13) { // hsbw
- var args = breakUpArgs(charstring, 2);
- var arg0 = args[0];
- var arg1 = args[1];
- lsb = arg0.value;
- width = arg1.value;
- // To convert to type2 we have to move the width value to the first
- // part of the charstring and then use hmoveto with lsb.
- charstring = arg1.arg;
- charstring = charstring.concat(arg0.arg);
- charstring.push('hmoveto');
- continue;
- } else if (value == 10) { // callsubr
- if (charstring[charstring.length - 1] < 3) { // subr #0..2
- // XXX: According to the spec if flex or hinting is not used then
- // subroutines 0-3 can actually be anything defined by the font,
- // so we really shouldn't be doing flex here but when
- // callothersubr 0-2 is used. There hasn't been a real world
- // example of this yet so we'll keep doing it here.
- var subrNumber = charstring.pop();
- switch (subrNumber) {
- case 1:
- flexing = true; // prepare for flex coordinates
- break;
- case 0:
- var flexArgs = breakUpArgs(charstring, 17);
-
- // removing all flex arguments from the stack
- charstring.splice(flexArgs[0].offset,
- charstring.length - flexArgs[0].offset);
-
- charstring = charstring.concat(
- flexArgs[0].arg, // bcp1x +
- flexArgs[2].arg, // rpx
- ['add'],
- flexArgs[1].arg, // bcp1y +
- flexArgs[3].arg, // rpy
- ['add'],
- flexArgs[4].arg, // bcp2x
- flexArgs[5].arg, // bcp2y
- flexArgs[6].arg, // p2x
- flexArgs[7].arg, // p2y
- flexArgs[8].arg, // bcp3x
- flexArgs[9].arg, // bcp3y
- flexArgs[10].arg, // bcp4x
- flexArgs[11].arg, // bcp4y
- flexArgs[12].arg, // p3x
- flexArgs[13].arg, // p3y
- flexArgs[14].arg, // flexDepth
- // 15 = finalx unused by flex
- // 16 = finaly unused by flex
- ['flex']
- );
-
- flexing = false;
- break;
- }
- continue;
- }
- } else if (value == 21 && flexing) { // rmoveto
- continue; // ignoring rmoveto
- } else if (value == 22 && flexing) { // hmoveto
- // Add the dy for flex.
- charstring.push(0);
- continue; // ignoring hmoveto
- } else if (value == 4 && flexing) { // vmoveto
- // Insert the dx for flex before dy.
- var flexArgs = breakUpArgs(charstring, 1);
- charstring.splice(flexArgs[0].offset, 0, 0);
- continue; // ignoring vmoveto
- } else if (!HINTING_ENABLED && (value == 1 || value == 3)) {
- charstring.push('drop', 'drop');
- continue;
- }
- command = charStringDictionary[value];
- }
-
- // Some charstring commands are meaningless in Type2 and will return
- // a null, let's just ignored them
- if (!command && i < count) {
- continue;
- } else if (!command) {
- break;
- } else if (command == -1) {
- warn('Support for Type1 command ' + value +
- ' (' + escape + ') is not implemented in charstring: ' +
- charstring);
- if (value == 12) {
- // we know how to ignore only some the Type1 commands
- switch (escape) {
- case 7:
- charstring.push('drop', 'drop', 'drop', 'drop');
- continue;
- case 8:
- charstring.push('drop');
- continue;
- }
- }
- }
-
- value = command;
- } else if (value <= 246) {
- value = value - 139;
- } else if (value <= 250) {
- value = ((value - 247) * 256) + array[++i] + 108;
- } else if (value <= 254) {
- value = -((value - 251) * 256) - array[++i] - 108;
- } else {
- value = (array[++i] & 0xff) << 24 | (array[++i] & 0xff) << 16 |
- (array[++i] & 0xff) << 8 | (array[++i] & 0xff) << 0;
- }
-
- charstring.push(value);
- }
-
- return { charstring: charstring, width: width, lsb: lsb };
- }
-
/*
* Returns an object containing a Subrs array and a CharStrings
* array extracted from and eexec encrypted block of data
@@ -20116,6 +20246,7 @@ var Type1Parser = function type1Parser() {
eexecStr += String.fromCharCode(eexec[i]);
var glyphsSection = false, subrsSection = false;
+ var subrs = [], charstrings = [];
var program = {
subrs: [],
charstrings: [],
@@ -20151,17 +20282,14 @@ var Type1Parser = function type1Parser() {
var data = eexec.slice(i, i + length);
var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
- var str = decodeCharString(encoded);
if (glyphsSection) {
- program.charstrings.push({
+ charstrings.push({
glyph: glyph,
- data: str.charstring,
- lsb: str.lsb,
- width: str.width
+ encoded: encoded
});
} else {
- program.subrs.push(str.charstring);
+ subrs.push(encoded);
}
i += length;
token = '';
@@ -20193,12 +20321,11 @@ var Type1Parser = function type1Parser() {
var data = eexec.slice(i + 1, i + 1 + length);
var lenIV = program.properties.privateData['lenIV'];
var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
- var str = decodeCharString(encoded);
i = i + 1 + length;
t = getToken(); // read in 'NP'
if (t == 'noaccess')
getToken(); // read in 'put'
- program.subrs[index] = str.charstring;
+ subrs[index] = encoded;
}
break;
case '/BlueValues':
@@ -20208,7 +20335,7 @@ var Type1Parser = function type1Parser() {
var blueArray = readNumberArray(eexecStr, i + 1);
// *Blue* values may contain invalid data: disables reading of
// those values when hinting is disabled.
- if (blueArray.length > 0 && (blueArray.length % 2) == 0 &&
+ if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
HINTING_ENABLED) {
program.properties.privateData[token.substring(1)] = blueArray;
}
@@ -20245,6 +20372,26 @@ var Type1Parser = function type1Parser() {
}
}
+ for (var i = 0; i < charstrings.length; i++) {
+ var glyph = charstrings[i].glyph;
+ var encoded = charstrings[i].encoded;
+ var charString = new Type1CharString();
+ var error = charString.convert(encoded, subrs);
+ var output = charString.output;
+ if (error) {
+ // It seems when FreeType encounters an error while evaluating a glyph
+ // that it completely ignores the glyph so we'll mimic that behaviour
+ // here and put an endchar to make the validator happy.
+ output = [14];
+ }
+ program.charstrings.push({
+ glyph: glyph,
+ data: output,
+ lsb: charString.lsb,
+ width: charString.width
+ });
+ }
+
return program;
};
@@ -20436,14 +20583,11 @@ Type1Font.prototype = {
},
getType2Charstrings: function Type1Font_getType2Charstrings(
- type1Subrs) {
+ type1Charstrings) {
var type2Charstrings = [];
- var count = type1Subrs.length;
- var type1Charstrings = [];
- for (var i = 0; i < count; i++)
- type1Charstrings.push(type1Subrs[i].charstring.slice());
- for (var i = 0; i < count; i++)
- type2Charstrings.push(this.flattenCharstring(type1Charstrings, i));
+ for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
+ type2Charstrings.push(type1Charstrings[i].charstring);
+ }
return type2Charstrings;
},
@@ -20463,81 +20607,12 @@ Type1Font.prototype = {
type2Subrs.push([0x0B]);
for (var i = 0; i < count; i++) {
- type2Subrs.push(this.flattenCharstring(type1Subrs, i));
+ type2Subrs.push(type1Subrs[i]);
}
return type2Subrs;
},
- /*
- * Flatten the commands by interpreting the postscript code and replacing
- * every 'callsubr', 'callothersubr' by the real commands.
- */
- commandsMap: {
- 'hstem': 1,
- 'vstem': 3,
- 'vmoveto': 4,
- 'rlineto': 5,
- 'hlineto': 6,
- 'vlineto': 7,
- 'rrcurveto': 8,
- 'callsubr': 10,
- 'return': 11,
- 'add': [12, 10],
- 'sub': [12, 11],
- 'div': [12, 12],
- 'exch': [12, 28],
- 'flex': [12, 35],
- 'drop' : [12, 18],
- 'endchar': 14,
- 'rmoveto': 21,
- 'hmoveto': 22,
- 'vhcurveto': 30,
- 'hvcurveto': 31
- },
-
- flattenCharstring: function Type1Font_flattenCharstring(charstrings, index) {
- var charstring = charstrings[index];
- if (!charstring)
- return [0x0B];
- var map = this.commandsMap;
- // charstring changes size - can't cache .length in loop
- for (var i = 0; i < charstring.length; i++) {
- var command = charstring[i];
- if (typeof command === 'string') {
- var cmd = map[command];
- assert(cmd, 'Unknow command: ' + command);
-
- if (isArray(cmd))
- charstring.splice(i++, 1, cmd[0], cmd[1]);
- else
- charstring[i] = cmd;
- } else if (command instanceof CallothersubrCmd) {
- var otherSubrCharstring = charstrings[command.index];
- if (otherSubrCharstring) {
- var lastCommand = otherSubrCharstring.indexOf('return');
- if (lastCommand >= 0)
- otherSubrCharstring = otherSubrCharstring.slice(0, lastCommand);
- charstring.splice.apply(charstring,
- [i, 1].concat(otherSubrCharstring));
- } else
- charstring.splice(i, 1); // ignoring empty subr call
- i--;
- } else {
- // Type1 charstring use a division for number above 32000
- if (command > 32000) {
- var divisor = charstring[i + 1];
- command /= divisor;
- charstring.splice(i, 3, 28, (command >> 8) & 0xff, command & 0xff);
- } else {
- charstring.splice(i, 1, 28, (command >> 8) & 0xff, command & 0xff);
- }
- i += 2;
- }
- }
- return charstring;
- },
-
wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
var cff = new CFF();
cff.header = new CFFHeader(1, 0, 4, 4);
@@ -20545,11 +20620,13 @@ Type1Font.prototype = {
cff.names = [name];
var topDict = new CFFTopDict();
- topDict.setByName('version', 0);
- topDict.setByName('Notice', 1);
- topDict.setByName('FullName', 2);
- topDict.setByName('FamilyName', 3);
- topDict.setByName('Weight', 4);
+ // CFF strings IDs 0...390 are predefined names, so refering
+ // to entries in our own String INDEX starts at SID 391.
+ topDict.setByName('version', 391);
+ topDict.setByName('Notice', 392);
+ topDict.setByName('FullName', 393);
+ topDict.setByName('FamilyName', 394);
+ topDict.setByName('Weight', 395);
topDict.setByName('Encoding', null); // placeholder
topDict.setByName('FontMatrix', properties.fontMatrix);
topDict.setByName('FontBBox', properties.bbox);
@@ -20632,7 +20709,7 @@ var CFFFont = (function CFFFontClosure() {
this.properties = properties;
var parser = new CFFParser(file, properties);
- var cff = parser.parse(true);
+ var cff = parser.parse();
var compiler = new CFFCompiler(cff);
this.readExtra(cff);
try {
@@ -20719,9 +20796,9 @@ var CFFFont = (function CFFFontClosure() {
var CFFParser = (function CFFParserClosure() {
var CharstringValidationData = [
null,
- { id: 'hstem', min: 2, resetStack: true },
+ { id: 'hstem', min: 2, resetStack: true, stem: true },
null,
- { id: 'vstem', min: 2, resetStack: true },
+ { id: 'vstem', min: 2, resetStack: true, stem: true },
{ id: 'vmoveto', min: 1, resetStack: true },
{ id: 'rlineto', min: 2, resetStack: true },
{ id: 'hlineto', min: 1, resetStack: true },
@@ -20729,19 +20806,19 @@ var CFFParser = (function CFFParserClosure() {
{ id: 'rrcurveto', min: 6, resetStack: true },
null,
{ id: 'callsubr', min: 1, undefStack: true },
- { id: 'return', min: 0, resetStack: true },
+ { id: 'return', min: 0, undefStack: true },
null, // 12
null,
null, // endchar
null,
null,
null,
- { id: 'hstemhm', min: 2, resetStack: true },
+ { id: 'hstemhm', min: 2, resetStack: true, stem: true },
null, // hintmask
null, // cntrmask
{ id: 'rmoveto', min: 2, resetStack: true },
{ id: 'hmoveto', min: 1, resetStack: true },
- { id: 'vstemhm', min: 2, resetStack: true },
+ { id: 'vstemhm', min: 2, resetStack: true, stem: true },
{ id: 'rcurveline', min: 8, resetStack: true },
{ id: 'rlinecurve', min: 8, resetStack: true },
{ id: 'vvcurveto', min: 4, resetStack: true },
@@ -20757,7 +20834,7 @@ var CFFParser = (function CFFParserClosure() {
null,
{ id: 'and', min: 2, stackDelta: -1 },
{ id: 'or', min: 2, stackDelta: -1 },
- { id: 'not', min: 2, stackDelta: -1 },
+ { id: 'not', min: 1, stackDelta: 0 },
null,
null,
null,
@@ -20797,7 +20874,7 @@ var CFFParser = (function CFFParserClosure() {
this.properties = properties;
}
CFFParser.prototype = {
- parse: function CFFParser_parse(normalizeCIDData) {
+ parse: function CFFParser_parse() {
var properties = this.properties;
var cff = new CFF();
this.cff = cff;
@@ -20865,30 +20942,6 @@ var CFFParser = (function CFFParserClosure() {
cff.charset = charset;
cff.encoding = encoding;
- if (!cff.isCIDFont || !normalizeCIDData)
- return cff;
-
- // DirectWrite does not like CID fonts data. Trying to convert/flatten
- // the font data and remove CID properties.
- if (cff.fdArray.length !== 1) {
- warn('Unable to normalize CID font in CFF data -- using font as is');
- return cff;
- }
-
- var fontDict = cff.fdArray[0];
- // Make the sanitizer happy and remove anything that is only for CID
- // fonts.
- fontDict.setByKey(17, topDict.getByName('CharStrings'));
- fontDict.removeByName('CIDFontVersion');
- fontDict.removeByName('CIDFontRevision');
- fontDict.removeByName('CIDFontType');
- fontDict.removeByName('CIDCount');
- fontDict.removeByName('UIDBase');
- cff.topDict = fontDict;
- cff.isCIDFont = false;
- delete cff.fdArray;
- delete cff.fdSelect;
-
return cff;
},
parseHeader: function CFFParser_parseHeader() {
@@ -20898,7 +20951,7 @@ var CFFParser = (function CFFParserClosure() {
while (bytes[offset] != 1)
++offset;
- if (offset != 0) {
+ if (offset !== 0) {
info('cff data is shifted');
bytes = bytes.subarray(offset);
this.bytes = bytes;
@@ -20988,7 +21041,7 @@ var CFFParser = (function CFFParserClosure() {
var start = pos;
var end = pos;
- if (count != 0) {
+ if (count !== 0) {
var offsetSize = bytes[pos++];
// add 1 for offset to determine size of last object
var startPos = pos + ((count + 1) * offsetSize) - 1;
@@ -21045,8 +21098,8 @@ var CFFParser = (function CFFParserClosure() {
}
return strings;
},
- createDict: function CFFParser_createDict(type, dict, strings) {
- var cffDict = new type(strings);
+ createDict: function CFFParser_createDict(Type, dict, strings) {
+ var cffDict = new Type(strings);
var types = cffDict.types;
for (var i = 0, ii = dict.length; i < ii; ++i) {
@@ -21074,7 +21127,7 @@ var CFFParser = (function CFFParserClosure() {
var validationCommand = null;
if (value == 12) {
var q = data[j++];
- if (q == 0) {
+ if (q === 0) {
// The CFF specification state that the 'dotsection' command
// (12, 0) is deprecated and treated as a no-op, but all Type2
// charstrings processors should support them. Unfortunately
@@ -21101,9 +21154,6 @@ var CFFParser = (function CFFParserClosure() {
} else if (value == 255) { // number (32 bit)
j += 4;
stackSize++;
- } else if (value == 18 || value == 23) {
- hints += stackSize >> 1;
- validationCommand = CharstringValidationData[value];
} else if (value == 19 || value == 20) {
hints += stackSize >> 1;
j += (hints + 7) >> 3; // skipping right amount of hints flag data
@@ -21112,6 +21162,9 @@ var CFFParser = (function CFFParserClosure() {
validationCommand = CharstringValidationData[value];
}
if (validationCommand) {
+ if (validationCommand.stem) {
+ hints += stackSize >> 1;
+ }
if ('min' in validationCommand) {
if (!undefStack && stackSize < validationCommand.min) {
warn('Not enough parameters for ' + validationCommand.id +
@@ -21178,7 +21231,7 @@ var CFFParser = (function CFFParserClosure() {
privateDict.subrsIndex = subrsIndex.obj;
},
parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
- if (pos == 0) {
+ if (pos === 0) {
return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
ISOAdobeCharset);
} else if (pos == 1) {
@@ -21249,7 +21302,7 @@ var CFFParser = (function CFFParserClosure() {
}
}
- if (pos == 0 || pos == 1) {
+ if (pos === 0 || pos == 1) {
predefined = true;
format = pos;
var baseEncoding = pos ? Encodings.ExpertEncoding :
@@ -21502,7 +21555,7 @@ var CFFTopDict = (function CFFTopDictClosure() {
[[12, 5], 'PaintType', 'num', 0],
[[12, 6], 'CharstringType', 'num', 2],
[[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],
- [.001, 0, 0, .001, 0, 0]],
+ [0.001, 0, 0, 0.001, 0, 0]],
[13, 'UniqueID', 'num', null],
[5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],
[[12, 8], 'StrokeWidth', 'num', 0],
@@ -21519,9 +21572,12 @@ var CFFTopDict = (function CFFTopDictClosure() {
[[12, 33], 'CIDFontType', 'num', 0],
[[12, 34], 'CIDCount', 'num', 8720],
[[12, 35], 'UIDBase', 'num', null],
- [[12, 36], 'FDArray', 'offset', null],
+ // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes
+ // before FDArray.
[[12, 37], 'FDSelect', 'offset', null],
- [[12, 38], 'FontName', 'sid', null]];
+ [[12, 36], 'FDArray', 'offset', null],
+ [[12, 38], 'FontName', 'sid', null]
+ ];
var tables = null;
function CFFTopDict(strings) {
if (tables === null)
@@ -21669,7 +21725,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
array[i] = str.charCodeAt(i);
return array;
- };
+ }
function CFFCompiler(cff) {
this.cff = cff;
}
@@ -21692,7 +21748,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
var nameIndex = this.compileNameIndex(cff.names);
output.add(nameIndex);
- var compiled = this.compileTopDicts([cff.topDict], output.length);
+ var compiled = this.compileTopDicts([cff.topDict],
+ output.length,
+ cff.isCIDFont);
output.add(compiled.output);
var topDictTracker = compiled.trackers[0];
@@ -21735,8 +21793,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
topDictTracker.setEntryLocation('FDSelect', [output.length], output);
var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
output.add(fdSelect);
-
- var compiled = this.compileTopDicts(cff.fdArray, output.length);
+ // It is unclear if the sub font dictionary can have CID related
+ // dictionary keys, but the sanitizer doesn't like them so remove them.
+ var compiled = this.compileTopDicts(cff.fdArray, output.length, true);
topDictTracker.setEntryLocation('FDArray', [output.length], output);
output.add(compiled.output);
var fontDictTrackers = compiled.trackers;
@@ -21749,7 +21808,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
return output.data;
},
encodeNumber: function CFFCompiler_encodeNumber(value) {
- if (parseFloat(value) == parseInt(value) && !isNaN(value)) // isInt
+ if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) // isInt
return this.encodeInteger(value);
else
return this.encodeFloat(value);
@@ -21811,11 +21870,20 @@ var CFFCompiler = (function CFFCompilerClosure() {
nameIndex.add(stringToArray(names[i]));
return this.compileIndex(nameIndex);
},
- compileTopDicts: function CFFCompiler_compileTopDicts(dicts, length) {
+ compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
+ length,
+ removeCidKeys) {
var fontDictTrackers = [];
var fdArrayIndex = new CFFIndex();
for (var i = 0, ii = dicts.length; i < ii; ++i) {
var fontDict = dicts[i];
+ if (removeCidKeys) {
+ fontDict.removeByName('CIDFontVersion');
+ fontDict.removeByName('CIDFontRevision');
+ fontDict.removeByName('CIDFontType');
+ fontDict.removeByName('CIDCount');
+ fontDict.removeByName('UIDBase');
+ }
var fontDictTracker = new CFFOffsetTracker();
var fontDictData = this.compileDict(fontDict, fontDictTracker);
fontDictTrackers.push(fontDictTracker);
@@ -21940,7 +22008,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
// If there is no object, just create an index. This technically
// should just be [0, 0] but OTS has an issue with that.
- if (count == 0)
+ if (count === 0)
return [0, 0, 0];
var data = [(count >> 8) & 0xFF, count & 0xff];
@@ -26461,7 +26529,7 @@ var PDFImage = (function PDFImageClosure() {
var buf = 0;
for (var i = 0, ii = length; i < ii; ++i) {
- if (i % rowComps == 0) {
+ if (i % rowComps === 0) {
mask = 0;
buf = 0;
} else {
@@ -26479,7 +26547,7 @@ var PDFImage = (function PDFImageClosure() {
// The general case that handles all other bpc values.
var bits = 0, buf = 0;
for (var i = 0, ii = length; i < ii; ++i) {
- if (i % rowComps == 0) {
+ if (i % rowComps === 0) {
buf = 0;
bits = 0;
}
@@ -26575,7 +26643,7 @@ var PDFImage = (function PDFImageClosure() {
buf = imgArray[imgArrayPos++];
mask = 128;
}
- if (!(buf & mask) == inverseDecode) {
+ if (!(buf & mask) === inverseDecode) {
buffer[bufferPos] = 0;
}
bufferPos += 4;
@@ -29724,7 +29792,8 @@ var Parser = (function ParserClosure() {
// searching for the /EI\s/
var state = 0, ch;
- while (state != 4 && (ch = stream.getByte()) != null) {
+ while (state != 4 &&
+ (ch = stream.getByte()) !== null && ch !== undefined) {
switch (ch) {
case 0x20:
case 0x0D:
@@ -29955,7 +30024,7 @@ var Lexer = (function LexerClosure() {
str += ch;
break;
case ')':
- if (--numParen == 0) {
+ if (--numParen === 0) {
done = true;
} else {
str += ch;
@@ -30067,13 +30136,13 @@ var Lexer = (function LexerClosure() {
if (isFirstHex) {
firstDigit = toHexDigit(ch);
if (firstDigit === -1) {
- warn("Ignoring invalid character '" + ch + "' in hex string");
+ warn('Ignoring invalid character "' + ch + '" in hex string');
continue;
}
} else {
secondDigit = toHexDigit(ch);
if (secondDigit === -1) {
- warn("Ignoring invalid character '" + ch + "' in hex string");
+ warn('Ignoring invalid character "' + ch + '" in hex string');
continue;
}
str += String.fromCharCode((firstDigit << 4) | secondDigit);
@@ -30131,6 +30200,7 @@ var Lexer = (function LexerClosure() {
stream.skip();
return Cmd.get('>>');
}
+ return Cmd.get(ch);
case '{':
case '}':
return Cmd.get(ch);
@@ -30854,7 +30924,7 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
function streamSequenceStreamReadBlock() {
var streams = this.streams;
- if (streams.length == 0) {
+ if (streams.length === 0) {
this.eof = true;
return;
}
@@ -30974,7 +31044,7 @@ var FlateStream = (function FlateStreamClosure() {
error('Invalid header in flate stream: ' + cmf + ', ' + flg);
if ((cmf & 0x0f) != 0x08)
error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
- if ((((cmf << 8) + flg) % 31) != 0)
+ if ((((cmf << 8) + flg) % 31) !== 0)
error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
if (flg & 0x20)
error('FDICT bit set in flate stream: ' + cmf + ', ' + flg);
@@ -31028,7 +31098,7 @@ var FlateStream = (function FlateStreamClosure() {
var code = codes[codeBuf & ((1 << maxLen) - 1)];
var codeLen = code >> 16;
var codeVal = code & 0xffff;
- if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
+ if (codeSize === 0 || codeSize < codeLen || codeLen === 0)
error('Bad encoding in flate stream');
this.codeBuf = (codeBuf >> codeLen);
this.codeSize = (codeSize - codeLen);
@@ -31082,7 +31152,7 @@ var FlateStream = (function FlateStreamClosure() {
this.eof = true;
hdr >>= 1;
- if (hdr == 0) { // uncompressed block
+ if (hdr === 0) { // uncompressed block
var bytes = this.bytes;
var bytesPos = this.bytesPos;
var b;
@@ -31315,7 +31385,7 @@ var PredictorStream = (function PredictorStreamClosure() {
var buffer = this.ensureBuffer(bufferLength + rowBytes);
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
- if (prevRow.length == 0)
+ if (prevRow.length === 0)
prevRow = new Uint8Array(rowBytes);
var j = bufferLength;
@@ -31400,10 +31470,10 @@ var JpegStream = (function JpegStreamClosure() {
// Looking for APP14, 'Adobe'
for (var i = 0; i < maxBytesScanned; ++i) {
if (bytes[i] == 0xFF && bytes[i + 1] == 0xEE &&
- bytes[i + 2] == 0x00 && bytes[i + 3] == 0x0E &&
+ bytes[i + 2] === 0x00 && bytes[i + 3] == 0x0E &&
bytes[i + 4] == 0x41 && bytes[i + 5] == 0x64 &&
bytes[i + 6] == 0x6F && bytes[i + 7] == 0x62 &&
- bytes[i + 8] == 0x65 && bytes[i + 9] == 0x00)
+ bytes[i + 8] == 0x65 && bytes[i + 9] === 0x00)
return true;
// scanning until frame tag
if (bytes[i] == 0xFF && bytes[i + 1] == 0xC0)
@@ -31660,7 +31730,7 @@ var DecryptStream = (function DecryptStreamClosure() {
DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
var chunk = this.str.getBytes(chunkSize);
- if (!chunk || chunk.length == 0) {
+ if (!chunk || chunk.length === 0) {
this.eof = true;
return;
}
@@ -32302,7 +32372,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.columns = params.get('Columns') || 1728;
this.rows = params.get('Rows') || 0;
var eoblock = params.get('EndOfBlock');
- if (eoblock == null)
+ if (eoblock === null || eoblock === undefined)
eoblock = true;
this.eoblock = eoblock;
this.black = params.get('BlackIs1') || false;
@@ -32321,7 +32391,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.buf = EOF;
var code1;
- while ((code1 = this.lookBits(12)) == 0) {
+ while ((code1 = this.lookBits(12)) === 0) {
this.eatBits(1);
}
if (code1 == 1) {
@@ -32405,7 +32475,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
var refPos, blackPixels, bits;
- if (this.outputBits == 0) {
+ if (this.outputBits === 0) {
if (this.eof)
return null;
@@ -32579,7 +32649,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.eof = true;
} else {
code1 = this.lookBits(12);
- while (code1 == 0) {
+ while (code1 === 0) {
this.eatBits(1);
code1 = this.lookBits(12);
}
@@ -32647,7 +32717,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (this.outputBits >= 8) {
this.buf = (this.codingPos & 1) ? 0 : 0xFF;
this.outputBits -= 8;
- if (this.outputBits == 0 && codingLine[this.codingPos] < columns) {
+ if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
this.codingPos++;
this.outputBits = (codingLine[this.codingPos] -
codingLine[this.codingPos - 1]);
@@ -32746,7 +32816,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (code == EOF)
return 1;
- if ((code >> 5) == 0)
+ if ((code >> 5) === 0)
p = whiteTable1[code];
else
p = whiteTable2[code >> 3];
@@ -32777,9 +32847,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
code = this.lookBits(13);
if (code == EOF)
return 1;
- if ((code >> 7) == 0)
+ if ((code >> 7) === 0)
p = blackTable1[code];
- else if ((code >> 9) == 0 && (code >> 7) != 0)
+ else if ((code >> 9) === 0 && (code >> 7) !== 0)
p = blackTable2[(code >> 1) - 64];
else
p = blackTable3[code >> 7];
@@ -32809,8 +32879,8 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
var c;
while (this.inputBits < n) {
- if ((c = this.str.getByte()) == null) {
- if (this.inputBits == 0)
+ if ((c = this.str.getByte()) === null || c === undefined) {
+ if (this.inputBits === 0)
return EOF;
return ((this.inputBuf << (n - this.inputBits)) &
(0xFFFF >> (16 - n)));
@@ -32863,7 +32933,7 @@ var LZWStream = (function LZWStreamClosure() {
var cachedData = this.cachedData;
while (bitsCached < n) {
var c = this.str.getByte();
- if (c == null) {
+ if (c === null || c === undefined) {
this.eof = true;
return null;
}
@@ -33082,6 +33152,12 @@ var WorkerMessageHandler = {
exception: e
});
+ return;
+ } else if (e instanceof MissingPDFException) {
+ handler.send('MissingPDF', {
+ exception: e
+ });
+
return;
} else {
handler.send('UnknownError', {
@@ -33137,8 +33213,15 @@ var WorkerMessageHandler = {
});
},
error: function getPDFError(e) {
- handler.send('DocError', 'Unexpected server response of ' +
- e.target.status + '.');
+ if (e.target.status == 404) {
+ handler.send('MissingPDF', {
+ exception: new MissingPDFException(
+ 'Missing PDF \"' + source.url + '\".')});
+ } else {
+ handler.send('DocError', 'Unexpected server response (' +
+ e.target.status + ') while retrieving PDF \"' +
+ source.url + '\".');
+ }
},
headers: source.httpHeaders
},
@@ -33150,11 +33233,13 @@ var WorkerMessageHandler = {
handler.on('GetPageRequest', function wphSetupGetPage(data) {
var pageNumber = data.pageIndex + 1;
var pdfPage = pdfModel.getPage(pageNumber);
+ var encrypt = pdfModel.xref.encrypt;
var page = {
pageIndex: data.pageIndex,
rotate: pdfPage.rotate,
ref: pdfPage.ref,
- view: pdfPage.view
+ view: pdfPage.view,
+ disableTextLayer: encrypt ? encrypt.disableTextLayer : false
};
handler.send('GetPage', {pageInfo: page});
});
@@ -33191,19 +33276,21 @@ var WorkerMessageHandler = {
var minimumStackMessage =
'worker.js: while trying to getPage() and getOperatorList()';
+ var wrappedException;
+
// Turn the error into an obj that can be serialized
if (typeof e === 'string') {
- e = {
+ wrappedException = {
message: e,
stack: minimumStackMessage
};
} else if (typeof e === 'object') {
- e = {
+ wrappedException = {
message: e.message || e.toString(),
stack: e.stack || minimumStackMessage
};
} else {
- e = {
+ wrappedException = {
message: 'Unknown exception type: ' + (typeof e),
stack: minimumStackMessage
};
@@ -33211,7 +33298,7 @@ var WorkerMessageHandler = {
handler.send('PageError', {
pageNum: pageNum,
- error: e
+ error: wrappedException
});
return;
}
@@ -33223,7 +33310,7 @@ var WorkerMessageHandler = {
var fonts = {};
for (var i = 0, ii = dependency.length; i < ii; i++) {
var dep = dependency[i];
- if (dep.indexOf('g_font_') == 0) {
+ if (dep.indexOf('g_font_') === 0) {
fonts[dep] = true;
}
}
@@ -33280,7 +33367,7 @@ var workerConsole = {
timeEnd: function timeEnd(name) {
var time = consoleTimer[name];
- if (time == null) {
+ if (!time) {
error('Unkown timer name ' + name);
}
this.log('Timer:', name, Date.now() - time);
@@ -33333,7 +33420,7 @@ var JpxImage = (function JpxImageClosure() {
xhr.send(null);
},
parse: function JpxImage_parse(data) {
- function ReadUint(data, offset, bytes) {
+ function readUint(data, offset, bytes) {
var n = 0;
for (var i = 0; i < bytes; i++)
n = n * 256 + (data[offset + i] & 0xFF);
@@ -33342,15 +33429,15 @@ var JpxImage = (function JpxImageClosure() {
var position = 0, length = data.length;
while (position < length) {
var headerSize = 8;
- var lbox = ReadUint(data, position, 4);
- var tbox = ReadUint(data, position + 4, 4);
+ var lbox = readUint(data, position, 4);
+ var tbox = readUint(data, position + 4, 4);
position += headerSize;
if (lbox == 1) {
- lbox = ReadUint(data, position, 8);
+ lbox = readUint(data, position, 8);
position += 8;
headerSize += 8;
}
- if (lbox == 0)
+ if (lbox === 0)
lbox = length - position + headerSize;
if (lbox < headerSize)
error('JPX error: Invalid box field size');
@@ -33579,7 +33666,7 @@ var JpxImage = (function JpxImageClosure() {
tile.partsCount = data[position + 9];
context.mainHeader = false;
- if (tile.partIndex == 0) {
+ if (tile.partIndex === 0) {
// reset component specific settings
tile.COD = context.COD;
tile.COC = context.COC.slice(0); // clone of the global COC
@@ -33590,7 +33677,7 @@ var JpxImage = (function JpxImageClosure() {
break;
case 0xFF93: // Start of data (SOD)
var tile = context.currentTile;
- if (tile.partIndex == 0) {
+ if (tile.partIndex === 0) {
initializeTile(context, tile.index);
buildPackets(context);
}
@@ -33921,7 +34008,7 @@ var JpxImage = (function JpxImageClosure() {
resolutions.push(resolution);
var subband;
- if (r == 0) {
+ if (r === 0) {
// one sub-band (LL) with last decomposition
subband = {};
subband.type = 'LL';
@@ -34023,7 +34110,7 @@ var JpxImage = (function JpxImageClosure() {
}
function readCodingpasses() {
var value = readBits(1);
- if (value == 0)
+ if (value === 0)
return 1;
value = (value << 1) | readBits(1);
if (value == 0x02)
@@ -34143,7 +34230,7 @@ var JpxImage = (function JpxImageClosure() {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
var blockHeight = codeblock.tby1_ - codeblock.tby0_;
- if (blockWidth == 0 || blockHeight == 0)
+ if (blockWidth === 0 || blockHeight === 0)
continue;
if (!('data' in codeblock))
continue;
@@ -34195,7 +34282,7 @@ var JpxImage = (function JpxImageClosure() {
var n = (bitModel.coefficentsSign[position] ? -1 : 1) *
bitModel.coefficentsMagnitude[position];
var nb = bitModel.bitsDecoded[position], correction;
- if (transformation == 0 || mb > nb) {
+ if (transformation === 0 || mb > nb) {
// use r only if transformation is irreversible or
// not all bitplanes were decoded for reversible transformation
n += n < 0 ? n - r : n > 0 ? n + r : 0;
@@ -34264,7 +34351,7 @@ var JpxImage = (function JpxImageClosure() {
}
var transformation = codingStyleParameters.transformation;
- var transform = transformation == 0 ? new IrreversibleTransform() :
+ var transform = transformation === 0 ? new IrreversibleTransform() :
new ReversibleTransform();
var result = transform.calculate(subbandCoefficients,
component.tcx0, component.tcy0);
@@ -34594,7 +34681,7 @@ var JpxImage = (function JpxImageClosure() {
return d;
} else {
this.chigh -= qeIcx;
- if ((this.a & 0x8000) == 0) {
+ if ((this.a & 0x8000) === 0) {
var d = this.exchangeMps(cx);
this.renormD();
return d;
@@ -34605,14 +34692,14 @@ var JpxImage = (function JpxImageClosure() {
},
renormD: function ArithmeticDecoder_renormD() {
do {
- if (this.ct == 0)
+ if (this.ct === 0)
this.byteIn();
this.a <<= 1;
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
this.clow = (this.clow << 1) & 0xFFFF;
this.ct--;
- } while ((this.a & 0x8000) == 0);
+ } while ((this.a & 0x8000) === 0);
},
exchangeMps: function ArithmeticDecoder_exchangeMps(cx) {
var d;
@@ -34848,12 +34935,12 @@ var JpxImage = (function JpxImageClosure() {
// significant but not those that have just become
if (!coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) != 0)
+ (processingFlags[index] & processedMask) !== 0)
continue;
var contextLabel = 16;
if ((processingFlags[index] &
- firstMagnitudeBitMask) != 0) {
+ firstMagnitudeBitMask) !== 0) {
processingFlags[i * width + j] ^= firstMagnitudeBitMask;
// first refinement
var significance = neighborsSignificance[index];
@@ -34894,14 +34981,14 @@ var JpxImage = (function JpxImageClosure() {
// using the property: labels[neighborsSignificance[index]] == 0
// when neighborsSignificance[index] == 0
var allEmpty = i0 + 3 < height &&
- processingFlags[index0] == 0 &&
- processingFlags[index0 + oneRowDown] == 0 &&
- processingFlags[index0 + twoRowsDown] == 0 &&
- processingFlags[index0 + threeRowsDown] == 0 &&
- neighborsSignificance[index0] == 0 &&
- neighborsSignificance[index0 + oneRowDown] == 0 &&
- neighborsSignificance[index0 + twoRowsDown] == 0 &&
- neighborsSignificance[index0 + threeRowsDown] == 0;
+ processingFlags[index0] === 0 &&
+ processingFlags[index0 + oneRowDown] === 0 &&
+ processingFlags[index0 + twoRowsDown] === 0 &&
+ processingFlags[index0 + threeRowsDown] === 0 &&
+ neighborsSignificance[index0] === 0 &&
+ neighborsSignificance[index0 + oneRowDown] === 0 &&
+ neighborsSignificance[index0 + twoRowsDown] === 0 &&
+ neighborsSignificance[index0 + threeRowsDown] === 0;
var i1 = 0, index = index0;
var cx, i;
if (allEmpty) {
@@ -34937,7 +35024,7 @@ var JpxImage = (function JpxImageClosure() {
break;
if (coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) != 0)
+ (processingFlags[index] & processedMask) !== 0)
continue;
var contextLabel = labels[neighborsSignificance[index]];
@@ -35023,7 +35110,7 @@ var JpxImage = (function JpxImageClosure() {
for (var v = 0; v < height; v++) {
if (width == 1) {
// if width = 1, when u0 even keep items as is, when odd divide by 2
- if ((u0 % 1) != 0) {
+ if ((u0 % 1) !== 0) {
items[v * width] /= 2;
}
continue;
@@ -35058,7 +35145,7 @@ var JpxImage = (function JpxImageClosure() {
for (var u = 0; u < width; u++) {
if (height == 1) {
// if height = 1, when v0 even keep items as is, when odd divide by 2
- if ((v0 % 1) != 0) {
+ if ((v0 % 1) !== 0) {
items[u] /= 2;
}
continue;
@@ -35285,7 +35372,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
return d;
} else {
this.chigh -= qeIcx;
- if ((this.a & 0x8000) == 0) {
+ if ((this.a & 0x8000) === 0) {
var d = this.exchangeMps(cx);
this.renormD();
return d;
@@ -35296,14 +35383,14 @@ var Jbig2Image = (function Jbig2ImageClosure() {
},
renormD: function ArithmeticDecoder_renormD() {
do {
- if (this.ct == 0)
+ if (this.ct === 0)
this.byteIn();
this.a <<= 1;
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
this.clow = (this.clow << 1) & 0xFFFF;
this.ct--;
- } while ((this.a & 0x8000) == 0);
+ } while ((this.a & 0x8000) === 0);
},
exchangeMps: function ArithmeticDecoder_exchangeMps(cx) {
var d;
@@ -35423,7 +35510,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
break;
default:
v = v * 2 + bit;
- if (--toRead == 0)
+ if (--toRead === 0)
state = 0;
continue;
}
@@ -35599,7 +35686,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
offsetX, offsetY, prediction, at,
decodingContext) {
var codingTemplate = RefinementTemplates[templateIndex].coding;
- if (templateIndex == 0)
+ if (templateIndex === 0)
codingTemplate = codingTemplate.concat([at[0]]);
var codingTemplateLength = codingTemplate.length;
var codingTemplateX = new Int32Array(codingTemplateLength);
@@ -35609,7 +35696,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
codingTemplateY[k] = codingTemplate[k].y;
}
var referenceTemplate = RefinementTemplates[templateIndex].reference;
- if (templateIndex == 0)
+ if (templateIndex === 0)
referenceTemplate = referenceTemplate.concat([at[1]]);
var referenceTemplateLength = referenceTemplate.length;
var referenceTemplateX = new Int32Array(referenceTemplateLength);
@@ -35692,7 +35779,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var totalWidth = 0;
while (true) {
var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
- if (deltaWidth == null)
+ if (deltaWidth === null)
break; // OOB
currentWidth += deltaWidth;
totalWidth += currentWidth;
@@ -35819,7 +35906,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
i++;
var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
- if (deltaS == null)
+ if (deltaS === null)
break; // OOB
currentS += deltaS + dsOffset;
} while (true);
@@ -35941,7 +36028,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
position += 2;
if (!dictionary.huffman) {
- var atLength = dictionary.template == 0 ? 4 : 1;
+ var atLength = dictionary.template === 0 ? 4 : 1;
var at = [];
for (var i = 0; i < atLength; i++) {
at.push({
@@ -36027,7 +36114,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
if (!genericRegion.mmr) {
- var atLength = genericRegion.template == 0 ? 4 : 1;
+ var atLength = genericRegion.template === 0 ? 4 : 1;
var at = [];
for (var i = 0; i < atLength; i++) {
at.push({
@@ -36290,11 +36377,11 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
];
function isOdd(i) {
- return (i & 1) != 0;
+ return (i & 1) !== 0;
}
function isEven(i) {
- return (i & 1) == 0;
+ return (i & 1) === 0;
}
function findUnequal(arr, start, value) {
@@ -36368,8 +36455,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
function bidi(str, startLevel) {
var isLTR = true;
var strLength = str.length;
- if (strLength == 0)
- return new BidiResult(str, ltr);
+ if (strLength === 0)
+ return new BidiResult(str, isLTR);
// get types, fill arrays
@@ -36402,7 +36489,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// if there are no rtl characters then no bidi needed
// if less than 30% chars are rtl then string is primarily ltr
// if more than 30% chars are rtl then string is primarily rtl
- if (numBidi == 0) {
+ if (numBidi === 0) {
isLTR = true;
return new BidiResult(str, isLTR);
}
diff --git a/browser/extensions/pdfjs/content/web/l10n.js b/browser/extensions/pdfjs/content/web/l10n.js
index df20ff57718e..1258f0777311 100644
--- a/browser/extensions/pdfjs/content/web/l10n.js
+++ b/browser/extensions/pdfjs/content/web/l10n.js
@@ -94,20 +94,15 @@
// get a localized string
get: translateString,
- // get|set the document language and direction
- get language() {
- return {
- // get|set the document language (ISO-639-1)
- get code() { return gLanguage; },
+ // get the document language
+ getLanguage: function() { return gLanguage; },
- // get the direction (ltr|rtl) of the current language
- get direction() {
- // http://www.w3.org/International/questions/qa-scripts
- // Arabic, Hebrew, Farsi, Pashto, Urdu
- var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
- return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
- }
- };
+ // get the direction (ltr|rtl) of the current language
+ getDirection: function() {
+ // http://www.w3.org/International/questions/qa-scripts
+ // Arabic, Hebrew, Farsi, Pashto, Urdu
+ var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
+ return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
}
};
})(this);
diff --git a/browser/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css
index c735810625c5..0a034e2a7f65 100644
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -665,7 +665,6 @@ html[dir='rtl'] .dropdownToolbarButton {
}
.dropdownToolbarButton {
- min-width: 120px;
max-width: 120px;
padding: 3px 2px 2px;
overflow: hidden;
diff --git a/browser/extensions/pdfjs/content/web/viewer.html b/browser/extensions/pdfjs/content/web/viewer.html
index 08b59e19cb39..ab5dfbb40b3b 100644
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+
@@ -81,8 +81,8 @@ limitations under the License.