diff --git a/.eslintignore b/.eslintignore
index 9c53635d1dcc..51bba90ec978 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -193,6 +193,7 @@ toolkit/modules/tests/xpcshell/test_task.js
toolkit/components/osfile/**
# External code:
+toolkit/components/microformats/test/**
toolkit/components/reader/Readability.js
toolkit/components/reader/JSDOMParser.js
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index bacacf638d3c..6498722fafaf 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -304,7 +304,7 @@ pref("browser.urlbar.matchBehavior", 1);
pref("browser.urlbar.filter.javascript", true);
// the maximum number of results to show in autocomplete when doing richResults
-pref("browser.urlbar.maxRichResults", 12);
+pref("browser.urlbar.maxRichResults", 10);
// The amount of time (ms) to wait after the user has stopped typing
// before starting to perform autocomplete. 50 is the default set in
// autocomplete.xml.
diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js
index b0ee29f1f704..1a8c260d5948 100644
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -660,6 +660,7 @@ var LightweightThemeListener = {
if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css")
return sheet;
}
+ return undefined;
});
Services.obs.addObserver(this, "lightweight-theme-styling-update", false);
diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js
index e82161a96a26..4e3d056e9c6a 100644
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -11,7 +11,6 @@ var gPluginHandler = {
"PluginContent:RemoveNotification",
"PluginContent:UpdateHiddenPluginUI",
"PluginContent:HideNotificationBar",
- "PluginContent:ShowInstallNotification",
"PluginContent:InstallSinglePlugin",
"PluginContent:ShowPluginCrashedNotification",
"PluginContent:SubmitReport",
@@ -56,8 +55,6 @@ var gPluginHandler = {
case "PluginContent:HideNotificationBar":
this.hideNotificationBar(msg.target, msg.data.name);
break;
- case "PluginContent:ShowInstallNotification":
- return this.showInstallNotification(msg.target, msg.data.pluginInfo);
case "PluginContent:InstallSinglePlugin":
this.installSinglePlugin(msg.data.pluginInfo);
break;
diff --git a/browser/base/content/browser-syncui.js b/browser/base/content/browser-syncui.js
index dc513a6cbe8f..ea4c51538e01 100644
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -251,7 +251,7 @@ var gSyncUI = {
if (needsSetup || this._loginFailed()) {
this.openSetup();
} else {
- return this.doSync();
+ this.doSync();
}
}).catch(err => {
this.log.error("Failed to handle toolbar button command", err);
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 20d515ab9c9a..8e8c67129987 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3387,7 +3387,7 @@ const DOMLinkHandler = {
addSearch: function(aBrowser, aEngine, aURL) {
let tab = gBrowser.getTabForBrowser(aBrowser);
if (!tab)
- return false;
+ return;
BrowserSearch.addEngine(aBrowser, aEngine, makeURI(aURL));
},
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 3f9ab642ea92..647f0fc93c64 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -698,7 +698,7 @@
showcommentcolumn="true"
showimagecolumn="true"
enablehistory="true"
- maxrows="6"
+ maxrows="10"
newlines="stripsurroundingwhitespace"
ontextentered="this.handleCommand(param);"
ontextreverted="return this.handleRevert();"
diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js
index 07b8f922b436..096d3c66251e 100644
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -268,6 +268,7 @@ function getClipboardHelper() {
return Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
} catch(e) {
// do nothing, later code will handle the error
+ return null;
}
}
const gClipboardHelper = getClipboardHelper();
diff --git a/browser/base/content/sanitize.js b/browser/base/content/sanitize.js
index e330cfd73270..0eaa57e9f66f 100644
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -603,6 +603,7 @@ Sanitizer.prototype = {
aWindow.skipNextCanClose = true;
return true;
}
+ return false;
},
_resetAllWindowClosures: function(aWindowList) {
for (let win of aWindowList) {
@@ -665,6 +666,7 @@ Sanitizer.prototype = {
e.stopPropagation();
return false;
}
+ return undefined;
}
newWindow.addEventListener("fullscreen", onFullScreen);
}
diff --git a/browser/base/content/sync/genericChange.js b/browser/base/content/sync/genericChange.js
index 08cd086e4d44..f7afdef1aa1a 100644
--- a/browser/base/content/sync/genericChange.js
+++ b/browser/base/content/sync/genericChange.js
@@ -147,6 +147,7 @@ var Change = {
return this.doChangePassword();
break;
}
+ return undefined;
},
doGeneratePassphrase: function () {
diff --git a/browser/base/content/sync/setup.js b/browser/base/content/sync/setup.js
index 568a50fcf48b..d5e460f40e26 100644
--- a/browser/base/content/sync/setup.js
+++ b/browser/base/content/sync/setup.js
@@ -123,14 +123,14 @@ var gSyncSetup = {
startNewAccountSetup: function () {
if (!Weave.Utils.ensureMPUnlocked())
- return false;
+ return;
this._settingUpNew = true;
this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE;
},
useExistingAccount: function () {
if (!Weave.Utils.ensureMPUnlocked())
- return false;
+ return;
this._settingUpNew = false;
if (this.wizardType == "pair") {
// We're already pairing, so there's no point in pairing again.
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index b02f25ed835b..6197233ba182 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1824,6 +1824,99 @@
+
+
+
+
+
+ into the DOM if necessary.
+ if (!notificationbox.parentNode) {
+ // NB: this appendChild call causes us to run constructors for the
+ // browser element, which fires off a bunch of notifications. Some
+ // of those notifications can cause code to run that inspects our
+ // state, so it is important that the tab element is fully
+ // initialized by this point.
+ this.mPanelContainer.appendChild(notificationbox);
+ }
+
+ // wire up a progress listener for the new browser object.
+ let tabListener = this.mTabProgressListener(aTab, browser, uriIsAboutBlank, usingPreloadedContent);
+ const filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
+ .createInstance(Ci.nsIWebProgress);
+ filter.addProgressListener(tabListener, Ci.nsIWebProgress.NOTIFY_ALL);
+ browser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
+ this._tabListeners.set(aTab, tabListener);
+ this._tabFilters.set(aTab, filter);
+
+ browser.droppedLinkHandler = handleDroppedLink;
+
+ // We start our browsers out as inactive, and then maintain
+ // activeness in the tab switcher.
+ browser.docShellIsActive = false;
+
+ // When addTab() is called with an URL that is not "about:blank" we
+ // set the "nodefaultsrc" attribute that prevents a frameLoader
+ // from being created as soon as the linked is inserted
+ // into the DOM. We thus have to register the new outerWindowID
+ // for non-remote browsers after we have called browser.loadURI().
+ if (!remote) {
+ this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser);
+ }
+
+ return { usingPreloadedContent: usingPreloadedContent };
+ ]]>
+
+
+
@@ -1833,6 +1926,8 @@
into the DOM if necessary.
- if (!notificationbox.parentNode) {
- // NB: this appendChild call causes us to run constructors for the
- // browser element, which fires off a bunch of notifications. Some
- // of those notifications can cause code to run that inspects our
- // state, so it is important that the tab element is fully
- // initialized by this point.
- this.mPanelContainer.appendChild(notificationbox);
- }
-
this.tabContainer.updateVisibility();
- // wire up a progress listener for the new browser object.
- var tabListener = this.mTabProgressListener(t, b, uriIsAboutBlank, usingPreloadedContent);
- const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
- .createInstance(Components.interfaces.nsIWebProgress);
- filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
- b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
- this._tabListeners.set(t, tabListener);
- this._tabFilters.set(t, filter);
+ let options = {
+ referrerURI : aReferrerURI,
+ referrerPolicy : aReferrerPolicy,
+ charset : aCharset,
+ postData : aPostData,
+ allowThirdPartyFixup : aAllowThirdPartyFixup,
+ fromExternal : aFromExternal,
+ allowMixedContent : aAllowMixedContent,
+ forceNotRemote : aForceNotRemote,
+ noReferrer : aNoReferrer,
+ userContextId : aUserContextId
+ };
- b.droppedLinkHandler = handleDroppedLink;
+ // Currently in this incarnation of bug 906076, we are forcing the
+ // browser to immediately be linked. In future incarnations of this
+ // bug this will be removed so we can leave the tab in its "lazy"
+ // state to be exploited for startup optimization. Note that for
+ // now this must occur before "TabOpen" event is fired, as that will
+ // trigger SessionStore.jsm to run code that expects the existence
+ // of tab.linkedBrowser.
+ let { usingPreloadedContent } = this._linkBrowserToTab(t, aURI, options);
+ let b = t.linkedBrowser;
// Dispatch a new tab notification. We do this once we're
// entirely done, so that things are in a consistent state
@@ -2005,23 +2070,6 @@
}
}
- // We start our browsers out as inactive, and then maintain
- // activeness in the tab switcher.
- b.docShellIsActive = false;
-
- // When addTab() is called with an URL that is not "about:blank" we
- // set the "nodefaultsrc" attribute that prevents a frameLoader
- // from being created as soon as the linked is inserted
- // into the DOM. We thus have to register the new outerWindowID
- // for non-remote browsers after we have called browser.loadURI().
- //
- // Note: Only do this of we still have a docShell. The TabOpen
- // event was dispatched above and a gBrowser.removeTab() call from
- // one of its listeners could cause us to fail here.
- if (!remote && b.docShell) {
- this._outerWindowIDBrowserMap.set(b.outerWindowID, b);
- }
-
// Check if we're opening a tab related to the current tab and
// move it to after the current tab.
// aReferrerURI is null or undefined if the tab is opened from
@@ -4266,6 +4314,7 @@
}
}
+ return undefined;
]]>
diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini
index f613a9d12efc..926132d22c6f 100644
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -321,7 +321,7 @@ skip-if = !datareporting
[browser_devices_get_user_media.js]
skip-if = buildapp == 'mulet' || (os == "linux" && debug) # linux: bug 976544
[browser_devices_get_user_media_about_urls.js]
-skip-if = e10s # Bug 1071623
+skip-if = e10s && debug
[browser_devices_get_user_media_in_frame.js]
[browser_discovery.js]
[browser_double_close_tab.js]
diff --git a/browser/base/content/test/general/browser_autocomplete_autoselect.js b/browser/base/content/test/general/browser_autocomplete_autoselect.js
index dac78675a657..3cacf6475521 100644
--- a/browser/base/content/test/general/browser_autocomplete_autoselect.js
+++ b/browser/base/content/test/general/browser_autocomplete_autoselect.js
@@ -16,12 +16,14 @@ add_task(function*() {
Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
});
+ let maxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
registerCleanupFunction(function* () {
yield PlacesTestUtils.clearHistory();
});
let visits = [];
- repeat(10, i => {
+ repeat(maxResults, i => {
visits.push({
uri: makeURI("http://example.com/autocomplete/?" + i),
});
@@ -34,20 +36,20 @@ add_task(function*() {
let popup = gURLBar.popup;
let results = popup.richlistbox.children;
- // 1 extra for the current search engine match
- is(results.length, 11, "Should get 11 results");
+ is(results.length, maxResults,
+ "Should get maxResults=" + maxResults + " results");
is_selected(0);
info("Key Down to select the next item");
EventUtils.synthesizeKey("VK_DOWN", {});
is_selected(1);
- info("Key Down 11 times should wrap around all the way around");
- repeat(11, () => EventUtils.synthesizeKey("VK_DOWN", {}));
+ info("Key Down maxResults times should wrap around all the way around");
+ repeat(maxResults, () => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected(1);
- info("Key Up 11 times should wrap around the other way");
- repeat(11, () => EventUtils.synthesizeKey("VK_UP", {}));
+ info("Key Up maxResults times should wrap around the other way");
+ repeat(maxResults, () => EventUtils.synthesizeKey("VK_UP", {}));
is_selected(1);
info("Page Up will go up the list, but not wrap");
@@ -56,7 +58,7 @@ add_task(function*() {
info("Page Up again will wrap around to the end of the list");
EventUtils.synthesizeKey("VK_PAGE_UP", {})
- is_selected(10);
+ is_selected(maxResults - 1);
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield promisePopupHidden(gURLBar.popup);
diff --git a/browser/base/content/test/general/browser_contextmenu.js b/browser/base/content/test/general/browser_contextmenu.js
index b888b224f654..308a2d992ed6 100644
--- a/browser/base/content/test/general/browser_contextmenu.js
+++ b/browser/base/content/test/general/browser_contextmenu.js
@@ -11,6 +11,8 @@ let LOGIN_FILL_ITEMS = [
], null,
];
+let hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled");
+
add_task(function* test_setup() {
const example_base = "http://example.com/browser/browser/base/content/test/general/";
const url = example_base + "subtst_contextmenu.html";
@@ -38,6 +40,7 @@ add_task(function* test_plaintext() {
"context-bookmarkpage", true], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -56,6 +59,7 @@ add_task(function* test_link() {
"---", null,
"context-bookmarklink", true,
"context-savelink", true,
+ ...(hasPocket ? ["context-savelinktopocket", true] : []),
"context-copylink", true,
"context-searchselect", true
]
@@ -196,6 +200,7 @@ add_task(function* test_iframe() {
"context-bookmarkpage", true], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -460,6 +465,7 @@ add_task(function* test_pagemenu() {
"+Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -490,6 +496,7 @@ add_task(function* test_dom_full_screen() {
"context-leave-dom-fullscreen", true,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -535,6 +542,7 @@ add_task(function* test_pagemenu2() {
"context-bookmarkpage", true], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -603,6 +611,7 @@ add_task(function* test_imagelink() {
"---", null,
"context-bookmarklink", true,
"context-savelink", true,
+ ...(hasPocket ? ["context-savelinktopocket", true] : []),
"context-copylink", true,
"---", null,
"context-viewimage", true,
@@ -701,6 +710,7 @@ add_task(function* test_click_to_play_blocked_plugin() {
"context-ctp-hide", true,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@@ -744,6 +754,7 @@ add_task(function* test_srcdoc() {
"context-bookmarkpage", true], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
diff --git a/browser/base/content/test/general/browser_contextmenu_input.js b/browser/base/content/test/general/browser_contextmenu_input.js
index 390723e54f49..330e4aece645 100644
--- a/browser/base/content/test/general/browser_contextmenu_input.js
+++ b/browser/base/content/test/general/browser_contextmenu_input.js
@@ -1,6 +1,8 @@
"use strict";
let contextMenu;
+let hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled");
+
add_task(function* test_setup() {
const example_base = "http://example.com/browser/browser/base/content/test/general/";
const url = example_base + "subtst_contextmenu_input.html";
@@ -187,6 +189,7 @@ add_task(function* test_date_time_color_range_input() {
"context-bookmarkpage", true], null,
"---", null,
"context-savepage", true,
+ ...(hasPocket ? ["context-pocket", true] : []),
"---", null,
"context-viewbgimage", false,
"context-selectall", null,
diff --git a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
index 19de9df24b08..f758de27c6c2 100644
--- a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
@@ -58,37 +58,8 @@ function loadPage(aUrl) {
return deferred.promise;
}
-// A fake about module to map get_user_media.html to different about urls.
-function fakeLoopAboutModule() {
-}
-
-fakeLoopAboutModule.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
- newChannel: function (aURI, aLoadInfo) {
- let rootDir = getRootDirectory(gTestPath);
- let uri = Services.io.newURI(rootDir + "get_user_media.html", null, null);
- let chan = Services.io.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
-
- chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
- return chan;
- },
- getURIFlags: function (aURI) {
- return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
- Ci.nsIAboutModule.ALLOW_SCRIPT |
- Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD |
- Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
- }
-};
-
-var factory = XPCOMUtils._getFactory(fakeLoopAboutModule);
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-
-var classIDLoopconversation, classIDEvil;
-
registerCleanupFunction(function() {
gBrowser.removeCurrentTab();
- registrar.unregisterFactory(classIDLoopconversation, factory);
- registrar.unregisterFactory(classIDEvil, factory);
});
const permissionError = "error: SecurityError: The operation is insecure.";
@@ -181,19 +152,46 @@ function test() {
gTab.linkedBrowser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
- classIDLoopconversation = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator).generateUUID();
- registrar.registerFactory(classIDLoopconversation, "",
- "@mozilla.org/network/protocol/about;1?what=loopconversation",
- factory);
-
- classIDEvil = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator).generateUUID();
- registrar.registerFactory(classIDEvil, "",
- "@mozilla.org/network/protocol/about;1?what=evil",
- factory);
-
Task.spawn(function () {
+ yield ContentTask.spawn(gBrowser.selectedBrowser,
+ getRootDirectory(gTestPath) + "get_user_media.html",
+ function* (url) {
+ const Ci = Components.interfaces;
+ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+ Components.utils.import("resource://gre/modules/Services.jsm");
+
+ /* A fake about module to map get_user_media.html to different about urls. */
+ function fakeLoopAboutModule() {
+ }
+
+ fakeLoopAboutModule.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+ newChannel: function (aURI, aLoadInfo) {
+ let uri = Services.io.newURI(url, null, null);
+ let chan = Services.io.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
+ chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
+ return chan;
+ },
+ getURIFlags: function (aURI) {
+ return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
+ }
+ };
+
+ var factory = XPCOMUtils._getFactory(fakeLoopAboutModule);
+ var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ let UUIDGenerator = Components.classes["@mozilla.org/uuid-generator;1"]
+ .getService(Ci.nsIUUIDGenerator);
+ registrar.registerFactory(UUIDGenerator.generateUUID(), "",
+ "@mozilla.org/network/protocol/about;1?what=loopconversation",
+ factory);
+ registrar.registerFactory(UUIDGenerator.generateUUID(), "",
+ "@mozilla.org/network/protocol/about;1?what=evil",
+ factory);
+ });
+
yield new Promise(resolve => SpecialPowers.pushPrefEnv({
"set": [[PREF_PERMISSION_FAKE, true],
["media.getusermedia.screensharing.enabled", true]],
@@ -206,6 +204,19 @@ function test() {
// Cleanup before the next test
expectNoObserverCalled();
}
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null,
+ function* () {
+ const Ci = Components.interfaces;
+ const Cc = Components.classes;
+ var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ let cid = Cc["@mozilla.org/network/protocol/about;1?what=loopconversation"];
+ registrar.unregisterFactory(cid,
+ registrar.getClassObject(cid, Ci.nsIFactory));
+ cid = Cc["@mozilla.org/network/protocol/about;1?what=evil"];
+ registrar.unregisterFactory(cid,
+ registrar.getClassObject(cid, Ci.nsIFactory));
+ });
}).then(finish, ex => {
ok(false, "Unexpected Exception: " + ex);
finish();
diff --git a/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
index 79c8137ff27f..7a82b2e3136d 100644
--- a/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
+++ b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
@@ -15,6 +15,8 @@ function is_selected(index) {
is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
}
+let gMaxResults;
+
add_task(function*() {
registerCleanupFunction(function* () {
yield PlacesTestUtils.clearHistory();
@@ -23,8 +25,10 @@ add_task(function*() {
yield PlacesTestUtils.clearHistory();
let tabCount = gBrowser.tabs.length;
+ gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
let visits = [];
- repeat(10, i => {
+ repeat(gMaxResults, i => {
visits.push({
uri: makeURI("http://example.com/autocomplete/?" + i),
});
@@ -44,7 +48,8 @@ function* do_test() {
let popup = gURLBar.popup;
let results = popup.richlistbox.children;
- is(results.length, 11, "Should get 11 results");
+ is(results.length, gMaxResults,
+ "Should get gMaxResults=" + gMaxResults + " results");
let initiallySelected = gURLBar.popup.richlistbox.selectedIndex;
diff --git a/browser/base/content/test/general/contextmenu_common.js b/browser/base/content/test/general/contextmenu_common.js
index 97610340ae56..768a52fa58a8 100644
--- a/browser/base/content/test/general/contextmenu_common.js
+++ b/browser/base/content/test/general/contextmenu_common.js
@@ -62,6 +62,7 @@ function getVisibleMenuItems(aMenu, aData) {
} else if (item.id.indexOf("spell-check-dictionary-") != 0 &&
item.id != "spell-no-suggestions" &&
item.id != "spell-add-dictionaries-main" &&
+ item.id != "context-savelinktopocket" &&
item.id != "fill-login-saved-passwords" &&
item.id != "fill-login-no-logins") {
ok(key, "menuitem " + item.id + " has an access key");
diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml
index 5b3a90b9a874..ca01e9747cf7 100644
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1360,9 +1360,16 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
var popupDirection = aElement.ownerDocument.defaultView.getComputedStyle(aElement).direction;
this.style.direction = popupDirection;
- // Move left margin to the window border.
+ // Make the popup's starting margin negaxtive so that the start of the
+ // popup aligns with the window border.
let elementRect = aElement.getBoundingClientRect();
- this.style.marginLeft = "-" + (elementRect.left - rect.left) + "px";
+ if (popupDirection == "rtl") {
+ let offset = elementRect.right - rect.right
+ this.style.marginRight = offset + "px";
+ } else {
+ let offset = rect.left - elementRect.left;
+ this.style.marginLeft = offset + "px";
+ }
// Position the popup below the navbar. To get the y-coordinate,
// which is an offset from the bottom of the input, subtract the
diff --git a/browser/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm
index dd37e5d0031f..a387d9ea0855 100644
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -2134,7 +2134,8 @@ var CustomizableUIInternal = {
dispatchToolboxEvent: function(aEventType, aDetails={}, aWindow=null) {
if (aWindow) {
- return this._dispatchToolboxEventToWindow(aEventType, aDetails, aWindow);
+ this._dispatchToolboxEventToWindow(aEventType, aDetails, aWindow);
+ return;
}
for (let [win, ] of gBuildWindows) {
this._dispatchToolboxEventToWindow(aEventType, aDetails, win);
@@ -2418,6 +2419,7 @@ var CustomizableUIInternal = {
aArgs);
} catch (e) {
Cu.reportError(e);
+ return undefined;
}
};
},
@@ -3912,7 +3914,7 @@ function XULWidgetGroupWrapper(aWidgetId) {
});
this.__defineGetter__("instances", function() {
- return Array.from(gBuildWindows, ([win,]) => this.forWindow(win));
+ return Array.from(gBuildWindows, (wins) => this.forWindow(wins[0]));
});
Object.freeze(this);
diff --git a/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js b/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
index 48bfad82bdba..44e94f63d11b 100644
--- a/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
+++ b/browser/components/customizableui/test/browser_984455_bookmarks_items_reparenting.js
@@ -128,6 +128,7 @@ function checkBookmarksItemsChevronContextMenu() {
if (child.style.visibility != "hidden")
return true;
}
+ return false;
});
yield checkPlacesContextMenu(chevronPopup);
info("Waiting for bookmark toolbar item chevron popup to close");
diff --git a/browser/components/extensions/ext-commands.js b/browser/components/extensions/ext-commands.js
index 8a6228375332..c6276c9882c4 100644
--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -195,11 +195,11 @@ CommandList.prototype = {
*/
getModifiersAttribute(chromeModifiers) {
let modifiersMap = {
- "Alt" : "alt",
- "Command" : "accel",
- "Ctrl" : "accel",
- "MacCtrl" : "control",
- "Shift" : "shift",
+ "Alt": "alt",
+ "Command": "accel",
+ "Ctrl": "accel",
+ "MacCtrl": "control",
+ "Shift": "shift",
};
return Array.from(chromeModifiers, modifier => {
return modifiersMap[modifier];
diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini
index 9872870612e7..40c92761e4f8 100644
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -58,6 +58,7 @@ support-files =
[browser_ext_windows_create.js]
tags = fullscreen
[browser_ext_windows_create_tabId.js]
+[browser_ext_windows_events.js]
[browser_ext_windows.js]
[browser_ext_windows_size.js]
skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode
diff --git a/browser/components/extensions/test/browser/browser_ext_currentWindow.js b/browser/components/extensions/test/browser/browser_ext_currentWindow.js
index f8026235c903..8ef9df1c45a4 100644
--- a/browser/components/extensions/test/browser/browser_ext_currentWindow.js
+++ b/browser/components/extensions/test/browser/browser_ext_currentWindow.js
@@ -122,11 +122,11 @@ add_task(function* () {
// Set focus to some other window.
yield focusWindow(window);
- yield triggerPopup(win1, function*() {
+ yield triggerPopup(win1, function* () {
yield checkWindow("popup", winId1, "win1");
});
- yield triggerPopup(win2, function*() {
+ yield triggerPopup(win2, function* () {
yield checkWindow("popup", winId2, "win2");
});
diff --git a/browser/components/extensions/test/browser/browser_ext_getViews.js b/browser/components/extensions/test/browser/browser_ext_getViews.js
index 0143d3694cbd..f071a4558ebc 100644
--- a/browser/components/extensions/test/browser/browser_ext_getViews.js
+++ b/browser/components/extensions/test/browser/browser_ext_getViews.js
@@ -140,12 +140,12 @@ add_task(function* () {
// short timeout seems to consistently fix it.
yield new Promise(resolve => win1.setTimeout(resolve, 10));
- yield triggerPopup(win1, function*() {
+ yield triggerPopup(win1, function* () {
yield checkViews("background", 2, 1);
yield checkViews("popup", 2, 1);
});
- yield triggerPopup(win2, function*() {
+ yield triggerPopup(win2, function* () {
yield checkViews("background", 2, 1);
yield checkViews("popup", 2, 1);
});
@@ -165,7 +165,7 @@ add_task(function* () {
info("opening win1 popup");
- yield triggerPopup(win1, function*() {
+ yield triggerPopup(win1, function* () {
yield checkViews("background", 1, 1);
yield checkViews("tab", 1, 1);
yield checkViews("popup", 1, 1);
@@ -173,7 +173,7 @@ add_task(function* () {
info("opening win2 popup");
- yield triggerPopup(win2, function*() {
+ yield triggerPopup(win2, function* () {
yield checkViews("background", 1, 1);
yield checkViews("tab", 1, 1);
yield checkViews("popup", 1, 1);
diff --git a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
index 459ca108de9f..5c8c865a88e4 100644
--- a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
@@ -226,3 +226,34 @@ add_task(function* test_tab_options() {
yield BrowserTestUtils.removeTab(tab);
});
+
+add_task(function* test_options_no_manifest() {
+ let extension = yield loadExtension({
+ manifest: {},
+
+ background: function() {
+ browser.test.log("Try to open options page when not specified in the manifest.");
+
+ browser.runtime.openOptionsPage().then(
+ () => {
+ browser.test.fail("Opening options page without one specified in the manifest generated an error");
+ browser.test.notifyFail("options-no-manifest");
+ },
+ error => {
+ let expected = "No `options_ui` declared";
+ browser.test.assertTrue(
+ error.message.includes(expected),
+ `Got expected error (got: '${error.message}', expected: '${expected}'`);
+ }
+ ).then(() => {
+ browser.test.notifyPass("options-no-manifest");
+ }).catch(error => {
+ browser.test.log(`Error: ${error} :: ${error.stack}`);
+ browser.test.notifyFail("options-no-manifest");
+ });
+ },
+ });
+
+ yield extension.awaitFinish("options-no-manifest");
+ yield extension.unload();
+});
diff --git a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
index 630420202d0d..3bd586a17f02 100644
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -13,6 +13,17 @@ add_task(function* testWindowCreate() {
});
};
+ let promiseTabUpdated = (expected) => {
+ return new Promise(resolve => {
+ browser.tabs.onUpdated.addListener(function listener(tabId, changeInfo, tab) {
+ if (changeInfo.url === expected) {
+ browser.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ });
+ });
+ };
+
let windowId;
browser.windows.getCurrent().then(window => {
windowId = window.id;
@@ -85,6 +96,35 @@ add_task(function* testWindowCreate() {
browser.test.assertTrue(/`incognito` property must match the incognito state of tab/.test(error.message),
"Create call failed as expected");
});
+ }).then(() => {
+ browser.test.log("Try to create a window with an invalid tabId");
+
+ return browser.windows.create({tabId: 0}).then(
+ window => {
+ browser.test.fail("Create call should have failed");
+ },
+ error => {
+ browser.test.assertTrue(/Invalid tab ID: 0/.test(error.message),
+ "Create call failed as expected");
+ }
+ );
+ }).then(() => {
+ browser.test.log("Try to create a window with two URLs");
+
+ return browser.windows.create({url: ["http://example.com/", "http://example.org/"]});
+ }).then(window => {
+ return Promise.all([
+ promiseTabUpdated("http://example.com/"),
+ promiseTabUpdated("http://example.org/"),
+ Promise.resolve(window),
+ ]);
+ }).then(([, , window]) => {
+ return browser.windows.get(window.id, {populate: true});
+ }).then(window => {
+ browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
+ browser.test.assertEq("http://example.com/", window.tabs[0].url, "Correct URL was loaded in tab 1");
+ browser.test.assertEq("http://example.org/", window.tabs[1].url, "Correct URL was loaded in tab 2");
+ return browser.windows.remove(window.id);
}).then(() => {
browser.test.notifyPass("window-create");
}).catch(e => {
diff --git a/browser/components/extensions/test/browser/browser_ext_windows_events.js b/browser/components/extensions/test/browser/browser_ext_windows_events.js
new file mode 100644
index 000000000000..5a19b207c2d5
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_windows_events.js
@@ -0,0 +1,39 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* testWindowsEvents() {
+ function background() {
+ browser.windows.onCreated.addListener(function listener(window) {
+ browser.windows.onCreated.removeListener(listener);
+ browser.test.assertTrue(Number.isInteger(window.id),
+ "Window object's id is an integer");
+ browser.test.assertEq("normal", window.type,
+ "Window object returned with the correct type");
+ browser.test.sendMessage("window-created", window.id);
+ });
+
+ browser.windows.onRemoved.addListener(function listener(windowId) {
+ browser.windows.onRemoved.removeListener(listener);
+ browser.test.assertTrue(Number.isInteger(windowId),
+ "windowId is an integer");
+ browser.test.sendMessage(`window-removed-${windowId}`);
+ browser.test.notifyPass("windows.events");
+ });
+
+ browser.test.sendMessage("ready");
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background: `(${background})()`,
+ });
+
+ yield extension.startup();
+ yield extension.awaitMessage("ready");
+ let win1 = yield BrowserTestUtils.openNewBrowserWindow();
+ let windowId = yield extension.awaitMessage("window-created");
+ yield BrowserTestUtils.closeWindow(win1);
+ yield extension.awaitMessage(`window-removed-${windowId}`);
+ yield extension.awaitFinish("windows.events");
+ yield extension.unload();
+});
diff --git a/browser/components/extensions/test/browser/file_popup_api_injection_a.html b/browser/components/extensions/test/browser/file_popup_api_injection_a.html
index dd1632da875b..750ff1db3782 100644
--- a/browser/components/extensions/test/browser/file_popup_api_injection_a.html
+++ b/browser/components/extensions/test/browser/file_popup_api_injection_a.html
@@ -3,6 +3,7 @@
diff --git a/browser/components/extensions/test/browser/file_popup_api_injection_b.html b/browser/components/extensions/test/browser/file_popup_api_injection_b.html
index 24d749220e03..b8c287e55c85 100644
--- a/browser/components/extensions/test/browser/file_popup_api_injection_b.html
+++ b/browser/components/extensions/test/browser/file_popup_api_injection_b.html
@@ -3,6 +3,7 @@
diff --git a/browser/components/extensions/test/browser/head.js b/browser/components/extensions/test/browser/head.js
index 28d048c7f608..6944d0e2dea6 100644
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -78,10 +78,8 @@ function getBrowserActionPopup(extension, win = window) {
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
return win.document.getElementById("customizationui-widget-panel");
- } else {
- return win.PanelUI.panel;
}
- return null;
+ return win.PanelUI.panel;
}
var clickBrowserAction = Task.async(function* (extension, win = window) {
diff --git a/browser/components/migration/ESEDBReader.jsm b/browser/components/migration/ESEDBReader.jsm
index b94e2754ee6b..e952b0cd41a5 100644
--- a/browser/components/migration/ESEDBReader.jsm
+++ b/browser/components/migration/ESEDBReader.jsm
@@ -478,6 +478,7 @@ ESEDB.prototype = {
systemTime.wSecond,
systemTime.wMilliseconds));
}
+ return undefined;
},
_getColumnInfo(tableName, columns) {
diff --git a/browser/components/migration/MSMigrationUtils.jsm b/browser/components/migration/MSMigrationUtils.jsm
index 0ba933bd6c2a..5b52ce86bacf 100644
--- a/browser/components/migration/MSMigrationUtils.jsm
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -872,6 +872,7 @@ WindowsVaultFormPasswords.prototype = {
if (aOnlyCheckExists) {
return false;
}
+ return undefined;
}
};
diff --git a/browser/components/migration/content/migration.js b/browser/components/migration/content/migration.js
index f2fc8dc4421e..0de70247fdae 100644
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -161,6 +161,7 @@ var MigrationWizard = {
else
this._selectedProfile = null;
}
+ return undefined;
},
// 2 - [Profile Selection]
diff --git a/browser/components/search/content/search.xml b/browser/components/search/content/search.xml
index 84c6134db4de..33900c1dfa1f 100644
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -1436,7 +1436,22 @@
BrowserSearch.searchBar.openSuggestionsPanel();
},
onError: function(errorCode) {
- Components.utils.reportError("Error adding search engine: " + errorCode);
+ if (errorCode != Ci.nsISearchInstallCallback.ERROR_DUPLICATE_ENGINE) {
+ // Download error is shown by the search service
+ return;
+ }
+ const kSearchBundleURI = "chrome://global/locale/search/search.properties";
+ let searchBundle = Services.strings.createBundle(kSearchBundleURI);
+ let brandBundle = document.getElementById("bundle_brand");
+ let brandName = brandBundle.getString("brandShortName");
+ let title = searchBundle.GetStringFromName("error_invalid_engine_title");
+ let text = searchBundle.formatStringFromName("error_duplicate_engine_msg",
+ [brandName, target.getAttribute("uri")], 2);
+ Services.prompt.QueryInterface(Ci.nsIPromptFactory);
+ let prompt = Services.prompt.getPrompt(gBrowser.contentWindow, Ci.nsIPrompt);
+ prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
+ prompt.setPropertyAsBool("allowTabModal", true);
+ prompt.alert(title, text);
}
}
Services.search.addEngine(target.getAttribute("uri"), null,
diff --git a/browser/components/uitour/test/head.js b/browser/components/uitour/test/head.js
index c1332f9a1189..ac3275fa3681 100644
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -27,6 +27,7 @@ function waitForConditionPromise(condition, timeoutMsg, tryCount=NUMBER_OF_TRIES
}
tries++;
setTimeout(checkCondition, SINGLE_TRY_TIMEOUT);
+ return undefined;
}
setTimeout(checkCondition, SINGLE_TRY_TIMEOUT);
return defer.promise;
diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm
index 30075ae3fdf1..76c6bd7dfef1 100644
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -1822,6 +1822,7 @@ Experiments.ExperimentEntry.prototype = {
this._log.error("_installAddon() - onInstallStarted, wrong addon type");
return false;
}
+ return undefined;
},
onInstallEnded: install => {
diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla
index b61e130b451e..eb2a3316f28d 100644
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
-Current extension version is: 1.4.185
+Current extension version is: 1.4.213
diff --git a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
index f1635da23369..17ad4c6bb377 100644
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -1023,14 +1023,18 @@ PdfStreamConverter.prototype = {
// Keep the URL the same so the browser sees it as the same.
channel.originalURI = aRequest.URI;
channel.loadGroup = aRequest.loadGroup;
+ channel.loadInfo.originAttributes = aRequest.loadInfo.originAttributes;
// We can use resource principal when data is fetched by the chrome
+ // make sure we reuse the origin attributes from the request channel to keep
+ // isolation consistent.
// e.g. useful for NoScript
var ssm = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager);
var uri = NetUtil.newURI(PDF_VIEWER_WEB_PAGE, null, null);
+ var attrs = aRequest.loadInfo.originAttributes;
var resourcePrincipal;
- resourcePrincipal = ssm.createCodebasePrincipal(uri, {});
+ resourcePrincipal = ssm.createCodebasePrincipal(uri, attrs);
aRequest.owner = resourcePrincipal;
channel.asyncOpen(proxy, aContext);
},
diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js
index 75b5b14b79e4..6e86de8bed09 100644
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
// Use strict in our context only - users might not want it
'use strict';
-var pdfjsVersion = '1.4.185';
-var pdfjsBuild = 'a250c15';
+var pdfjsVersion = '1.4.213';
+var pdfjsBuild = '1c253e6';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@@ -613,6 +613,17 @@ function isLittleEndian() {
return (buffer16[0] === 1);
}
+// Checks if it's possible to eval JS expressions.
+function isEvalSupported() {
+ try {
+ /* jshint evil: true */
+ new Function('');
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
@@ -867,7 +878,7 @@ var Util = (function UtilClosure() {
/**
* PDF page viewport created based on scale, rotation and offset.
* @class
- * @alias PDFJS.PageViewport
+ * @alias PageViewport
*/
var PageViewport = (function PageViewportClosure() {
/**
@@ -943,13 +954,13 @@ var PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ PageViewport.prototype = /** @lends PageViewport.prototype */ {
/**
* Clones viewport with additional properties.
* @param args {Object} (optional) If specified, may contain the 'scale' or
* 'rotation' properties to override the corresponding properties in
* the cloned viewport.
- * @returns {PDFJS.PageViewport} Cloned viewport.
+ * @returns {PageViewport} Cloned viewport.
*/
clone: function PageViewPort_clone(args) {
args = args || {};
@@ -1079,7 +1090,7 @@ function isArrayBuffer(v) {
/**
* Creates a promise capability object.
- * @alias PDFJS.createPromiseCapability
+ * @alias createPromiseCapability
*
* @return {PromiseCapability} A capability object contains:
* - a Promise, resolve and reject methods.
@@ -1443,6 +1454,7 @@ exports.isString = isString;
exports.isSameOrigin = isSameOrigin;
exports.isValidUrl = isValidUrl;
exports.isLittleEndian = isLittleEndian;
+exports.isEvalSupported = isEvalSupported;
exports.loadJpegStream = loadJpegStream;
exports.log2 = log2;
exports.readInt8 = readInt8;
@@ -1462,88 +1474,12 @@ exports.warn = warn;
(function (root, factory) {
{
- factory((root.pdfjsDisplayGlobal = {}), root.pdfjsSharedUtil);
+ factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedUtil);
}
}(this, function (exports, sharedUtil) {
- var globalScope = sharedUtil.globalScope;
-
- var isWorker = (typeof window === 'undefined');
-
- // The global PDFJS object exposes the API
- // In production, it will be declared outside a global wrapper
- // In development, it will be declared here
- if (!globalScope.PDFJS) {
- globalScope.PDFJS = {};
- }
- var PDFJS = globalScope.PDFJS;
-
- if (typeof pdfjsVersion !== 'undefined') {
- PDFJS.version = pdfjsVersion;
- }
- if (typeof pdfjsBuild !== 'undefined') {
- PDFJS.build = pdfjsBuild;
- }
-
- PDFJS.pdfBug = false;
-
- if (PDFJS.verbosity !== undefined) {
- sharedUtil.setVerbosityLevel(PDFJS.verbosity);
- }
- delete PDFJS.verbosity;
- Object.defineProperty(PDFJS, 'verbosity', {
- get: function () { return sharedUtil.getVerbosityLevel(); },
- set: function (level) { sharedUtil.setVerbosityLevel(level); },
- enumerable: true,
- configurable: true
- });
-
- PDFJS.VERBOSITY_LEVELS = sharedUtil.VERBOSITY_LEVELS;
- PDFJS.OPS = sharedUtil.OPS;
- PDFJS.UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
- PDFJS.isValidUrl = sharedUtil.isValidUrl;
- PDFJS.shadow = sharedUtil.shadow;
- PDFJS.createBlob = sharedUtil.createBlob;
- PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) {
- return sharedUtil.createObjectURL(data, contentType,
- PDFJS.disableCreateObjectURL);
- };
- Object.defineProperty(PDFJS, 'isLittleEndian', {
- configurable: true,
- get: function PDFJS_isLittleEndian() {
- var value = sharedUtil.isLittleEndian();
- return sharedUtil.shadow(PDFJS, 'isLittleEndian', value);
- }
- });
- PDFJS.removeNullCharacters = sharedUtil.removeNullCharacters;
- PDFJS.PasswordResponses = sharedUtil.PasswordResponses;
- PDFJS.PasswordException = sharedUtil.PasswordException;
- PDFJS.UnknownErrorException = sharedUtil.UnknownErrorException;
- PDFJS.InvalidPDFException = sharedUtil.InvalidPDFException;
- PDFJS.MissingPDFException = sharedUtil.MissingPDFException;
- PDFJS.UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
- PDFJS.Util = sharedUtil.Util;
- PDFJS.PageViewport = sharedUtil.PageViewport;
- PDFJS.createPromiseCapability = sharedUtil.createPromiseCapability;
-
- exports.globalScope = globalScope;
- exports.isWorker = isWorker;
- exports.PDFJS = globalScope.PDFJS;
-}));
-
-
-(function (root, factory) {
- {
- factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedUtil,
- root.pdfjsDisplayGlobal);
- }
-}(this, function (exports, sharedUtil, displayGlobal) {
-
-var deprecated = sharedUtil.deprecated;
var removeNullCharacters = sharedUtil.removeNullCharacters;
-var shadow = sharedUtil.shadow;
var warn = sharedUtil.warn;
-var PDFJS = displayGlobal.PDFJS;
/**
* Optimised CSS custom property getter/setter.
@@ -1599,9 +1535,7 @@ var CustomStyle = (function CustomStyleClosure() {
return CustomStyle;
})();
-PDFJS.CustomStyle = CustomStyle;
-
- PDFJS.hasCanvasTypedArrays = true;
+ function hasCanvasTypedArrays() { return true; }
var LinkTarget = {
NONE: 0, // Default value.
@@ -1611,8 +1545,6 @@ var LinkTarget = {
TOP: 4,
};
-PDFJS.LinkTarget = LinkTarget;
-
var LinkTargetStringMap = [
'',
'_self',
@@ -1621,42 +1553,37 @@ var LinkTargetStringMap = [
'_top'
];
-function isExternalLinkTargetSet() {
- switch (PDFJS.externalLinkTarget) {
- case LinkTarget.NONE:
- return false;
- case LinkTarget.SELF:
- case LinkTarget.BLANK:
- case LinkTarget.PARENT:
- case LinkTarget.TOP:
- return true;
- }
- warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget);
- // Reset the external link target, to suppress further warnings.
- PDFJS.externalLinkTarget = LinkTarget.NONE;
- return false;
-}
-PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet;
+/**
+ * @typedef ExternalLinkParameters
+ * @typedef {Object} ExternalLinkParameters
+ * @property {string} url
+ * @property {LinkTarget} target
+ * @property {string} rel
+ */
/**
* Adds various attributes (href, title, target, rel) to hyperlinks.
* @param {HTMLLinkElement} link - The link element.
- * @param {Object} params - An object with the properties:
- * @param {string} params.url - An absolute URL.
+ * @param {ExternalLinkParameters} params - An object with the properties.
*/
function addLinkAttributes(link, params) {
var url = params && params.url;
link.href = link.title = (url ? removeNullCharacters(url) : '');
if (url) {
- if (isExternalLinkTargetSet()) {
- link.target = LinkTargetStringMap[PDFJS.externalLinkTarget];
+ var target = params.target;
+ if (typeof target === 'undefined') {
+ target = getDefaultSetting('externalLinkTarget');
}
+ link.target = LinkTargetStringMap[target];
// Strip referrer from the URL.
- link.rel = PDFJS.externalLinkRel;
+ var rel = params.rel;
+ if (typeof rel === 'undefined') {
+ rel = getDefaultSetting('externalLinkRel');
+ }
+ link.rel = rel;
}
}
-PDFJS.addLinkAttributes = addLinkAttributes;
// Gets the file name from a given URL.
function getFilenameFromUrl(url) {
@@ -1667,22 +1594,96 @@ function getFilenameFromUrl(url) {
query > 0 ? query : url.length);
return url.substring(url.lastIndexOf('/', end) + 1, end);
}
-PDFJS.getFilenameFromUrl = getFilenameFromUrl;
+
+function getDefaultSetting(id) {
+ // The list of the settings and their default is maintained for backward
+ // compatibility and shall not be extended or modified. See also global.js.
+ var globalSettings = sharedUtil.globalScope.PDFJS;
+ switch (id) {
+ case 'pdfBug':
+ return globalSettings ? globalSettings.pdfBug : false;
+ case 'disableAutoFetch':
+ return globalSettings ? globalSettings.disableAutoFetch : false;
+ case 'disableStream':
+ return globalSettings ? globalSettings.disableStream : false;
+ case 'disableRange':
+ return globalSettings ? globalSettings.disableRange : false;
+ case 'disableFontFace':
+ return globalSettings ? globalSettings.disableFontFace : false;
+ case 'disableCreateObjectURL':
+ return globalSettings ? globalSettings.disableCreateObjectURL : false;
+ case 'disableWebGL':
+ return globalSettings ? globalSettings.disableWebGL : true;
+ case 'cMapUrl':
+ return globalSettings ? globalSettings.cMapUrl : null;
+ case 'cMapPacked':
+ return globalSettings ? globalSettings.cMapPacked : false;
+ case 'postMessageTransfers':
+ return globalSettings ? globalSettings.postMessageTransfers : true;
+ case 'workerSrc':
+ return globalSettings ? globalSettings.workerSrc : null;
+ case 'disableWorker':
+ return globalSettings ? globalSettings.disableWorker : false;
+ case 'maxImageSize':
+ return globalSettings ? globalSettings.maxImageSize : -1;
+ case 'imageResourcesPath':
+ return globalSettings ? globalSettings.imageResourcesPath : '';
+ case 'isEvalSupported':
+ return globalSettings ? globalSettings.isEvalSupported : true;
+ case 'externalLinkTarget':
+ if (!globalSettings) {
+ return LinkTarget.NONE;
+ }
+ switch (globalSettings.externalLinkTarget) {
+ case LinkTarget.NONE:
+ case LinkTarget.SELF:
+ case LinkTarget.BLANK:
+ case LinkTarget.PARENT:
+ case LinkTarget.TOP:
+ return globalSettings.externalLinkTarget;
+ }
+ warn('PDFJS.externalLinkTarget is invalid: ' +
+ globalSettings.externalLinkTarget);
+ // Reset the external link target, to suppress further warnings.
+ globalSettings.externalLinkTarget = LinkTarget.NONE;
+ return LinkTarget.NONE;
+ case 'externalLinkRel':
+ return globalSettings ? globalSettings.externalLinkRel : 'noreferrer';
+ case 'enableStats':
+ return !!(globalSettings && globalSettings.enableStats);
+ default:
+ throw new Error('Unknown default setting: ' + id);
+ }
+}
+
+function isExternalLinkTargetSet() {
+ var externalLinkTarget = getDefaultSetting('externalLinkTarget');
+ switch (externalLinkTarget) {
+ case LinkTarget.NONE:
+ return false;
+ case LinkTarget.SELF:
+ case LinkTarget.BLANK:
+ case LinkTarget.PARENT:
+ case LinkTarget.TOP:
+ return true;
+ }
+}
exports.CustomStyle = CustomStyle;
exports.addLinkAttributes = addLinkAttributes;
exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
exports.getFilenameFromUrl = getFilenameFromUrl;
exports.LinkTarget = LinkTarget;
+exports.hasCanvasTypedArrays = hasCanvasTypedArrays;
+exports.getDefaultSetting = getDefaultSetting;
}));
(function (root, factory) {
{
- factory((root.pdfjsDisplayFontLoader = {}), root.pdfjsSharedUtil,
- root.pdfjsDisplayGlobal);
+ factory((root.pdfjsDisplayFontLoader = {}), root.pdfjsSharedUtil);
}
-}(this, function (exports, sharedUtil, displayGlobal) {
+}(this, function (exports, sharedUtil) {
var assert = sharedUtil.assert;
var bytesToString = sharedUtil.bytesToString;
@@ -1690,10 +1691,6 @@ var string32 = sharedUtil.string32;
var shadow = sharedUtil.shadow;
var warn = sharedUtil.warn;
-var PDFJS = displayGlobal.PDFJS;
-var globalScope = displayGlobal.globalScope;
-var isWorker = displayGlobal.isWorker;
-
function FontLoader(docId) {
this.docId = docId;
this.styleElement = null;
@@ -1720,8 +1717,6 @@ FontLoader.prototype = {
}
},
bind: function fontLoaderBind(fonts, callback) {
- assert(!isWorker, 'bind() shall be called from main thread');
-
for (var i = 0, ii = fonts.length; i < ii; i++) {
var font = fonts[i];
if (font.attached) {
@@ -1739,29 +1734,21 @@ FontLoader.prototype = {
}
};
+var IsEvalSupportedCached = {
+ get value() {
+ return shadow(this, 'value', sharedUtil.isEvalSupported());
+ }
+};
+
var FontFaceObject = (function FontFaceObjectClosure() {
- function FontFaceObject(translatedData) {
+ function FontFaceObject(translatedData, options) {
this.compiledGlyphs = Object.create(null);
// importing translated data
for (var i in translatedData) {
this[i] = translatedData[i];
}
+ this.options = options;
}
- Object.defineProperty(FontFaceObject, 'isEvalSupported', {
- get: function () {
- var evalSupport = false;
- if (PDFJS.isEvalSupported) {
- try {
- /* jshint evil: true */
- new Function('');
- evalSupport = true;
- } catch (e) {}
- }
- return shadow(this, 'isEvalSupported', evalSupport);
- },
- enumerable: true,
- configurable: true
- });
FontFaceObject.prototype = {
createFontFaceRule: function FontFaceObject_createFontFaceRule() {
@@ -1769,7 +1756,7 @@ var FontFaceObject = (function FontFaceObjectClosure() {
return null;
}
- if (PDFJS.disableFontFace) {
+ if (this.options.disableFontFace) {
this.disableFontFace = true;
return null;
}
@@ -1778,13 +1765,11 @@ var FontFaceObject = (function FontFaceObjectClosure() {
var fontName = this.loadedName;
// Add the font-face rule to the document
- var url = ('url(data:' + this.mimetype + ';base64,' +
- window.btoa(data) + ');');
+ var url = ('url(data:' + this.mimetype + ';base64,' + btoa(data) + ');');
var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
- if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
- globalScope['FontInspector'].enabled) {
- globalScope['FontInspector'].fontAdded(this, url);
+ if (this.options.fontRegistry) {
+ this.options.fontRegistry.registerFont(this, url);
}
return rule;
@@ -1797,7 +1782,7 @@ var FontFaceObject = (function FontFaceObjectClosure() {
var current, i, len;
// If we can, compile cmds into JS for MAXIMUM SPEED
- if (FontFaceObject.isEvalSupported) {
+ if (this.options.isEvalSupported && IsEvalSupportedCached.value) {
var args, js = '';
for (i = 0, len = cmds.length; i < len; i++) {
current = cmds[i];
@@ -1841,15 +1826,12 @@ exports.FontLoader = FontLoader;
(function (root, factory) {
{
- factory((root.pdfjsDisplayMetadata = {}), root.pdfjsSharedUtil,
- root.pdfjsDisplayGlobal);
+ factory((root.pdfjsDisplayMetadata = {}), root.pdfjsSharedUtil);
}
-}(this, function (exports, sharedUtil, displayGlobal) {
+}(this, function (exports, sharedUtil) {
var error = sharedUtil.error;
-var PDFJS = displayGlobal.PDFJS;
-var Metadata = PDFJS.Metadata = (function MetadataClosure() {
function fixMetadata(meta) {
return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
@@ -1926,441 +1908,15 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
}
};
- return Metadata;
-})();
-
exports.Metadata = Metadata;
}));
(function (root, factory) {
{
- factory((root.pdfjsDisplayWebGL = {}), root.pdfjsSharedUtil,
- root.pdfjsDisplayGlobal);
+ factory((root.pdfjsDisplaySVG = {}), root.pdfjsSharedUtil);
}
-}(this, function (exports, sharedUtil, displayGlobal) {
-
-var shadow = sharedUtil.shadow;
-var PDFJS = displayGlobal.PDFJS;
-
-var WebGLUtils = (function WebGLUtilsClosure() {
- function loadShader(gl, code, shaderType) {
- var shader = gl.createShader(shaderType);
- gl.shaderSource(shader, code);
- gl.compileShader(shader);
- var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
- if (!compiled) {
- var errorMsg = gl.getShaderInfoLog(shader);
- throw new Error('Error during shader compilation: ' + errorMsg);
- }
- return shader;
- }
- function createVertexShader(gl, code) {
- return loadShader(gl, code, gl.VERTEX_SHADER);
- }
- function createFragmentShader(gl, code) {
- return loadShader(gl, code, gl.FRAGMENT_SHADER);
- }
- function createProgram(gl, shaders) {
- var program = gl.createProgram();
- for (var i = 0, ii = shaders.length; i < ii; ++i) {
- gl.attachShader(program, shaders[i]);
- }
- gl.linkProgram(program);
- var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
- if (!linked) {
- var errorMsg = gl.getProgramInfoLog(program);
- throw new Error('Error during program linking: ' + errorMsg);
- }
- return program;
- }
- function createTexture(gl, image, textureId) {
- gl.activeTexture(textureId);
- var texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
-
- // Set the parameters so we can render any size image.
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-
- // Upload the image into the texture.
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
- return texture;
- }
-
- var currentGL, currentCanvas;
- function generateGL() {
- if (currentGL) {
- return;
- }
- currentCanvas = document.createElement('canvas');
- currentGL = currentCanvas.getContext('webgl',
- { premultipliedalpha: false });
- }
-
- var smaskVertexShaderCode = '\
- attribute vec2 a_position; \
- attribute vec2 a_texCoord; \
- \
- uniform vec2 u_resolution; \
- \
- varying vec2 v_texCoord; \
- \
- void main() { \
- vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
- gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
- \
- v_texCoord = a_texCoord; \
- } ';
-
- var smaskFragmentShaderCode = '\
- precision mediump float; \
- \
- uniform vec4 u_backdrop; \
- uniform int u_subtype; \
- uniform sampler2D u_image; \
- uniform sampler2D u_mask; \
- \
- varying vec2 v_texCoord; \
- \
- void main() { \
- vec4 imageColor = texture2D(u_image, v_texCoord); \
- vec4 maskColor = texture2D(u_mask, v_texCoord); \
- if (u_backdrop.a > 0.0) { \
- maskColor.rgb = maskColor.rgb * maskColor.a + \
- u_backdrop.rgb * (1.0 - maskColor.a); \
- } \
- float lum; \
- if (u_subtype == 0) { \
- lum = maskColor.a; \
- } else { \
- lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
- maskColor.b * 0.11; \
- } \
- imageColor.a *= lum; \
- imageColor.rgb *= imageColor.a; \
- gl_FragColor = imageColor; \
- } ';
-
- var smaskCache = null;
-
- function initSmaskGL() {
- var canvas, gl;
-
- generateGL();
- canvas = currentCanvas;
- currentCanvas = null;
- gl = currentGL;
- currentGL = null;
-
- // setup a GLSL program
- var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
- var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
- var program = createProgram(gl, [vertexShader, fragmentShader]);
- gl.useProgram(program);
-
- var cache = {};
- cache.gl = gl;
- cache.canvas = canvas;
- cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
- cache.positionLocation = gl.getAttribLocation(program, 'a_position');
- cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
- cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
-
- var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
- var texLayerLocation = gl.getUniformLocation(program, 'u_image');
- var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
-
- // provide texture coordinates for the rectangle.
- var texCoordBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
- 0.0, 0.0,
- 1.0, 0.0,
- 0.0, 1.0,
- 0.0, 1.0,
- 1.0, 0.0,
- 1.0, 1.0]), gl.STATIC_DRAW);
- gl.enableVertexAttribArray(texCoordLocation);
- gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
-
- gl.uniform1i(texLayerLocation, 0);
- gl.uniform1i(texMaskLocation, 1);
-
- smaskCache = cache;
- }
-
- function composeSMask(layer, mask, properties) {
- var width = layer.width, height = layer.height;
-
- if (!smaskCache) {
- initSmaskGL();
- }
- var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
- canvas.width = width;
- canvas.height = height;
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
- gl.uniform2f(cache.resolutionLocation, width, height);
-
- if (properties.backdrop) {
- gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
- properties.backdrop[1], properties.backdrop[2], 1);
- } else {
- gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
- }
- gl.uniform1i(cache.subtypeLocation,
- properties.subtype === 'Luminosity' ? 1 : 0);
-
- // Create a textures
- var texture = createTexture(gl, layer, gl.TEXTURE0);
- var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
-
-
- // Create a buffer and put a single clipspace rectangle in
- // it (2 triangles)
- var buffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
- 0, 0,
- width, 0,
- 0, height,
- 0, height,
- width, 0,
- width, height]), gl.STATIC_DRAW);
- gl.enableVertexAttribArray(cache.positionLocation);
- gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
-
- // draw
- gl.clearColor(0, 0, 0, 0);
- gl.enable(gl.BLEND);
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
- gl.clear(gl.COLOR_BUFFER_BIT);
-
- gl.drawArrays(gl.TRIANGLES, 0, 6);
-
- gl.flush();
-
- gl.deleteTexture(texture);
- gl.deleteTexture(maskTexture);
- gl.deleteBuffer(buffer);
-
- return canvas;
- }
-
- var figuresVertexShaderCode = '\
- attribute vec2 a_position; \
- attribute vec3 a_color; \
- \
- uniform vec2 u_resolution; \
- uniform vec2 u_scale; \
- uniform vec2 u_offset; \
- \
- varying vec4 v_color; \
- \
- void main() { \
- vec2 position = (a_position + u_offset) * u_scale; \
- vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
- gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
- \
- v_color = vec4(a_color / 255.0, 1.0); \
- } ';
-
- var figuresFragmentShaderCode = '\
- precision mediump float; \
- \
- varying vec4 v_color; \
- \
- void main() { \
- gl_FragColor = v_color; \
- } ';
-
- var figuresCache = null;
-
- function initFiguresGL() {
- var canvas, gl;
-
- generateGL();
- canvas = currentCanvas;
- currentCanvas = null;
- gl = currentGL;
- currentGL = null;
-
- // setup a GLSL program
- var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
- var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
- var program = createProgram(gl, [vertexShader, fragmentShader]);
- gl.useProgram(program);
-
- var cache = {};
- cache.gl = gl;
- cache.canvas = canvas;
- cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
- cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
- cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
- cache.positionLocation = gl.getAttribLocation(program, 'a_position');
- cache.colorLocation = gl.getAttribLocation(program, 'a_color');
-
- figuresCache = cache;
- }
-
- function drawFigures(width, height, backgroundColor, figures, context) {
- if (!figuresCache) {
- initFiguresGL();
- }
- var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
-
- canvas.width = width;
- canvas.height = height;
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
- gl.uniform2f(cache.resolutionLocation, width, height);
-
- // count triangle points
- var count = 0;
- var i, ii, rows;
- for (i = 0, ii = figures.length; i < ii; i++) {
- switch (figures[i].type) {
- case 'lattice':
- rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
- count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
- break;
- case 'triangles':
- count += figures[i].coords.length;
- break;
- }
- }
- // transfer data
- var coords = new Float32Array(count * 2);
- var colors = new Uint8Array(count * 3);
- var coordsMap = context.coords, colorsMap = context.colors;
- var pIndex = 0, cIndex = 0;
- for (i = 0, ii = figures.length; i < ii; i++) {
- var figure = figures[i], ps = figure.coords, cs = figure.colors;
- switch (figure.type) {
- case 'lattice':
- var cols = figure.verticesPerRow;
- rows = (ps.length / cols) | 0;
- for (var row = 1; row < rows; row++) {
- var offset = row * cols + 1;
- for (var col = 1; col < cols; col++, offset++) {
- coords[pIndex] = coordsMap[ps[offset - cols - 1]];
- coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
- coords[pIndex + 2] = coordsMap[ps[offset - cols]];
- coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
- coords[pIndex + 4] = coordsMap[ps[offset - 1]];
- coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
- colors[cIndex] = colorsMap[cs[offset - cols - 1]];
- colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
- colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
- colors[cIndex + 3] = colorsMap[cs[offset - cols]];
- colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
- colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
- colors[cIndex + 6] = colorsMap[cs[offset - 1]];
- colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
- colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
-
- coords[pIndex + 6] = coords[pIndex + 2];
- coords[pIndex + 7] = coords[pIndex + 3];
- coords[pIndex + 8] = coords[pIndex + 4];
- coords[pIndex + 9] = coords[pIndex + 5];
- coords[pIndex + 10] = coordsMap[ps[offset]];
- coords[pIndex + 11] = coordsMap[ps[offset] + 1];
- colors[cIndex + 9] = colors[cIndex + 3];
- colors[cIndex + 10] = colors[cIndex + 4];
- colors[cIndex + 11] = colors[cIndex + 5];
- colors[cIndex + 12] = colors[cIndex + 6];
- colors[cIndex + 13] = colors[cIndex + 7];
- colors[cIndex + 14] = colors[cIndex + 8];
- colors[cIndex + 15] = colorsMap[cs[offset]];
- colors[cIndex + 16] = colorsMap[cs[offset] + 1];
- colors[cIndex + 17] = colorsMap[cs[offset] + 2];
- pIndex += 12;
- cIndex += 18;
- }
- }
- break;
- case 'triangles':
- for (var j = 0, jj = ps.length; j < jj; j++) {
- coords[pIndex] = coordsMap[ps[j]];
- coords[pIndex + 1] = coordsMap[ps[j] + 1];
- colors[cIndex] = colorsMap[cs[j]];
- colors[cIndex + 1] = colorsMap[cs[j] + 1];
- colors[cIndex + 2] = colorsMap[cs[j] + 2];
- pIndex += 2;
- cIndex += 3;
- }
- break;
- }
- }
-
- // draw
- if (backgroundColor) {
- gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
- backgroundColor[2] / 255, 1.0);
- } else {
- gl.clearColor(0, 0, 0, 0);
- }
- gl.clear(gl.COLOR_BUFFER_BIT);
-
- var coordsBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
- gl.enableVertexAttribArray(cache.positionLocation);
- gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
-
- var colorsBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
- gl.enableVertexAttribArray(cache.colorLocation);
- gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
- 0, 0);
-
- gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
- gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
-
- gl.drawArrays(gl.TRIANGLES, 0, count);
-
- gl.flush();
-
- gl.deleteBuffer(coordsBuffer);
- gl.deleteBuffer(colorsBuffer);
-
- return canvas;
- }
-
- function cleanup() {
- if (smaskCache && smaskCache.canvas) {
- smaskCache.canvas.width = 0;
- smaskCache.canvas.height = 0;
- }
- if (figuresCache && figuresCache.canvas) {
- figuresCache.canvas.width = 0;
- figuresCache.canvas.height = 0;
- }
- smaskCache = null;
- figuresCache = null;
- }
-
- return {
- get isEnabled() {
- if (PDFJS.disableWebGL) {
- return false;
- }
- var enabled = false;
- try {
- generateGL();
- enabled = !!currentGL;
- } catch (e) { }
- return shadow(this, 'isEnabled', enabled);
- },
- composeSMask: composeSMask,
- drawFigures: drawFigures,
- clear: cleanup
- };
-})();
-
-exports.WebGLUtils = WebGLUtils;
+}(this, function (exports, sharedUtil) {
}));
@@ -2378,6 +1934,7 @@ var addLinkAttributes = displayDOMUtils.addLinkAttributes;
var getFilenameFromUrl = displayDOMUtils.getFilenameFromUrl;
var warn = sharedUtil.warn;
var CustomStyle = displayDOMUtils.CustomStyle;
+var getDefaultSetting = displayDOMUtils.getDefaultSetting;
/**
* @typedef {Object} AnnotationElementParameters
@@ -2450,6 +2007,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
this.viewport = parameters.viewport;
this.linkService = parameters.linkService;
this.downloadManager = parameters.downloadManager;
+ this.imageResourcesPath = parameters.imageResourcesPath;
if (isRenderable) {
this.container = this._createContainer();
@@ -2706,7 +2264,7 @@ var TextAnnotationElement = (function TextAnnotationElementClosure() {
var image = document.createElement('img');
image.style.height = this.container.style.height;
image.style.width = this.container.style.width;
- image.src = PDFJS.imageResourcesPath + 'annotation-' +
+ image.src = this.imageResourcesPath + 'annotation-' +
this.data.name.toLowerCase() + '.svg';
image.alt = '[{{type}} Annotation]';
image.dataset.l10nId = 'text_annotation_type';
@@ -3181,6 +2739,7 @@ var FileAttachmentAnnotationElement = (
* @property {Array} annotations
* @property {PDFPage} page
* @property {IPDFLinkService} linkService
+ * @property {string} imageResourcesPath
*/
/**
@@ -3211,7 +2770,9 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
page: parameters.page,
viewport: parameters.viewport,
linkService: parameters.linkService,
- downloadManager: parameters.downloadManager
+ downloadManager: parameters.downloadManager,
+ imageResourcesPath: parameters.imageResourcesPath ||
+ getDefaultSetting('imageResourcesPath')
};
var element = annotationElementFactory.create(properties);
if (element.isRenderable) {
@@ -3242,12 +2803,674 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
};
})();
-PDFJS.AnnotationLayer = AnnotationLayer;
-
exports.AnnotationLayer = AnnotationLayer;
}));
+(function (root, factory) {
+ {
+ factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil,
+ root.pdfjsDisplayDOMUtils);
+ }
+}(this, function (exports, sharedUtil, displayDOMUtils) {
+
+var Util = sharedUtil.Util;
+var createPromiseCapability = sharedUtil.createPromiseCapability;
+var CustomStyle = displayDOMUtils.CustomStyle;
+var getDefaultSetting = displayDOMUtils.getDefaultSetting;
+var PageViewport = sharedUtil.PageViewport;
+
+/**
+ * Text layer render parameters.
+ *
+ * @typedef {Object} TextLayerRenderParameters
+ * @property {TextContent} textContent - Text content to render (the object is
+ * returned by the page's getTextContent() method).
+ * @property {HTMLElement} container - HTML element that will contain text runs.
+ * @property {PageViewport} viewport - The target viewport to properly
+ * layout the text runs.
+ * @property {Array} textDivs - (optional) HTML elements that are correspond
+ * the text items of the textContent input. This is output and shall be
+ * initially be set to empty array.
+ * @property {number} timeout - (optional) Delay in milliseconds before
+ * rendering of the text runs occurs.
+ */
+var renderTextLayer = (function renderTextLayerClosure() {
+ var MAX_TEXT_DIVS_TO_RENDER = 100000;
+
+ var NonWhitespaceRegexp = /\S/;
+
+ function isAllWhitespace(str) {
+ return !NonWhitespaceRegexp.test(str);
+ }
+
+ function appendText(textDivs, viewport, geom, styles) {
+ var style = styles[geom.fontName];
+ var textDiv = document.createElement('div');
+ textDivs.push(textDiv);
+ if (isAllWhitespace(geom.str)) {
+ textDiv.dataset.isWhitespace = true;
+ return;
+ }
+ var tx = Util.transform(viewport.transform, geom.transform);
+ var angle = Math.atan2(tx[1], tx[0]);
+ if (style.vertical) {
+ angle += Math.PI / 2;
+ }
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
+ var fontAscent = fontHeight;
+ if (style.ascent) {
+ fontAscent = style.ascent * fontAscent;
+ } else if (style.descent) {
+ fontAscent = (1 + style.descent) * fontAscent;
+ }
+
+ var left;
+ var top;
+ if (angle === 0) {
+ left = tx[4];
+ top = tx[5] - fontAscent;
+ } else {
+ left = tx[4] + (fontAscent * Math.sin(angle));
+ top = tx[5] - (fontAscent * Math.cos(angle));
+ }
+ textDiv.style.left = left + 'px';
+ textDiv.style.top = top + 'px';
+ textDiv.style.fontSize = fontHeight + 'px';
+ textDiv.style.fontFamily = style.fontFamily;
+
+ textDiv.textContent = geom.str;
+ // |fontName| is only used by the Font Inspector. This test will succeed
+ // when e.g. the Font Inspector is off but the Stepper is on, but it's
+ // not worth the effort to do a more accurate test.
+ if (getDefaultSetting('pdfBug')) {
+ textDiv.dataset.fontName = geom.fontName;
+ }
+ // Storing into dataset will convert number into string.
+ if (angle !== 0) {
+ textDiv.dataset.angle = angle * (180 / Math.PI);
+ }
+ // We don't bother scaling single-char text divs, because it has very
+ // little effect on text highlighting. This makes scrolling on docs with
+ // lots of such divs a lot faster.
+ if (geom.str.length > 1) {
+ if (style.vertical) {
+ textDiv.dataset.canvasWidth = geom.height * viewport.scale;
+ } else {
+ textDiv.dataset.canvasWidth = geom.width * viewport.scale;
+ }
+ }
+ }
+
+ function render(task) {
+ if (task._canceled) {
+ return;
+ }
+ var textLayerFrag = task._container;
+ var textDivs = task._textDivs;
+ var capability = task._capability;
+ var textDivsLength = textDivs.length;
+
+ // No point in rendering many divs as it would make the browser
+ // unusable even after the divs are rendered.
+ if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
+ capability.resolve();
+ return;
+ }
+
+ var canvas = document.createElement('canvas');
+ canvas.mozOpaque = true;
+ var ctx = canvas.getContext('2d', {alpha: false});
+
+ var lastFontSize;
+ var lastFontFamily;
+ for (var i = 0; i < textDivsLength; i++) {
+ var textDiv = textDivs[i];
+ if (textDiv.dataset.isWhitespace !== undefined) {
+ continue;
+ }
+
+ var fontSize = textDiv.style.fontSize;
+ var fontFamily = textDiv.style.fontFamily;
+
+ // Only build font string and set to context if different from last.
+ if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
+ ctx.font = fontSize + ' ' + fontFamily;
+ lastFontSize = fontSize;
+ lastFontFamily = fontFamily;
+ }
+
+ var width = ctx.measureText(textDiv.textContent).width;
+ if (width > 0) {
+ textLayerFrag.appendChild(textDiv);
+ var transform;
+ if (textDiv.dataset.canvasWidth !== undefined) {
+ // Dataset values come of type string.
+ var textScale = textDiv.dataset.canvasWidth / width;
+ transform = 'scaleX(' + textScale + ')';
+ } else {
+ transform = '';
+ }
+ var rotation = textDiv.dataset.angle;
+ if (rotation) {
+ transform = 'rotate(' + rotation + 'deg) ' + transform;
+ }
+ if (transform) {
+ CustomStyle.setProp('transform' , textDiv, transform);
+ }
+ }
+ }
+ capability.resolve();
+ }
+
+ /**
+ * Text layer rendering task.
+ *
+ * @param {TextContent} textContent
+ * @param {HTMLElement} container
+ * @param {PageViewport} viewport
+ * @param {Array} textDivs
+ * @private
+ */
+ function TextLayerRenderTask(textContent, container, viewport, textDivs) {
+ this._textContent = textContent;
+ this._container = container;
+ this._viewport = viewport;
+ textDivs = textDivs || [];
+ this._textDivs = textDivs;
+ this._canceled = false;
+ this._capability = createPromiseCapability();
+ this._renderTimer = null;
+ }
+ TextLayerRenderTask.prototype = {
+ get promise() {
+ return this._capability.promise;
+ },
+
+ cancel: function TextLayer_cancel() {
+ this._canceled = true;
+ if (this._renderTimer !== null) {
+ clearTimeout(this._renderTimer);
+ this._renderTimer = null;
+ }
+ this._capability.reject('canceled');
+ },
+
+ _render: function TextLayer_render(timeout) {
+ var textItems = this._textContent.items;
+ var styles = this._textContent.styles;
+ var textDivs = this._textDivs;
+ var viewport = this._viewport;
+ for (var i = 0, len = textItems.length; i < len; i++) {
+ appendText(textDivs, viewport, textItems[i], styles);
+ }
+
+ if (!timeout) { // Render right away
+ render(this);
+ } else { // Schedule
+ var self = this;
+ this._renderTimer = setTimeout(function() {
+ render(self);
+ self._renderTimer = null;
+ }, timeout);
+ }
+ }
+ };
+
+
+ /**
+ * Starts rendering of the text layer.
+ *
+ * @param {TextLayerRenderParameters} renderParameters
+ * @returns {TextLayerRenderTask}
+ */
+ function renderTextLayer(renderParameters) {
+ var task = new TextLayerRenderTask(renderParameters.textContent,
+ renderParameters.container,
+ renderParameters.viewport,
+ renderParameters.textDivs);
+ task._render(renderParameters.timeout);
+ return task;
+ }
+
+ return renderTextLayer;
+})();
+
+exports.renderTextLayer = renderTextLayer;
+}));
+
+
+(function (root, factory) {
+ {
+ factory((root.pdfjsDisplayWebGL = {}), root.pdfjsSharedUtil,
+ root.pdfjsDisplayDOMUtils);
+ }
+}(this, function (exports, sharedUtil, displayDOMUtils) {
+
+var shadow = sharedUtil.shadow;
+var getDefaultSetting = displayDOMUtils.getDefaultSetting;
+
+var WebGLUtils = (function WebGLUtilsClosure() {
+ function loadShader(gl, code, shaderType) {
+ var shader = gl.createShader(shaderType);
+ gl.shaderSource(shader, code);
+ gl.compileShader(shader);
+ var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ if (!compiled) {
+ var errorMsg = gl.getShaderInfoLog(shader);
+ throw new Error('Error during shader compilation: ' + errorMsg);
+ }
+ return shader;
+ }
+ function createVertexShader(gl, code) {
+ return loadShader(gl, code, gl.VERTEX_SHADER);
+ }
+ function createFragmentShader(gl, code) {
+ return loadShader(gl, code, gl.FRAGMENT_SHADER);
+ }
+ function createProgram(gl, shaders) {
+ var program = gl.createProgram();
+ for (var i = 0, ii = shaders.length; i < ii; ++i) {
+ gl.attachShader(program, shaders[i]);
+ }
+ gl.linkProgram(program);
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ var errorMsg = gl.getProgramInfoLog(program);
+ throw new Error('Error during program linking: ' + errorMsg);
+ }
+ return program;
+ }
+ function createTexture(gl, image, textureId) {
+ gl.activeTexture(textureId);
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ // Set the parameters so we can render any size image.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ // Upload the image into the texture.
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ return texture;
+ }
+
+ var currentGL, currentCanvas;
+ function generateGL() {
+ if (currentGL) {
+ return;
+ }
+ currentCanvas = document.createElement('canvas');
+ currentGL = currentCanvas.getContext('webgl',
+ { premultipliedalpha: false });
+ }
+
+ var smaskVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec2 a_texCoord; \
+ \
+ uniform vec2 u_resolution; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_texCoord = a_texCoord; \
+ } ';
+
+ var smaskFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ uniform vec4 u_backdrop; \
+ uniform int u_subtype; \
+ uniform sampler2D u_image; \
+ uniform sampler2D u_mask; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec4 imageColor = texture2D(u_image, v_texCoord); \
+ vec4 maskColor = texture2D(u_mask, v_texCoord); \
+ if (u_backdrop.a > 0.0) { \
+ maskColor.rgb = maskColor.rgb * maskColor.a + \
+ u_backdrop.rgb * (1.0 - maskColor.a); \
+ } \
+ float lum; \
+ if (u_subtype == 0) { \
+ lum = maskColor.a; \
+ } else { \
+ lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
+ maskColor.b * 0.11; \
+ } \
+ imageColor.a *= lum; \
+ imageColor.rgb *= imageColor.a; \
+ gl_FragColor = imageColor; \
+ } ';
+
+ var smaskCache = null;
+
+ function initSmaskGL() {
+ var canvas, gl;
+
+ generateGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
+ cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
+
+ var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
+ var texLayerLocation = gl.getUniformLocation(program, 'u_image');
+ var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
+
+ // provide texture coordinates for the rectangle.
+ var texCoordBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(texCoordLocation);
+ gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
+
+ gl.uniform1i(texLayerLocation, 0);
+ gl.uniform1i(texMaskLocation, 1);
+
+ smaskCache = cache;
+ }
+
+ function composeSMask(layer, mask, properties) {
+ var width = layer.width, height = layer.height;
+
+ if (!smaskCache) {
+ initSmaskGL();
+ }
+ var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ if (properties.backdrop) {
+ gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
+ properties.backdrop[1], properties.backdrop[2], 1);
+ } else {
+ gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
+ }
+ gl.uniform1i(cache.subtypeLocation,
+ properties.subtype === 'Luminosity' ? 1 : 0);
+
+ // Create a textures
+ var texture = createTexture(gl, layer, gl.TEXTURE0);
+ var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
+
+
+ // Create a buffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0, 0,
+ width, 0,
+ 0, height,
+ 0, height,
+ width, 0,
+ width, height]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ // draw
+ gl.clearColor(0, 0, 0, 0);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.flush();
+
+ gl.deleteTexture(texture);
+ gl.deleteTexture(maskTexture);
+ gl.deleteBuffer(buffer);
+
+ return canvas;
+ }
+
+ var figuresVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec3 a_color; \
+ \
+ uniform vec2 u_resolution; \
+ uniform vec2 u_scale; \
+ uniform vec2 u_offset; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ vec2 position = (a_position + u_offset) * u_scale; \
+ vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_color = vec4(a_color / 255.0, 1.0); \
+ } ';
+
+ var figuresFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ gl_FragColor = v_color; \
+ } ';
+
+ var figuresCache = null;
+
+ function initFiguresGL() {
+ var canvas, gl;
+
+ generateGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
+ cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.colorLocation = gl.getAttribLocation(program, 'a_color');
+
+ figuresCache = cache;
+ }
+
+ function drawFigures(width, height, backgroundColor, figures, context) {
+ if (!figuresCache) {
+ initFiguresGL();
+ }
+ var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ // count triangle points
+ var count = 0;
+ var i, ii, rows;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ switch (figures[i].type) {
+ case 'lattice':
+ rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
+ count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
+ break;
+ case 'triangles':
+ count += figures[i].coords.length;
+ break;
+ }
+ }
+ // transfer data
+ var coords = new Float32Array(count * 2);
+ var colors = new Uint8Array(count * 3);
+ var coordsMap = context.coords, colorsMap = context.colors;
+ var pIndex = 0, cIndex = 0;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ switch (figure.type) {
+ case 'lattice':
+ var cols = figure.verticesPerRow;
+ rows = (ps.length / cols) | 0;
+ for (var row = 1; row < rows; row++) {
+ var offset = row * cols + 1;
+ for (var col = 1; col < cols; col++, offset++) {
+ coords[pIndex] = coordsMap[ps[offset - cols - 1]];
+ coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
+ coords[pIndex + 2] = coordsMap[ps[offset - cols]];
+ coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
+ coords[pIndex + 4] = coordsMap[ps[offset - 1]];
+ coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
+ colors[cIndex] = colorsMap[cs[offset - cols - 1]];
+ colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
+ colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
+ colors[cIndex + 3] = colorsMap[cs[offset - cols]];
+ colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
+ colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
+ colors[cIndex + 6] = colorsMap[cs[offset - 1]];
+ colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
+ colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
+
+ coords[pIndex + 6] = coords[pIndex + 2];
+ coords[pIndex + 7] = coords[pIndex + 3];
+ coords[pIndex + 8] = coords[pIndex + 4];
+ coords[pIndex + 9] = coords[pIndex + 5];
+ coords[pIndex + 10] = coordsMap[ps[offset]];
+ coords[pIndex + 11] = coordsMap[ps[offset] + 1];
+ colors[cIndex + 9] = colors[cIndex + 3];
+ colors[cIndex + 10] = colors[cIndex + 4];
+ colors[cIndex + 11] = colors[cIndex + 5];
+ colors[cIndex + 12] = colors[cIndex + 6];
+ colors[cIndex + 13] = colors[cIndex + 7];
+ colors[cIndex + 14] = colors[cIndex + 8];
+ colors[cIndex + 15] = colorsMap[cs[offset]];
+ colors[cIndex + 16] = colorsMap[cs[offset] + 1];
+ colors[cIndex + 17] = colorsMap[cs[offset] + 2];
+ pIndex += 12;
+ cIndex += 18;
+ }
+ }
+ break;
+ case 'triangles':
+ for (var j = 0, jj = ps.length; j < jj; j++) {
+ coords[pIndex] = coordsMap[ps[j]];
+ coords[pIndex + 1] = coordsMap[ps[j] + 1];
+ colors[cIndex] = colorsMap[cs[j]];
+ colors[cIndex + 1] = colorsMap[cs[j] + 1];
+ colors[cIndex + 2] = colorsMap[cs[j] + 2];
+ pIndex += 2;
+ cIndex += 3;
+ }
+ break;
+ }
+ }
+
+ // draw
+ if (backgroundColor) {
+ gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
+ backgroundColor[2] / 255, 1.0);
+ } else {
+ gl.clearColor(0, 0, 0, 0);
+ }
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var coordsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ var colorsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.colorLocation);
+ gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
+ 0, 0);
+
+ gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
+ gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
+
+ gl.drawArrays(gl.TRIANGLES, 0, count);
+
+ gl.flush();
+
+ gl.deleteBuffer(coordsBuffer);
+ gl.deleteBuffer(colorsBuffer);
+
+ return canvas;
+ }
+
+ function cleanup() {
+ if (smaskCache && smaskCache.canvas) {
+ smaskCache.canvas.width = 0;
+ smaskCache.canvas.height = 0;
+ }
+ if (figuresCache && figuresCache.canvas) {
+ figuresCache.canvas.width = 0;
+ figuresCache.canvas.height = 0;
+ }
+ smaskCache = null;
+ figuresCache = null;
+ }
+
+ return {
+ get isEnabled() {
+ if (getDefaultSetting('disableWebGL')) {
+ return false;
+ }
+ var enabled = false;
+ try {
+ generateGL();
+ enabled = !!currentGL;
+ } catch (e) { }
+ return shadow(this, 'isEnabled', enabled);
+ },
+ composeSMask: composeSMask,
+ drawFigures: drawFigures,
+ clear: cleanup
+ };
+})();
+
+exports.WebGLUtils = WebGLUtils;
+}));
+
+
(function (root, factory) {
{
factory((root.pdfjsDisplayPatternHelper = {}), root.pdfjsSharedUtil,
@@ -3671,240 +3894,6 @@ exports.TilingPattern = TilingPattern;
}));
-(function (root, factory) {
- {
- factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil,
- root.pdfjsDisplayDOMUtils, root.pdfjsDisplayGlobal);
- }
-}(this, function (exports, sharedUtil, displayDOMUtils, displayGlobal) {
-
-var Util = sharedUtil.Util;
-var createPromiseCapability = sharedUtil.createPromiseCapability;
-var CustomStyle = displayDOMUtils.CustomStyle;
-var PDFJS = displayGlobal.PDFJS;
-
-/**
- * Text layer render parameters.
- *
- * @typedef {Object} TextLayerRenderParameters
- * @property {TextContent} textContent - Text content to render (the object is
- * returned by the page's getTextContent() method).
- * @property {HTMLElement} container - HTML element that will contain text runs.
- * @property {PDFJS.PageViewport} viewport - The target viewport to properly
- * layout the text runs.
- * @property {Array} textDivs - (optional) HTML elements that are correspond
- * the text items of the textContent input. This is output and shall be
- * initially be set to empty array.
- * @property {number} timeout - (optional) Delay in milliseconds before
- * rendering of the text runs occurs.
- */
-var renderTextLayer = (function renderTextLayerClosure() {
- var MAX_TEXT_DIVS_TO_RENDER = 100000;
-
- var NonWhitespaceRegexp = /\S/;
-
- function isAllWhitespace(str) {
- return !NonWhitespaceRegexp.test(str);
- }
-
- function appendText(textDivs, viewport, geom, styles) {
- var style = styles[geom.fontName];
- var textDiv = document.createElement('div');
- textDivs.push(textDiv);
- if (isAllWhitespace(geom.str)) {
- textDiv.dataset.isWhitespace = true;
- return;
- }
- var tx = Util.transform(viewport.transform, geom.transform);
- var angle = Math.atan2(tx[1], tx[0]);
- if (style.vertical) {
- angle += Math.PI / 2;
- }
- var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
- var fontAscent = fontHeight;
- if (style.ascent) {
- fontAscent = style.ascent * fontAscent;
- } else if (style.descent) {
- fontAscent = (1 + style.descent) * fontAscent;
- }
-
- var left;
- var top;
- if (angle === 0) {
- left = tx[4];
- top = tx[5] - fontAscent;
- } else {
- left = tx[4] + (fontAscent * Math.sin(angle));
- top = tx[5] - (fontAscent * Math.cos(angle));
- }
- textDiv.style.left = left + 'px';
- textDiv.style.top = top + 'px';
- textDiv.style.fontSize = fontHeight + 'px';
- textDiv.style.fontFamily = style.fontFamily;
-
- textDiv.textContent = geom.str;
- // |fontName| is only used by the Font Inspector. This test will succeed
- // when e.g. the Font Inspector is off but the Stepper is on, but it's
- // not worth the effort to do a more accurate test.
- if (PDFJS.pdfBug) {
- textDiv.dataset.fontName = geom.fontName;
- }
- // Storing into dataset will convert number into string.
- if (angle !== 0) {
- textDiv.dataset.angle = angle * (180 / Math.PI);
- }
- // We don't bother scaling single-char text divs, because it has very
- // little effect on text highlighting. This makes scrolling on docs with
- // lots of such divs a lot faster.
- if (geom.str.length > 1) {
- if (style.vertical) {
- textDiv.dataset.canvasWidth = geom.height * viewport.scale;
- } else {
- textDiv.dataset.canvasWidth = geom.width * viewport.scale;
- }
- }
- }
-
- function render(task) {
- if (task._canceled) {
- return;
- }
- var textLayerFrag = task._container;
- var textDivs = task._textDivs;
- var capability = task._capability;
- var textDivsLength = textDivs.length;
-
- // No point in rendering many divs as it would make the browser
- // unusable even after the divs are rendered.
- if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
- capability.resolve();
- return;
- }
-
- var canvas = document.createElement('canvas');
- canvas.mozOpaque = true;
- var ctx = canvas.getContext('2d', {alpha: false});
-
- var lastFontSize;
- var lastFontFamily;
- for (var i = 0; i < textDivsLength; i++) {
- var textDiv = textDivs[i];
- if (textDiv.dataset.isWhitespace !== undefined) {
- continue;
- }
-
- var fontSize = textDiv.style.fontSize;
- var fontFamily = textDiv.style.fontFamily;
-
- // Only build font string and set to context if different from last.
- if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
- ctx.font = fontSize + ' ' + fontFamily;
- lastFontSize = fontSize;
- lastFontFamily = fontFamily;
- }
-
- var width = ctx.measureText(textDiv.textContent).width;
- if (width > 0) {
- textLayerFrag.appendChild(textDiv);
- var transform;
- if (textDiv.dataset.canvasWidth !== undefined) {
- // Dataset values come of type string.
- var textScale = textDiv.dataset.canvasWidth / width;
- transform = 'scaleX(' + textScale + ')';
- } else {
- transform = '';
- }
- var rotation = textDiv.dataset.angle;
- if (rotation) {
- transform = 'rotate(' + rotation + 'deg) ' + transform;
- }
- if (transform) {
- CustomStyle.setProp('transform' , textDiv, transform);
- }
- }
- }
- capability.resolve();
- }
-
- /**
- * Text layer rendering task.
- *
- * @param {TextContent} textContent
- * @param {HTMLElement} container
- * @param {PDFJS.PageViewport} viewport
- * @param {Array} textDivs
- * @private
- */
- function TextLayerRenderTask(textContent, container, viewport, textDivs) {
- this._textContent = textContent;
- this._container = container;
- this._viewport = viewport;
- textDivs = textDivs || [];
- this._textDivs = textDivs;
- this._canceled = false;
- this._capability = createPromiseCapability();
- this._renderTimer = null;
- }
- TextLayerRenderTask.prototype = {
- get promise() {
- return this._capability.promise;
- },
-
- cancel: function TextLayer_cancel() {
- this._canceled = true;
- if (this._renderTimer !== null) {
- clearTimeout(this._renderTimer);
- this._renderTimer = null;
- }
- this._capability.reject('canceled');
- },
-
- _render: function TextLayer_render(timeout) {
- var textItems = this._textContent.items;
- var styles = this._textContent.styles;
- var textDivs = this._textDivs;
- var viewport = this._viewport;
- for (var i = 0, len = textItems.length; i < len; i++) {
- appendText(textDivs, viewport, textItems[i], styles);
- }
-
- if (!timeout) { // Render right away
- render(this);
- } else { // Schedule
- var self = this;
- this._renderTimer = setTimeout(function() {
- render(self);
- self._renderTimer = null;
- }, timeout);
- }
- }
- };
-
-
- /**
- * Starts rendering of the text layer.
- *
- * @param {TextLayerRenderParameters} renderParameters
- * @returns {TextLayerRenderTask}
- */
- function renderTextLayer(renderParameters) {
- var task = new TextLayerRenderTask(renderParameters.textContent,
- renderParameters.container,
- renderParameters.viewport,
- renderParameters.textDivs);
- task._render(renderParameters.timeout);
- return task;
- }
-
- return renderTextLayer;
-})();
-
-PDFJS.renderTextLayer = renderTextLayer;
-
-exports.renderTextLayer = renderTextLayer;
-}));
-
-
(function (root, factory) {
{
factory((root.pdfjsDisplayCanvas = {}), root.pdfjsSharedUtil,
@@ -3925,12 +3914,14 @@ var assert = sharedUtil.assert;
var info = sharedUtil.info;
var isNum = sharedUtil.isNum;
var isArray = sharedUtil.isArray;
+var isLittleEndian = sharedUtil.isLittleEndian;
var error = sharedUtil.error;
var shadow = sharedUtil.shadow;
var warn = sharedUtil.warn;
var TilingPattern = displayPatternHelper.TilingPattern;
var getShadingPatternFromIR = displayPatternHelper.getShadingPatternFromIR;
var WebGLUtils = displayWebGL.WebGLUtils;
+var hasCanvasTypedArrays = displayDOMUtils.hasCanvasTypedArrays;
//