--- a/browser/components/customizableui/src/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/src/CustomizableWidgets.jsm
@@ -279,57 +279,58 @@ const CustomizableWidgets = [{
if (typeof win.OpenBrowserWindow == "function") {
win.OpenBrowserWindow({private: true});
}
}
}
}, {
id: "save-page-button",
shortcutId: "key_savePage",
- tooltiptext: "save-page-button.tooltiptext2",
+ tooltiptext: "save-page-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand: function(aEvent) {
let win = aEvent.target &&
aEvent.target.ownerDocument &&
aEvent.target.ownerDocument.defaultView;
if (win && typeof win.saveDocument == "function") {
win.saveDocument(win.content.document);
}
}
}, {
id: "find-button",
shortcutId: "key_find",
- tooltiptext: "find-button.tooltiptext2",
+ tooltiptext: "find-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand: function(aEvent) {
let win = aEvent.target &&
aEvent.target.ownerDocument &&
aEvent.target.ownerDocument.defaultView;
if (win && win.gFindBar) {
win.gFindBar.onFindCommand();
}
}
}, {
id: "open-file-button",
shortcutId: "openFileKb",
- tooltiptext: "open-file-button.tooltiptext2",
+ tooltiptext: "open-file-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand: function(aEvent) {
let win = aEvent.target
&& aEvent.target.ownerDocument
&& aEvent.target.ownerDocument.defaultView;
if (win && typeof win.BrowserOpenFileWindow == "function") {
win.BrowserOpenFileWindow();
}
}
}, {
id: "developer-button",
type: "view",
viewId: "PanelUI-developer",
shortcutId: "key_devToolboxMenuItem",
+ tooltiptext: "developer-button.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onViewShowing: function(aEvent) {
// Populate the subview with whatever menuitems are in the developer
// menu. We skip menu elements, because the menu panel has no way
// of dealing with those right now.
let doc = aEvent.target.ownerDocument;
let win = doc.defaultView;
@@ -345,16 +346,17 @@ const CustomizableWidgets = [{
onViewHiding: function(aEvent) {
let doc = aEvent.target.ownerDocument;
clearSubview(doc.getElementById("PanelUI-developerItems"));
}
}, {
id: "sidebar-button",
type: "view",
viewId: "PanelUI-sidebar",
+ tooltiptext: "sidebar-button.tooltiptext2",
onViewShowing: function(aEvent) {
// Largely duplicated from the developer-button above with a couple minor
// alterations.
// Populate the subview with whatever menuitems are in the
// sidebar menu. We skip menu elements, because the menu panel has no way
// of dealing with those right now.
let doc = aEvent.target.ownerDocument;
let win = doc.defaultView;
@@ -372,17 +374,17 @@ const CustomizableWidgets = [{
},
onViewHiding: function(aEvent) {
let doc = aEvent.target.ownerDocument;
clearSubview(doc.getElementById("PanelUI-sidebarItems"));
}
}, {
id: "add-ons-button",
shortcutId: "key_openAddons",
- tooltiptext: "add-ons-button.tooltiptext2",
+ tooltiptext: "add-ons-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand: function(aEvent) {
let win = aEvent.target &&
aEvent.target.ownerDocument &&
aEvent.target.ownerDocument.defaultView;
if (win && typeof win.BrowserOpenAddonsMgr == "function") {
win.BrowserOpenAddonsMgr();
}
@@ -407,16 +409,17 @@ const CustomizableWidgets = [{
aEvent.target.ownerDocument.defaultView;
if (win && typeof win.openPreferences == "function") {
win.openPreferences();
}
}
}, {
id: "zoom-controls",
type: "custom",
+ tooltiptext: "zoom-controls.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onBuild: function(aDocument) {
const kPanelId = "PanelUI-popup";
let areaType = CustomizableUI.getAreaType(this.currentArea);
let inPanel = areaType == CustomizableUI.TYPE_MENU_PANEL;
let inToolbar = areaType == CustomizableUI.TYPE_TOOLBAR;
let buttons = [{
@@ -579,16 +582,17 @@ const CustomizableWidgets = [{
};
CustomizableUI.addListener(listener);
return node;
}
}, {
id: "edit-controls",
type: "custom",
+ tooltiptext: "edit-controls.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onBuild: function(aDocument) {
let buttons = [{
id: "cut-button",
command: "cmd_cut",
label: true,
tooltiptext: "tooltiptext2",
shortcutId: "key_cut",
@@ -670,16 +674,17 @@ const CustomizableWidgets = [{
return node;
}
},
{
id: "feed-button",
type: "view",
viewId: "PanelUI-feeds",
+ tooltiptext: "feed-button.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onClick: function(aEvent) {
let win = aEvent.target.ownerDocument.defaultView;
let feeds = win.gBrowser.selectedBrowser.feeds;
// Here, we only care about the case where we have exactly 1 feed and the
// user clicked...
let isClick = (aEvent.button == 0 || aEvent.button == 1);
@@ -872,17 +877,17 @@ const CustomizableWidgets = [{
};
CustomizableUI.addListener(listener);
if (!this.charsetInfo) {
this.charsetInfo = CharsetMenu.getData();
}
}
}, {
id: "email-link-button",
- tooltiptext: "email-link-button.tooltiptext2",
+ tooltiptext: "email-link-button.tooltiptext3",
onCommand: function(aEvent) {
let win = aEvent.view;
win.MailIntegration.sendLinkForWindow(win.content);
}
}];
#ifdef XP_WIN
#ifdef MOZ_METRO
--- a/browser/devtools/app-manager/app-projects.js
+++ b/browser/devtools/app-manager/app-projects.js
@@ -1,11 +1,11 @@
const {Cc,Ci,Cu} = require("chrome");
const ObservableObject = require("devtools/shared/observable-object");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
const {generateUUID} = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
/**
* IndexedDB wrapper that just save project objects
*
* The only constraint is that project objects have to have
--- a/browser/devtools/app-manager/app-validator.js
+++ b/browser/devtools/app-manager/app-validator.js
@@ -1,15 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let {Ci,Cu,CC} = require("chrome");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
let XMLHttpRequest = CC("@mozilla.org/xmlextras/xmlhttprequest;1");
let strings = Services.strings.createBundle("chrome://browser/locale/devtools/app-manager.properties");
function AppValidator(project) {
this.project = project;
--- a/browser/devtools/app-manager/content/device.js
+++ b/browser/devtools/app-manager/content/device.js
@@ -12,17 +12,17 @@ const {require} = devtools;
const {ConnectionManager, Connection}
= require("devtools/client/connection-manager");
const {getDeviceFront} = require("devtools/server/actors/device");
const {getTargetForApp, launchApp, closeApp}
= require("devtools/app-actor-front");
const DeviceStore = require("devtools/app-manager/device-store");
const WebappsStore = require("devtools/app-manager/webapps-store");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const DEFAULT_APP_ICON = "chrome://browser/skin/devtools/app-manager/default-app-icon.png";
window.addEventListener("message", function(event) {
try {
let message = JSON.parse(event.data);
if (message.name == "connection") {
let cid = parseInt(message.cid);
for (let c of ConnectionManager.connections) {
--- a/browser/devtools/app-manager/content/index.js
+++ b/browser/devtools/app-manager/content/index.js
@@ -2,17 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cu = Components.utils;
Cu.import("resource:///modules/devtools/gDevTools.jsm");
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {require} = devtools;
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const prefs = require('sdk/preferences/service');
let UI = {
_toolboxTabCursor: 0,
_handledTargets: new Map(),
connection: null,
--- a/browser/devtools/app-manager/content/projects.js
+++ b/browser/devtools/app-manager/content/projects.js
@@ -13,17 +13,17 @@ const {ConnectionManager, Connection} =
const {AppProjects} = require("devtools/app-manager/app-projects");
const {AppValidator} = require("devtools/app-manager/app-validator");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
const {installHosted, installPackaged, getTargetForApp,
reloadApp, launchApp, closeApp} = require("devtools/app-actor-front");
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
window.addEventListener("message", function(event) {
try {
let json = JSON.parse(event.data);
if (json.name == "connection") {
let cid = parseInt(json.cid);
--- a/browser/devtools/app-manager/test/head.js
+++ b/browser/devtools/app-manager/test/head.js
@@ -1,16 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
const {Promise: promise} =
- Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+ Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
const {devtools} =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {require} = devtools;
const {AppProjects} = require("devtools/app-manager/app-projects");
const APP_MANAGER_URL = "about:app-manager";
const TEST_BASE =
--- a/browser/devtools/app-manager/webapps-store.js
+++ b/browser/devtools/app-manager/webapps-store.js
@@ -1,14 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const ObservableObject = require("devtools/shared/observable-object");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const {Connection} = require("devtools/client/connection-manager");
const {Cu} = require("chrome");
const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
const _knownWebappsStores = new WeakMap();
let WebappsStore;
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -93,17 +93,17 @@ Cu.import("resource://gre/modules/devtoo
Cu.import("resource:///modules/devtools/SimpleListWidget.jsm");
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/VariablesView.jsm");
Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const Editor = require("devtools/sourceeditor/editor");
const DebuggerEditor = require("devtools/sourceeditor/debugger.js");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
const FastListWidget = require("devtools/shared/widgets/FastListWidget");
XPCOMUtils.defineLazyModuleGetter(this, "Parser",
"resource:///modules/devtools/Parser.jsm");
--- a/browser/devtools/eyedropper/test/head.js
+++ b/browser/devtools/eyedropper/test/head.js
@@ -1,15 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/eyedropper/test/";
const TEST_HOST = 'mochi.test:8888';
-const promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
+const promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js").Promise;
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
const { Eyedropper } = require("devtools/eyedropper/eyedropper");
waitForExplicitFinish();
function cleanup()
{
--- a/browser/devtools/inspector/breadcrumbs.js
+++ b/browser/devtools/inspector/breadcrumbs.js
@@ -11,17 +11,17 @@ const ENSURE_SELECTION_VISIBLE_DELAY = 5
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
const MAX_LABEL_LENGTH = 40;
-let promise = require("sdk/core/promise");
+let promise = require("devtools/toolkit/deprecated-sync-thenables");
const LOW_PRIORITY_ELEMENTS = {
"HEAD": true,
"BASE": true,
"BASEFONT": true,
"ISINDEX": true,
"LINK": true,
"META": true,
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -3,17 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cc, Ci, Cu, Cr} = require("chrome");
Cu.import("resource://gre/modules/Services.jsm");
-let promise = require("sdk/core/promise");
+let promise = require("devtools/toolkit/deprecated-sync-thenables");
let EventEmitter = require("devtools/toolkit/event-emitter");
let {CssLogic} = require("devtools/styleinspector/css-logic");
loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
--- a/browser/devtools/inspector/selector-search.js
+++ b/browser/devtools/inspector/selector-search.js
@@ -1,15 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
// Maximum number of selector suggestions shown in the panel.
const MAX_SUGGESTIONS = 15;
/**
* Converts any input box on a page to a CSS selector search and suggestion box.
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -15,17 +15,17 @@ const COLLAPSE_DATA_URL_REGEX = /^data.+
const COLLAPSE_DATA_URL_LENGTH = 60;
const CONTAINER_FLASHING_DURATION = 500;
const NEW_SELECTION_HIGHLIGHTER_TIMER = 1000;
const {UndoStack} = require("devtools/shared/undo");
const {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
const {HTMLEditor} = require("devtools/markupview/html-editor");
-const promise = require("sdk/core/promise");
+const promise = require("devtools/toolkit/deprecated-sync-thenables");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
const EventEmitter = require("devtools/toolkit/event-emitter");
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
Cu.import("resource://gre/modules/devtools/Templater.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
--- a/browser/devtools/markupview/test/head.js
+++ b/browser/devtools/markupview/test/head.js
@@ -1,17 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cu = Components.utils;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let TargetFactory = devtools.TargetFactory;
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
-let promise = devtools.require("sdk/core/promise");
+let promise = devtools.require("devtools/toolkit/deprecated-sync-thenables");
let {getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
// All test are asynchronous
waitForExplicitFinish();
//Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -389,16 +389,17 @@ RequestsMenuView.prototype = Heritage.ex
$("#headers-summary-resend").hidden = true;
}
if (NetMonitorController.supportsPerfStats) {
$("#request-menu-context-perf").addEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-perf-notice-button").addEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-network-summary-button").addEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-network-summary-label").addEventListener("click", this._onContextPerfCommand, false);
+ $("#network-statistics-back-button").addEventListener("command", this._onContextPerfCommand, false);
} else {
$("#notice-perf-message").hidden = true;
$("#request-menu-context-perf").hidden = true;
$("#requests-menu-network-summary-button").hidden = true;
$("#requests-menu-network-summary-label").hidden = true;
}
},
@@ -423,16 +424,17 @@ RequestsMenuView.prototype = Heritage.ex
$("#request-menu-context-copy-url").removeEventListener("command", this._onContextCopyUrlCommand, false);
$("#request-menu-context-copy-image-as-data-uri").removeEventListener("command", this._onContextCopyImageAsDataUriCommand, false);
$("#request-menu-context-resend").removeEventListener("command", this._onContextResendCommand, false);
$("#request-menu-context-perf").removeEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-perf-notice-button").removeEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-network-summary-button").removeEventListener("command", this._onContextPerfCommand, false);
$("#requests-menu-network-summary-label").removeEventListener("click", this._onContextPerfCommand, false);
+ $("#network-statistics-back-button").removeEventListener("command", this._onContextPerfCommand, false);
$("#custom-request-send-button").removeEventListener("click", this.sendCustomRequestEvent, false);
$("#custom-request-close-button").removeEventListener("click", this.closeCustomRequestEvent, false);
$("#headers-summary-resend").removeEventListener("click", this.cloneSelectedRequestEvent, false);
},
/**
* Resets this container (removes all the networking information).
--- a/browser/devtools/netmonitor/netmonitor.xul
+++ b/browser/devtools/netmonitor/netmonitor.xul
@@ -511,17 +511,16 @@
</vbox>
<box id="network-statistics-view">
<toolbar id="network-statistics-toolbar"
class="devtools-toolbar">
<button id="network-statistics-back-button"
class="devtools-toolbarbutton"
- onclick="NetMonitorView.toggleFrontendMode()"
label="&netmonitorUI.backButton;"/>
</toolbar>
<box id="network-statistics-charts"
class="devtools-responsive-container"
flex="1">
<vbox id="primed-cache-chart" pack="center" flex="1"/>
<splitter id="network-statistics-view-splitter"
class="devtools-side-splitter"/>
--- a/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_paintflashing.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_paintflashing.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_button_responsive.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_responsive.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_responsive.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_scratchpad.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_scratchpad.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
let numScratchpads = 0;
function init() {
--- a/browser/devtools/shared/test/browser_telemetry_button_tilt.js
+++ b/browser/devtools/shared/test/browser_telemetry_button_tilt.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_tilt.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_sidebar.js
+++ b/browser/devtools/shared/test/browser_telemetry_sidebar.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_sidebar.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_inspector.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_inspector.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsdebugger.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsdebugger.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_jsprofiler.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_jsprofiler.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_netmonitor.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_netmonitor.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_options.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_options.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_styleeditor.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
+++ b/browser/devtools/shared/test/browser_telemetry_toolboxtabs_webconsole.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_styleeditor_webconsole.js</p>";
// Because we need to gather stats for the period of time that a tool has been
// opened we make use of setTimeout() to create tool active times.
const TOOL_DELAY = 200;
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
--- a/browser/devtools/shared/test/browser_templater_basic.js
+++ b/browser/devtools/shared/test/browser_templater_basic.js
@@ -4,17 +4,17 @@
// Tests that the DOM Template engine works properly
/*
* These tests run both in Mozilla/Mochitest and plain browsers (as does
* domtemplate)
* We should endevour to keep the source in sync.
*/
-var promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+var promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
var template = Cu.import("resource://gre/modules/devtools/Templater.jsm", {}).template;
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html";
function test() {
addTab(TEST_URI, function() {
info("Starting DOM Templater Tests");
runTest(0);
--- a/browser/devtools/webconsole/console-output.js
+++ b/browser/devtools/webconsole/console-output.js
@@ -865,17 +865,17 @@ Messages.Simple.prototype = Heritage.ext
/**
* Render the message body DOM element.
* @private
* @return Element
*/
_renderBody: function()
{
let body = this.document.createElementNS(XHTML_NS, "span");
- body.className = "body devtools-monospace";
+ body.className = "message-body-wrapper message-body devtools-monospace";
let anchor, container = body;
if (this._link || this._linkCallback) {
container = anchor = this.document.createElementNS(XHTML_NS, "a");
anchor.href = this._link || "#";
anchor.draggable = false;
this._addLinkCallback(anchor, this._linkCallback);
body.appendChild(anchor);
@@ -1218,70 +1218,158 @@ Messages.ConsoleGeneric = function(packe
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
private: packet.private,
filterDuplicates: true,
location: {
url: packet.filename,
line: packet.lineNumber,
},
};
+
switch (packet.level) {
case "count": {
let counter = packet.counter, label = counter.label;
if (!label) {
label = l10n.getStr("noCounterLabel");
}
Messages.Extended.call(this, [label+ ": " + counter.count], options);
break;
}
default:
Messages.Extended.call(this, packet.arguments, options);
break;
}
this._repeatID.consoleApiLevel = packet.level;
this._repeatID.styles = packet.styles;
+ this._stacktrace = this._repeatID.stacktrace = packet.stacktrace;
this._styles = packet.styles || [];
+
+ this._onClickCollapsible = this._onClickCollapsible.bind(this);
};
Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
{
_styles: null,
+ _stacktrace: null,
+
+ /**
+ * Tells if the message can be expanded/collapsed.
+ * @type boolean
+ */
+ collapsible: false,
+
+ /**
+ * Getter that tells if this message is collapsed - no details are shown.
+ * @type boolean
+ */
+ get collapsed() {
+ return this.collapsible && this.element && !this.element.hasAttribute("open");
+ },
_renderBodyPieceSeparator: function()
{
return this.document.createTextNode(" ");
},
render: function()
{
+ let msg = this.document.createElementNS(XHTML_NS, "span");
+ msg.className = "message-body devtools-monospace";
+
+ this._renderBodyPieces(msg);
+
+ let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
+ let location = Messages.Simple.prototype._renderLocation.call(this);
+ if (location) {
+ location.target = "jsdebugger";
+ }
+
+ let stack = null;
+ let twisty = null;
+ if (this._stacktrace && this._stacktrace.length > 0) {
+ stack = new Widgets.Stacktrace(this, this._stacktrace).render().element;
+
+ twisty = this.document.createElementNS(XHTML_NS, "a");
+ twisty.className = "theme-twisty";
+ twisty.href = "#";
+ twisty.title = l10n.getStr("messageToggleDetails");
+ twisty.addEventListener("click", this._onClickCollapsible);
+ }
+
+ let flex = this.document.createElementNS(XHTML_NS, "span");
+ flex.className = "message-flex-body";
+
+ if (twisty) {
+ flex.appendChild(twisty);
+ }
+
+ flex.appendChild(msg);
+
+ if (repeatNode) {
+ flex.appendChild(repeatNode);
+ }
+ if (location) {
+ flex.appendChild(location);
+ }
+
+ let result = this.document.createDocumentFragment();
+ result.appendChild(flex);
+
+ if (stack) {
+ result.appendChild(this.document.createTextNode("\n"));
+ result.appendChild(stack);
+ }
+
+ this._message = result;
+ this._stacktrace = null;
+
+ Messages.Simple.prototype.render.call(this);
+
+ if (stack) {
+ this.collapsible = true;
+ this.element.setAttribute("collapsible", true);
+
+ let icon = this.element.querySelector(".icon");
+ icon.addEventListener("click", this._onClickCollapsible);
+ }
+
+ return this;
+ },
+
+ _renderBody: function()
+ {
+ let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
+ body.classList.remove("devtools-monospace", "message-body");
+ return body;
+ },
+
+ _renderBodyPieces: function(container)
+ {
let lastStyle = null;
- let result = this.document.createDocumentFragment();
for (let i = 0; i < this._messagePieces.length; i++) {
let separator = i > 0 ? this._renderBodyPieceSeparator() : null;
if (separator) {
- result.appendChild(separator);
+ container.appendChild(separator);
}
let piece = this._messagePieces[i];
let style = this._styles[i];
// No long string support.
if (style && typeof style == "string" ) {
lastStyle = this.cleanupStyle(style);
}
- result.appendChild(this._renderBodyPiece(piece, lastStyle));
+ container.appendChild(this._renderBodyPiece(piece, lastStyle));
}
- this._message = result;
this._messagePieces = null;
this._styles = null;
- return Messages.Simple.prototype.render.call(this);
},
_renderBodyPiece: function(piece, style)
{
let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece);
let result = elem;
if (style) {
@@ -1293,16 +1381,51 @@ Messages.ConsoleGeneric.prototype = Heri
span.appendChild(elem);
result = span;
}
}
return result;
},
+ // no-op for the message location and .repeats elements.
+ // |this.render()| handles customized message output.
+ _renderLocation: function() { },
+ _renderRepeatNode: function() { },
+
+ /**
+ * Expand/collapse message details.
+ */
+ toggleDetails: function()
+ {
+ let twisty = this.element.querySelector(".theme-twisty");
+ if (this.element.hasAttribute("open")) {
+ this.element.removeAttribute("open");
+ twisty.removeAttribute("open");
+ } else {
+ this.element.setAttribute("open", true);
+ twisty.setAttribute("open", true);
+ }
+ },
+
+ /**
+ * The click event handler for the message expander arrow element. This method
+ * toggles the display of message details.
+ *
+ * @private
+ * @param nsIDOMEvent ev
+ * The DOM event object.
+ * @see this.toggleDetails()
+ */
+ _onClickCollapsible: function(ev)
+ {
+ ev.preventDefault();
+ this.toggleDetails();
+ },
+
/**
* Given a style attribute value, return a cleaned up version of the string
* such that:
*
* - no external URL is allowed to load. See RE_CLEANUP_STYLES.
* - only some of the properties are allowed, based on a whitelist. See
* RE_ALLOWED_STYLES.
*
@@ -1350,17 +1473,17 @@ Messages.ConsoleGeneric.prototype = Heri
* @constructor
* @extends Messages.Simple
* @param object packet
* The Console API call packet received from the server.
*/
Messages.ConsoleTrace = function(packet)
{
let options = {
- className: "consoleTrace cm-s-mozilla",
+ className: "cm-s-mozilla",
timestamp: packet.timeStamp,
category: "webdev",
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
private: packet.private,
filterDuplicates: true,
location: {
url: packet.filename,
line: packet.lineNumber,
@@ -1407,16 +1530,23 @@ Messages.ConsoleTrace.prototype = Herita
}
}
}
this._arguments = null;
return result;
},
+ render: function()
+ {
+ Messages.Simple.prototype.render.apply(this, arguments);
+ this.element.setAttribute("open", true);
+ return this;
+ },
+
/**
* Render the stack frames.
*
* @private
* @return DOMElement
*/
_renderStack: function()
{
@@ -1424,31 +1554,32 @@ Messages.ConsoleTrace.prototype = Herita
cmvar.className = "cm-variable";
cmvar.textContent = "console";
let cmprop = this.document.createElementNS(XHTML_NS, "span");
cmprop.className = "cm-property";
cmprop.textContent = "trace";
let title = this.document.createElementNS(XHTML_NS, "span");
- title.className = "title devtools-monospace";
+ title.className = "message-body devtools-monospace";
title.appendChild(cmvar);
title.appendChild(this.document.createTextNode("."));
title.appendChild(cmprop);
title.appendChild(this.document.createTextNode("():"));
let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
let location = Messages.Simple.prototype._renderLocation.call(this);
if (location) {
location.target = "jsdebugger";
}
let widget = new Widgets.Stacktrace(this, this._stacktrace).render();
- let body = this.document.createElementNS(XHTML_NS, "div");
+ let body = this.document.createElementNS(XHTML_NS, "span");
+ body.className = "message-flex-body";
body.appendChild(title);
if (repeatNode) {
body.appendChild(repeatNode);
}
if (location) {
body.appendChild(location);
}
body.appendChild(this.document.createTextNode("\n"));
@@ -1458,17 +1589,17 @@ Messages.ConsoleTrace.prototype = Herita
frag.appendChild(widget.element);
return frag;
},
_renderBody: function()
{
let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
- body.classList.remove("devtools-monospace");
+ body.classList.remove("devtools-monospace", "message-body");
return body;
},
// no-op for the message location and .repeats elements.
// |this._renderStack| handles customized message output.
_renderLocation: function() { },
_renderRepeatNode: function() { },
}); // Messages.ConsoleTrace.prototype
@@ -2717,17 +2848,16 @@ Widgets.Stacktrace.prototype = Heritage.
let elem = this.document.createElementNS(XHTML_NS, "li");
elem.appendChild(fn);
elem.appendChild(location);
elem.appendChild(this.document.createTextNode("\n"));
return elem;
},
-
}); // Widgets.Stacktrace.prototype
function gSequenceId()
{
return gSequenceId.n++;
}
gSequenceId.n = 0;
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -108,16 +108,17 @@ support-files =
test-bug_923281_console_log_filter.html
test-bug_923281_test1.js
test-bug_923281_test2.js
test-bug_939783_console_trace_duplicates.html
test-bug-952277-highlight-nodes-in-vview.html
test-bug-609872-cd-iframe-parent.html
test-bug-609872-cd-iframe-child.html
test-bug-989025-iframe-parent.html
+ test-console-api-stackframe.html
[browser_bug664688_sandbox_update_after_navigation.js]
[browser_bug_638949_copy_link_location.js]
[browser_bug_862916_console_dir_and_filter_off.js]
[browser_bug_865288_repeat_different_objects.js]
[browser_bug_865871_variables_view_close_on_esc_key.js]
[browser_bug_869003_inspect_cross_domain_object.js]
[browser_bug_871156_ctrlw_close_tab.js]
@@ -278,8 +279,9 @@ run-if = os == "mac"
[browser_webconsole_output_dom_elements_04.js]
[browser_webconsole_output_events.js]
[browser_console_variables_view_highlighter.js]
[browser_webconsole_start_netmon_first.js]
[browser_webconsole_console_trace_duplicates.js]
[browser_webconsole_cd_iframe.js]
[browser_webconsole_autocomplete_crossdomain_iframe.js]
[browser_webconsole_console_custom_styles.js]
+[browser_webconsole_console_api_stackframe.js]
--- a/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js
+++ b/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js
@@ -62,16 +62,17 @@ function onConsoleMessage(aResults) {
output.focus();
let message = [...aResults[0].matched][0];
goUpdateCommand(COMMAND_NAME);
ok(!isEnabled(), COMMAND_NAME + "is disabled");
// Test that the "Copy Link Location" menu item is hidden for non-network
// messages.
+ message.scrollIntoView();
waitForContextMenu(menu, message, () => {
let isHidden = menu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isHidden, CONTEXT_MENU_ID + " is hidden");
}, testWithNetActivity);
}
function testWithNetActivity() {
HUD.jsterm.clearOutput();
@@ -102,15 +103,16 @@ function onNetworkMessage(aResults) {
waitForClipboard((aData) => { return aData.trim() == message.url; },
() => { goDoCommand(COMMAND_NAME) },
testMenuWithNetActivity, testMenuWithNetActivity);
function testMenuWithNetActivity() {
// Test that the "Copy Link Location" menu item is visible for network-related
// messages.
+ message.scrollIntoView();
waitForContextMenu(menu, message, () => {
let isVisible = !menu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isVisible, CONTEXT_MENU_ID + " is visible");
}, finishTest);
}
}
--- a/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js
+++ b/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js
@@ -48,17 +48,17 @@ function checkMessages([result])
let m = -1;
function nextMessage()
{
let msg = msgs[++m];
if (msg) {
ok(msg, "message element #" + m);
- let clickable = msg.querySelector(".body a");
+ let clickable = msg.querySelector(".message-body a");
ok(clickable, "clickable object #" + m);
msg.scrollIntoView(false);
clickObject(clickable);
}
else {
finishTest();
}
--- a/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
+++ b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
@@ -18,17 +18,17 @@ function test()
let {tab} = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
let jsterm = hud.jsterm;
let msg = yield execute("fooObj");
ok(msg, "output message found");
let anchor = msg.querySelector("a");
- let body = msg.querySelector(".body");
+ let body = msg.querySelector(".message-body");
ok(anchor, "object anchor");
ok(body, "message body");
ok(body.textContent.contains('testProp: "testValue"'), "message text check");
msg.scrollIntoView();
executeSoon(() => {
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
});
@@ -54,17 +54,17 @@ function test()
});
yield jsterm.once("sidebar-closed");
jsterm.clearOutput();
msg = yield execute("window.location");
ok(msg, "output message found");
- body = msg.querySelector(".body");
+ body = msg.querySelector(".message-body");
ok(body, "message body");
anchor = msg.querySelector("a");
ok(anchor, "object anchor");
ok(body.textContent.contains("Location \u2192 http://example.com/browser/"),
"message text check");
msg.scrollIntoView();
executeSoon(() => {
--- a/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js
+++ b/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js
@@ -42,17 +42,17 @@ function consoleOpened(hud)
}).then(onConsoleMessage);
}
function onConsoleMessage(aResults)
{
let msg = [...aResults[0].matched][0];
ok(msg, "message element");
- let body = msg.querySelector(".body");
+ let body = msg.querySelector(".message-body");
ok(body, "message body");
let clickable = aResults[0].clickableElements[0];
ok(clickable, "clickable object found");
ok(body.textContent.contains('{ hello: "world!",'), "message text check");
gJSTerm.once("variablesview-fetched", onObjFetch);
--- a/browser/devtools/webconsole/test/browser_console_click_focus.js
+++ b/browser/devtools/webconsole/test/browser_console_click_focus.js
@@ -20,17 +20,17 @@ function testInputFocus() {
webconsole: hud,
messages: [{
text: "Dolske Digs Bacon",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
}).then(([result]) => {
let msg = [...result.matched][0];
- let outputItem = msg.querySelector(".body");
+ let outputItem = msg.querySelector(".message-body");
ok(outputItem, "found a logged message");
let inputNode = hud.jsterm.inputNode;
ok(inputNode.getAttribute("focused"), "input node is focused, first");
let lostFocus = () => {
inputNode.removeEventListener("blur", lostFocus);
info("input node lost focus");
}
--- a/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
+++ b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
@@ -29,17 +29,17 @@ function performTest(hud)
text: "fooBug676722",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
objects: true,
}],
}).then(([result]) => {
let msg = [...result.matched][0];
ok(msg, "message element");
- let body = msg.querySelector(".body");
+ let body = msg.querySelector(".message-body");
ok(body, "message body");
let clickable = result.clickableElements[0];
ok(clickable, "the console.log() object anchor was found");
ok(body.textContent.contains('{ abba: "omgBug676722" }'),
"clickable node content is correct");
hud.jsterm.once("variablesview-fetched",
(aEvent, aVar) => {
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
@@ -31,17 +31,17 @@ function tabLoad2(aEvent) {
webconsole: HUD,
messages: [{
text: "test-console.html",
category: CATEGORY_NETWORK,
severity: SEVERITY_LOG,
}],
}).then(([result]) => {
let msg = [...result.matched][0];
- outputItem = msg.querySelector(".body .url");
+ outputItem = msg.querySelector(".message-body .url");
ok(outputItem, "found a network message");
document.addEventListener("popupshown", networkPanelShown, false);
// Send the mousedown and click events such that the network panel opens.
EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
EventUtils.sendMouseEvent({type: "click"}, outputItem);
});
}
@@ -97,17 +97,17 @@ function networkPanelHidden(aEvent) {
document.removeEventListener("popupshown", networkPanelShowFailure, false);
// Done with the network output. Now test the jsterm output and the property
// panel.
HUD.jsterm.execute("document", (msg) => {
info("jsterm execute 'document' callback");
HUD.jsterm.once("variablesview-open", onVariablesViewOpen);
- let outputItem = msg.querySelector(".body a");
+ let outputItem = msg.querySelector(".message-body a");
ok(outputItem, "jsterm output message found");
// Send the mousedown and click events such that the property panel opens.
EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
EventUtils.sendMouseEvent({type: "click"}, outputItem);
});
});
}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
@@ -61,17 +61,17 @@ function consoleOpened(HUD) {
completion = JSPropertyProvider(dbgWindow, null, "window._container.");
ok(completion, "matches available for window._container");
ok(completion.matches.length, "matches available for window (length)");
jsterm.clearOutput();
jsterm.execute("window._container", (msg) => {
jsterm.once("variablesview-fetched", testVariablesView.bind(null, HUD));
- let anchor = msg.querySelector(".body a");
+ let anchor = msg.querySelector(".message-body a");
EventUtils.synthesizeMouse(anchor, 2, 2, {}, HUD.iframeWindow);
});
}
function testVariablesView(aWebconsole, aEvent, aView) {
findVariableViewProperties(aView, [
{ name: "gen1", isGenerator: true },
{ name: "gen2", isGenerator: true },
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -70,17 +70,17 @@ function autocompletePopupHidden()
}
function testPropertyPanel()
{
let jsterm = gHUD.jsterm;
jsterm.clearOutput();
jsterm.execute("document", (msg) => {
jsterm.once("variablesview-fetched", onVariablesViewReady);
- let anchor = msg.querySelector(".body a");
+ let anchor = msg.querySelector(".message-body a");
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gHUD.iframeWindow);
});
}
function onVariablesViewReady(aEvent, aView)
{
findVariableViewProperties(aView, [
{ name: "body", value: "<body>" },
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js
@@ -53,16 +53,17 @@ function onConsoleMessage(aResults) {
// Check if the command is disabled non-network messages.
goUpdateCommand(COMMAND_NAME);
let controller = top.document.commandDispatcher
.getControllerForCommand(COMMAND_NAME);
let isDisabled = !controller || !controller.isCommandEnabled(COMMAND_NAME);
ok(isDisabled, COMMAND_NAME + " should be disabled.");
+ outputNode.selectedItem.scrollIntoView();
waitForContextMenu(contextMenu, outputNode.selectedItem, () => {
let isHidden = contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isHidden, CONTEXT_MENU_ID + " should be hidden.");
}, testOnNetActivity);
}
function testOnNetActivity() {
HUD.jsterm.clearOutput();
@@ -112,13 +113,14 @@ function onNetworkMessage(aResults) {
// Try to open the URL.
goDoCommand(COMMAND_NAME);
}
function testOnNetActivity_contextmenu(msg) {
outputNode.focus();
HUD.ui.output.selectMessage(msg);
+ msg.scrollIntoView();
waitForContextMenu(contextMenu, msg, () => {
let isShown = !contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isShown, CONTEXT_MENU_ID + " should be shown.");
}, finishTest);
}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
@@ -1,13 +1,17 @@
/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Any copyright is dedicated to the Public Domain.
+/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
- * ***** END LICENSE BLOCK ***** */
+ */
+
+// Test that message source links for js errors and console API calls open in
+// the jsdebugger when clicked.
+
+"use strict";
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test" +
"/test-bug-766001-js-console-links.html";
function test() {
let hud;
requestLongerTimeout(2);
@@ -56,18 +60,16 @@ function test() {
let line = node.sourceLine;
ok(line, "found source line for index " + index);
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" }, node);
});
- yield hud.ui.once("source-in-debugger-opened", checkLine.bind(null, url, line));
- }
+ yield hud.ui.once("source-in-debugger-opened");
- function* checkLine(url, line) {
let toolbox = yield gDevTools.getToolbox(hud.target);
let {panelWin: { DebuggerView: view }} = toolbox.getPanel("jsdebugger");
is(view.Sources.selectedValue, url, "expected source url");
is(view.editor.getCursor().line, line - 1, "expected source line");
}
}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_api_stackframe.js
@@ -0,0 +1,81 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the console API messages for console.error()/exception()/assert()
+// include a stackframe. See bug 920116.
+
+function test() {
+ let hud;
+
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-api-stackframe.html";
+ const TEST_FILE = TEST_URI.substr(TEST_URI.lastIndexOf("/"));
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ const stack = [{
+ file: TEST_FILE,
+ fn: "thirdCall",
+ line: /\b2[123]\b/, // 21,22,23
+ }, {
+ file: TEST_FILE,
+ fn: "secondCall",
+ line: 16,
+ }, {
+ file: TEST_FILE,
+ fn: "firstCall",
+ line: 12,
+ }];
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foo-log",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ collapsible: false,
+ }, {
+ text: "foo-error",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }, {
+ text: "foo-exception",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }, {
+ text: "foo-assert",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }],
+ });
+
+ let elem = [...results[1].matched][0];
+ ok(elem, "message element");
+
+ let msg = elem._messageObject;
+ ok(msg, "message object");
+
+ ok(msg.collapsed, "message is collapsed");
+
+ msg.toggleDetails();
+
+ ok(!msg.collapsed, "message is not collapsed");
+
+ msg.toggleDetails();
+
+ ok(msg.collapsed, "message is collapsed");
+
+ yield closeConsole(tab);
+ }
+}
--- a/browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js
@@ -54,17 +54,17 @@ function test() {
text: "foobar",
category: CATEGORY_WEBDEV,
}],
});
let msg = [...result.matched][0];
ok(msg, "message element");
- let span = msg.querySelector(".body span[style]");
+ let span = msg.querySelector(".message-body span[style]");
ok(span, "span element");
info("span textContent is: " + span.textContent);
isnot(span.textContent.indexOf("foobar"), -1, "span textContent check");
let outputStyle = span.getAttribute("style").replace(/\s+|;+$/g, "");
if (check.sameStyleExpected) {
is(outputStyle, check.style, "span style is correct");
--- a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
@@ -25,17 +25,17 @@ function nextTest() {
function checkResult(msg, desc) {
waitForMessages({
webconsole: jsterm.hud.owner,
messages: [{
name: desc,
category: CATEGORY_OUTPUT,
}],
}).then(([result]) => {
- let node = [...result.matched][0].querySelector(".body");
+ let node = [...result.matched][0].querySelector(".message-body");
if (typeof msg == "string") {
is(node.textContent.trim(), msg,
"correct message shown for " + desc);
}
else if (typeof msg == "function") {
ok(msg(node), "correct message shown for " + desc);
}
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -1,13 +1,15 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let {require, TargetFactory} = devtools;
let {Utils: WebConsoleUtils} = require("devtools/toolkit/webconsole/utils");
let {Messages} = require("devtools/webconsole/console-output");
@@ -877,24 +879,28 @@ function openDebugger(aOptions = {})
* Provide this if you want to match a console.time() message.
* - consoleTimeEnd: same as above, but for console.timeEnd().
* - consoleDir: boolean, set to |true| to match a console.dir()
* message.
* - consoleGroup: boolean, set to |true| to match a console.group()
* message.
* - longString: boolean, set to |true} to match long strings in the
* message.
+ * - collapsible: boolean, set to |true| to match messages that can
+ * be collapsed/expanded.
* - type: match messages that are instances of the given object. For
* example, you can point to Messages.NavigationMarker to match any
* such message.
* - objects: boolean, set to |true| if you expect inspectable
* objects in the message.
* - source: object of the shape { url, line }. This is used to
* match the source URL and line number of the error message or
* console API call.
+ * - stacktrace: array of objects of the form { file, fn, line } that
+ * can match frames in the stacktrace associated with the message.
* - groupDepth: number used to check the depth of the message in
* a group.
* - url: URL to match for network requests.
* @return object
* A promise object is returned once the messages you want are found.
* The promise is resolved with the array of rule objects you give in
* the |messages| property. Each objects is the same as provided, with
* additional properties:
@@ -913,73 +919,53 @@ function waitForMessages(aOptions)
let rules = WebConsoleUtils.cloneObject(aOptions.messages, true);
let rulesMatched = 0;
let listenerAdded = false;
let deferred = promise.defer();
aOptions.matchCondition = aOptions.matchCondition || "all";
function checkText(aRule, aText)
{
- let result;
+ let result = false;
if (Array.isArray(aRule)) {
result = aRule.every((s) => checkText(s, aText));
}
else if (typeof aRule == "string") {
result = aText.indexOf(aRule) > -1;
}
else if (aRule instanceof RegExp) {
result = aRule.test(aText);
}
+ else {
+ result = aRule == aText;
+ }
return result;
}
function checkConsoleTrace(aRule, aElement)
{
let elemText = aElement.textContent;
let trace = aRule.consoleTrace;
if (!checkText("console.trace():", elemText)) {
return false;
}
- let frame = aElement.querySelector(".stacktrace li:first-child");
- if (trace.file) {
- let file = frame.querySelector(".message-location").title;
- if (!checkText(trace.file, file)) {
- ok(false, "console.trace() message is missing the file name: " +
- trace.file);
- displayErrorContext(aRule, aElement);
- return false;
- }
- }
-
- if (trace.fn) {
- let fn = frame.querySelector(".function").textContent;
- if (!checkText(trace.fn, fn)) {
- ok(false, "console.trace() message is missing the function name: " +
- trace.fn);
- displayErrorContext(aRule, aElement);
- return false;
- }
- }
-
- if (trace.line) {
- let line = frame.querySelector(".message-location").sourceLine;
- if (!checkText(trace.line, line)) {
- ok(false, "console.trace() message is missing the line number: " +
- trace.line);
- displayErrorContext(aRule, aElement);
- return false;
- }
- }
-
aRule.category = CATEGORY_WEBDEV;
aRule.severity = SEVERITY_LOG;
aRule.type = Messages.ConsoleTrace;
+ if (!aRule.stacktrace && typeof trace == "object" && trace !== true) {
+ if (Array.isArray(trace)) {
+ aRule.stacktrace = trace;
+ } else {
+ aRule.stacktrace = [trace];
+ }
+ }
+
return true;
}
function checkConsoleTime(aRule, aElement)
{
let elemText = aElement.textContent;
let time = aRule.consoleTime;
@@ -1053,16 +1039,76 @@ function waitForMessages(aOptions)
if ("line" in aRule.source && location.sourceLine != aRule.source.line) {
return false;
}
return true;
}
+ function checkCollapsible(aRule, aElement)
+ {
+ let msg = aElement._messageObject;
+ if (!msg || !!msg.collapsible != aRule.collapsible) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function checkStacktrace(aRule, aElement)
+ {
+ let stack = aRule.stacktrace;
+ let frames = aElement.querySelectorAll(".stacktrace > li");
+ if (!frames.length) {
+ return false;
+ }
+
+ for (let i = 0; i < stack.length; i++) {
+ let frame = frames[i];
+ let expected = stack[i];
+ if (!frame) {
+ ok(false, "expected frame #" + i + " but didnt find it");
+ return false;
+ }
+
+ if (expected.file) {
+ let file = frame.querySelector(".message-location").title;
+ if (!checkText(expected.file, file)) {
+ ok(false, "frame #" + i + " does not match file name: " +
+ expected.file);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+
+ if (expected.fn) {
+ let fn = frame.querySelector(".function").textContent;
+ if (!checkText(expected.fn, fn)) {
+ ok(false, "frame #" + i + " does not match the function name: " +
+ expected.fn);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+
+ if (expected.line) {
+ let line = frame.querySelector(".message-location").sourceLine;
+ if (!checkText(expected.line, line)) {
+ ok(false, "frame #" + i + " does not match the line number: " +
+ expected.line);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
function checkMessage(aRule, aElement)
{
let elemText = aElement.textContent;
if (aRule.text && !checkText(aRule.text, elemText)) {
return false;
}
@@ -1089,16 +1135,20 @@ function waitForMessages(aOptions)
if (aRule.consoleGroup && !checkConsoleGroup(aRule, aElement)) {
return false;
}
if (aRule.source && !checkSource(aRule, aElement)) {
return false;
}
+ if ("collapsible" in aRule && !checkCollapsible(aRule, aElement)) {
+ return false;
+ }
+
let partialMatch = !!(aRule.consoleTrace || aRule.consoleTime ||
aRule.consoleTimeEnd);
// The rule tries to match the newer types of messages, based on their
// object constructor.
if (aRule.type) {
if (!aElement._messageObject ||
!(aElement._messageObject instanceof aRule.type)) {
@@ -1124,16 +1174,28 @@ function waitForMessages(aOptions)
if (partialMatch) {
is(aElement.severity, aRule.severity,
"message severity for rule: " + displayRule(aRule));
displayErrorContext(aRule, aElement);
}
return false;
}
+ if (aRule.text) {
+ partialMatch = true;
+ }
+
+ if (aRule.stacktrace && !checkStacktrace(aRule, aElement)) {
+ if (partialMatch) {
+ ok(false, "failed to match stacktrace for rule: " + displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+
if (aRule.category == CATEGORY_NETWORK && "url" in aRule &&
!checkText(aRule.url, aElement.url)) {
return false;
}
if ("repeats" in aRule) {
let repeats = aElement.querySelector(".message-repeats");
if (!repeats || repeats.getAttribute("value") != aRule.repeats) {
@@ -1161,17 +1223,17 @@ function waitForMessages(aOptions)
displayErrorContext(aRule, aElement);
}
return false;
}
aRule.longStrings = longStrings;
}
if ("objects" in aRule) {
- let clickables = aElement.querySelectorAll(".body a");
+ let clickables = aElement.querySelectorAll(".message-body a");
if (aRule.objects != !!clickables[0]) {
if (partialMatch) {
is(!!clickables[0], aRule.objects,
"objects existence check failed for message rule: " +
displayRule(aRule));
displayErrorContext(aRule, aElement);
}
return false;
@@ -1405,17 +1467,18 @@ function checkOutputForInputs(hud, input
}
if (typeof entry.inspectorIcon == "boolean") {
yield checkLinkToInspector(entry, msg);
}
}
function checkObjectClick(entry, msg)
{
- let body = msg.querySelector(".body a") || msg.querySelector(".body");
+ let body = msg.querySelector(".message-body a") ||
+ msg.querySelector(".message-body");
ok(body, "the message body");
let deferred = promise.defer();
entry._onVariablesViewOpen = onVariablesViewOpen.bind(null, entry, deferred);
hud.jsterm.on("variablesview-open", entry._onVariablesViewOpen);
eventHandlers.add(entry._onVariablesViewOpen);
--- a/browser/devtools/webconsole/test/test-bug-766001-console-log.js
+++ b/browser/devtools/webconsole/test/test-bug-766001-console-log.js
@@ -1,8 +1,10 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-window.addEventListener("load", function() {
+function onLoad123() {
console.log("Blah Blah");
-}, false);
+}
+
+window.addEventListener("load", onLoad123, false);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-api-stackframe.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+ <head>
+ <meta charset="utf8">
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <title>Test for bug 920116 - stacktraces for console API messages</title>
+ <script>
+ function firstCall() {
+ secondCall();
+ }
+
+ function secondCall() {
+ thirdCall();
+ }
+
+ function thirdCall() {
+ console.log("foo-log");
+ console.error("foo-error");
+ console.exception("foo-exception");
+ console.assert("red" == "blue", "foo-assert");
+ }
+
+ window.onload = firstCall;
+ </script>
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -1368,17 +1368,17 @@ WebConsoleFrame.prototype = {
let node = this.createMessageNode(aCategory, severity,
errorMessage,
aScriptError.sourceName,
aScriptError.lineNumber, null, null,
aScriptError.timeStamp);
// Select the body of the message node that is displayed in the console
- let msgBody = node.getElementsByClassName("body")[0];
+ let msgBody = node.getElementsByClassName("message-body")[0];
// Add the more info link node to messages that belong to certain categories
this.addMoreInfoLink(msgBody, aScriptError);
if (aScriptError.private) {
node.setAttribute("private", true);
}
if (objectActors.size > 0) {
@@ -2456,17 +2456,17 @@ WebConsoleFrame.prototype = {
iconContainer.className = "icon";
// Apply the current group by indenting appropriately.
let iconMarginLeft = this.groupDepth * GROUP_INDENT + GROUP_INDENT_DEFAULT;
iconContainer.style.marginLeft = iconMarginLeft + "px";
// Create the message body, which contains the actual text of the message.
let bodyNode = this.document.createElementNS(XHTML_NS, "span");
- bodyNode.className = "body devtools-monospace";
+ bodyNode.className = "message-body-wrapper message-body devtools-monospace";
// Store the body text, since it is needed later for the variables view.
let body = aBody;
// If a string was supplied for the body, turn it into a DOM node and an
// associated clipboard string now.
aClipboardText = aClipboardText ||
(aBody + (aSourceURL ? " @ " + aSourceURL : "") +
(aSourceLine ? ":" + aSourceLine : ""));
@@ -2603,17 +2603,19 @@ WebConsoleFrame.prototype = {
}
filenameNode.className = "filename";
filenameNode.textContent = " " + (filename || l10n.getStr("unknownLocation"));
locationNode.appendChild(filenameNode);
locationNode.href = isScratchpad || !fullURL ? "#" : fullURL;
locationNode.draggable = false;
- locationNode.target = aTarget;
+ if (aTarget) {
+ locationNode.target = aTarget;
+ }
locationNode.setAttribute("title", aSourceURL);
locationNode.className = "message-location theme-link devtools-monospace";
// Make the location clickable.
let onClick = () => {
let target = locationNode.target;
if (target == "scratchpad" || isScratchpad) {
this.owner.viewSourceInScratchpad(aSourceURL);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
-Current extension version is: 1.0.21
+Current extension version is: 1.0.68
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -222,17 +222,18 @@ ChromeActions.prototype = {
},
download: function(data, sendResponse) {
var self = this;
var originalUrl = data.originalUrl;
// The data may not be downloaded so we need just retry getting the pdf with
// the original url.
var originalUri = NetUtil.newURI(data.originalUrl);
var filename = data.filename;
- if (typeof filename !== 'string' || !/\.pdf$/i.test(filename)) {
+ if (typeof filename !== 'string' ||
+ (!/\.pdf$/i.test(filename) && !data.isAttachment)) {
filename = 'document.pdf';
}
var blobUri = data.blobUrl ? NetUtil.newURI(data.blobUrl) : originalUri;
var extHelperAppSvc =
Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
getService(Ci.nsIExternalHelperAppService);
var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher).activeWindow;
@@ -268,17 +269,18 @@ ChromeActions.prototype = {
if ('nsIPrivateBrowsingChannel' in Ci &&
channel instanceof Ci.nsIPrivateBrowsingChannel) {
channel.setPrivate(docIsPrivate);
}
var listener = {
extListener: null,
onStartRequest: function(aRequest, aContext) {
- this.extListener = extHelperAppSvc.doContent('application/pdf',
+ this.extListener = extHelperAppSvc.doContent((data.isAttachment ? '' :
+ 'application/pdf'),
aRequest, frontWindow, false);
this.extListener.onStartRequest(aRequest, aContext);
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
if (this.extListener)
this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
// Notify the content code we're done downloading.
if (sendResponse)
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -16,18 +16,18 @@
*/
/*jshint globalstrict: false */
// Initializing PDFJS global object (if still undefined)
if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '1.0.21';
-PDFJS.build = 'f954cde';
+PDFJS.version = '1.0.68';
+PDFJS.build = 'ead4cbf';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
'use strict';
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
@@ -448,16 +448,38 @@ function stringToBytes(str) {
return bytes;
}
function string32(value) {
return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
(value >> 8) & 0xff, value & 0xff);
}
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
// Lazy test the endianness of the platform
// NOTE: This will be 'true' for simulated TypedArrays
function isLittleEndian() {
var buffer8 = new Uint8Array(2);
buffer8[0] = 1;
var buffer16 = new Uint16Array(buffer8.buffer);
return (buffer16[0] === 1);
}
@@ -1740,41 +1762,41 @@ var DeviceCmykCS = (function DeviceCmykC
// f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
var c = src[srcOffset + 0] * srcScale;
var m = src[srcOffset + 1] * srcScale;
var y = src[srcOffset + 2] * srcScale;
var k = src[srcOffset + 3] * srcScale;
var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
+ (c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k +
+ -285.2331026137004) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y +
+ -17.873870861415444 * k - 5.497006427196366) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 17.5119270841813) +
+ k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
+ (c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k +
+ -79.2970844816548) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 190.9453302588951) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
+ k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
+ (c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k +
+ -14.183576799673286) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 112.23884253719248) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k +
+ -193.58209356861505) +
+ k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
}
function DeviceCmykCS() {
this.name = 'DeviceCMYK';
@@ -2137,17 +2159,16 @@ var PDFFunction = (function PDFFunctionC
parse: function PDFFunction_parse(xref, fn) {
var IR = this.getIR(xref, fn);
return this.fromIR(IR);
},
constructSampled: function PDFFunction_constructSampled(str, dict) {
function toMultiArray(arr) {
var inputLength = arr.length;
- var outputLength = arr.length / 2;
var out = [];
var index = 0;
for (var i = 0; i < inputLength; i += 2) {
out[index] = [arr[i], arr[i + 1]];
++index;
}
return out;
}
@@ -2208,17 +2229,17 @@ var PDFFunction = (function PDFFunctionC
// See chapter 3, page 110 of the PDF reference.
var m = IR[1];
var domain = IR[2];
var encode = IR[3];
var decode = IR[4];
var samples = IR[5];
var size = IR[6];
var n = IR[7];
- var mask = IR[8];
+ //var mask = IR[8];
var range = IR[9];
if (m != args.length) {
error('Incorrect number of arguments: ' + m + ' != ' +
args.length);
}
var x = args;
@@ -2879,16 +2900,17 @@ var Annotation = (function AnnotationClo
data.borderWidth = 0;
}
}
}
}
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
}
Annotation.prototype = {
getData: function Annotation_getData() {
return this.data;
},
@@ -2987,18 +3009,16 @@ var Annotation = (function AnnotationClo
'Font'
// ProcSet
// Properties
]);
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
var transform = getTransformMatrix(data.rect, bbox, matrix);
- var border = data.border;
-
resourcesPromise.then(function(resources) {
var opList = new OperatorList();
opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
evaluator.getOperatorList(this.appearance, resources, opList);
opList.addOp(OPS.endAnnotation, []);
promise.resolve(opList);
this.appearance.reset();
@@ -3214,17 +3234,16 @@ var TextWidgetAnnotation = (function Tex
var fontName = fontObj.loadedName;
var fontFamily = fontName ? '"' + fontName + '", ' : '';
// Use a reasonable default font if the font doesn't specify a fallback
var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
style.fontFamily = fontFamily + fallbackName;
}
- var parent = WidgetAnnotation.prototype;
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
hasHtml: function TextWidgetAnnotation_hasHtml() {
return !this.data.hasAppearance && !!this.data.fieldValue;
},
getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
assert(!isWorker, 'getHtmlElement() shall be called from main thread');
@@ -3237,17 +3256,17 @@ var TextWidgetAnnotation = (function Tex
content.textContent = item.fieldValue;
var textAlignment = item.textAlignment;
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
content.style.verticalAlign = 'middle';
content.style.display = 'table-cell';
var fontObj = item.fontRefName ?
commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
+ setTextStyles(content, item, fontObj);
element.appendChild(content);
return element;
},
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
if (this.appearance) {
@@ -3269,17 +3288,16 @@ var TextWidgetAnnotation = (function Tex
// Include any font resources found in the default appearance
var stream = new Stream(stringToBytes(defaultAppearance));
evaluator.getOperatorList(stream, this.fieldResources, opList);
var appearanceFnArray = opList.fnArray;
var appearanceArgsArray = opList.argsArray;
var fnArray = [];
- var argsArray = [];
// TODO(mack): Add support for stroke color
data.rgb = [0, 0, 0];
// TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
for (var i = 0, n = fnArray.length; i < n; ++i) {
var fnId = appearanceFnArray[i];
var args = appearanceArgsArray[i];
@@ -3485,17 +3503,16 @@ var TextAnnotation = (function TextAnnot
var toggleAnnotation = function toggleAnnotation() {
if (pinned) {
hideAnnotation(true);
} else {
showAnnotation(true);
}
};
- var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
image.addEventListener('mouseover', function image_mouseOverHandler() {
showAnnotation();
}, false);
image.addEventListener('mouseout', function image_mouseOutHandler() {
hideAnnotation();
@@ -3590,17 +3607,16 @@ var LinkAnnotation = (function LinkAnnot
},
getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
var container = this.initContainer();
container.className = 'annotLink';
var item = this.data;
- var rect = item.rect;
container.style.borderColor = item.colorCssRgb;
container.style.borderStyle = 'solid';
var link = document.createElement('a');
link.href = link.title = this.data.url || '';
container.appendChild(link);
@@ -3846,16 +3862,23 @@ var PDFDocumentProxy = (function PDFDocu
/**
* @return {Promise} A promise that is resolved with a lookup table for
* mapping named destinations to reference numbers.
*/
getDestinations: function PDFDocumentProxy_getDestinations() {
return this.transport.getDestinations();
},
/**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named attachments to their content.
+ */
+ getAttachments: function PDFDocumentProxy_getAttachments() {
+ return this.transport.getAttachments();
+ },
+ /**
* @return {Promise} A promise that is resolved with an array of all the
* JavaScript strings in the name tree.
*/
getJavaScript: function PDFDocumentProxy_getJavaScript() {
var promise = new PDFJS.LegacyPromise();
var js = this.pdfInfo.javaScript;
promise.resolve(js);
return promise;
@@ -4622,16 +4645,26 @@ var WorkerTransport = (function WorkerTr
this.messageHandler.send('GetDestinations', null,
function transportDestinations(destinations) {
promise.resolve(destinations);
}
);
return promise;
},
+ getAttachments: function WorkerTransport_getAttachments() {
+ var promise = new PDFJS.LegacyPromise();
+ this.messageHandler.send('GetAttachments', null,
+ function transportAttachments(attachments) {
+ promise.resolve(attachments);
+ }
+ );
+ return promise;
+ },
+
startCleanup: function WorkerTransport_startCleanup() {
this.messageHandler.send('Cleanup', null,
function endCleanup() {
for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
var page = this.pageCache[i];
if (page) {
page.destroy();
}
@@ -5416,17 +5449,16 @@ var CanvasGraphics = (function CanvasGra
var src = imgData.data;
var dest = chunkImgData.data;
var i, j, thisChunkHeight, elemsInThisChunk;
// There are multiple forms in which the pixel data can be passed, and
// imgData.kind tells us which one this is.
if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
// Grayscale, 1 bit per pixel (i.e. black-and-white).
- var destDataLength = dest.length;
var srcLength = src.byteLength;
var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :
new Uint32ArrayView(dest);
var dest32DataLength = dest32.length;
var fullSrcDiff = (width + 7) >> 3;
var white = 0xFFFFFFFF;
var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?
0xFF000000 : 0x000000FF;
@@ -5687,17 +5719,16 @@ var CanvasGraphics = (function CanvasGra
var i = executionStartIdx || 0;
var argsArrayLen = argsArray.length;
// Sometimes the OperatorList to execute is empty.
if (argsArrayLen == i) {
return i;
}
- var executionEndIdx;
var endTime = Date.now() + EXECUTION_TIME;
var commonObjs = this.commonObjs;
var objs = this.objs;
var fnId;
var deferred = Promise.resolve();
while (true) {
@@ -6263,17 +6294,16 @@ var CanvasGraphics = (function CanvasGra
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
var textHScale = current.textHScale * current.fontDirection;
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
var glyphsLength = glyphs.length;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
var i, glyph, width;
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
if (fontSize === 0) {
return;
}
// Type3 fonts - each glyph is a "mini-PDF"
if (font.coded) {
ctx.save();
@@ -6391,17 +6421,16 @@ var CanvasGraphics = (function CanvasGra
current.y -= x * textHScale;
} else {
current.x += x * textHScale;
}
ctx.restore();
}
},
showSpacedText: function CanvasGraphics_showSpacedText(arr) {
- var ctx = this.ctx;
var current = this.current;
var font = current.font;
var fontSize = current.fontSize;
// TJ array's number is independent from fontMatrix
var textHScale = current.textHScale * 0.001 * current.fontDirection;
var arrLength = arr.length;
var vertical = font.vertical;
@@ -6467,18 +6496,16 @@ var CanvasGraphics = (function CanvasGra
},
getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
var pattern;
if (IR[0] == 'TilingPattern') {
var args = IR[1];
var base = cs.base;
var color;
if (base) {
- var baseComps = base.numComps;
-
color = base.getRgb(args, 0);
}
pattern = new TilingPattern(IR, color, this.ctx, this.objs,
this.commonObjs, this.baseTransform);
} else {
pattern = getShadingPatternFromIR(IR);
}
return pattern;
@@ -7727,23 +7754,23 @@ var createMeshCanvas = (function createM
return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
scaleX: scaleX, scaleY: scaleY};
}
return createMeshCanvas;
})();
ShadingIRs.Mesh = {
fromIR: function Mesh_fromIR(raw) {
- var type = raw[1];
+ //var type = raw[1];
var coords = raw[2];
var colors = raw[3];
var figures = raw[4];
var bounds = raw[5];
var matrix = raw[6];
- var bbox = raw[7];
+ //var bbox = raw[7];
var background = raw[8];
return {
type: 'Pattern',
getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
var combinedScale;
// Obtain scale from matrix and current transformation matrix.
if (shadingFill) {
combinedScale = Util.singularValueDecompose2dScale(
@@ -7830,17 +7857,16 @@ var TilingPattern = (function TilingPatt
var bbox = this.bbox;
var xstep = this.xstep;
var ystep = this.ystep;
var paintType = this.paintType;
var tilingType = this.tilingType;
var color = this.color;
var objs = this.objs;
var commonObjs = this.commonObjs;
- var ctx = this.ctx;
info('TilingType: ' + tilingType);
var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
var topLeft = [x0, y0];
// we want the canvas to be as large as the step size
var botRight = [x0 + xstep, y0 + ystep];
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -16,18 +16,18 @@
*/
/*jshint globalstrict: false */
// Initializing PDFJS global object (if still undefined)
if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '1.0.21';
-PDFJS.build = 'f954cde';
+PDFJS.version = '1.0.68';
+PDFJS.build = 'ead4cbf';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
'use strict';
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
@@ -448,16 +448,38 @@ function stringToBytes(str) {
return bytes;
}
function string32(value) {
return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
(value >> 8) & 0xff, value & 0xff);
}
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
// Lazy test the endianness of the platform
// NOTE: This will be 'true' for simulated TypedArrays
function isLittleEndian() {
var buffer8 = new Uint8Array(2);
buffer8[0] = 1;
var buffer16 = new Uint16Array(buffer8.buffer);
return (buffer16[0] === 1);
}
@@ -1740,41 +1762,41 @@ var DeviceCmykCS = (function DeviceCmykC
// f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
var c = src[srcOffset + 0] * srcScale;
var m = src[srcOffset + 1] * srcScale;
var y = src[srcOffset + 2] * srcScale;
var k = src[srcOffset + 3] * srcScale;
var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
+ (c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k +
+ -285.2331026137004) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y +
+ -17.873870861415444 * k - 5.497006427196366) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 17.5119270841813) +
+ k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
+ (c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k +
+ -79.2970844816548) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 190.9453302588951) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
+ k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
+ (c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k +
+ -14.183576799673286) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 112.23884253719248) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k +
+ -193.58209356861505) +
+ k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
}
function DeviceCmykCS() {
this.name = 'DeviceCMYK';
@@ -2137,17 +2159,16 @@ var PDFFunction = (function PDFFunctionC
parse: function PDFFunction_parse(xref, fn) {
var IR = this.getIR(xref, fn);
return this.fromIR(IR);
},
constructSampled: function PDFFunction_constructSampled(str, dict) {
function toMultiArray(arr) {
var inputLength = arr.length;
- var outputLength = arr.length / 2;
var out = [];
var index = 0;
for (var i = 0; i < inputLength; i += 2) {
out[index] = [arr[i], arr[i + 1]];
++index;
}
return out;
}
@@ -2208,17 +2229,17 @@ var PDFFunction = (function PDFFunctionC
// See chapter 3, page 110 of the PDF reference.
var m = IR[1];
var domain = IR[2];
var encode = IR[3];
var decode = IR[4];
var samples = IR[5];
var size = IR[6];
var n = IR[7];
- var mask = IR[8];
+ //var mask = IR[8];
var range = IR[9];
if (m != args.length) {
error('Incorrect number of arguments: ' + m + ' != ' +
args.length);
}
var x = args;
@@ -2879,16 +2900,17 @@ var Annotation = (function AnnotationClo
data.borderWidth = 0;
}
}
}
}
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
}
Annotation.prototype = {
getData: function Annotation_getData() {
return this.data;
},
@@ -2987,18 +3009,16 @@ var Annotation = (function AnnotationClo
'Font'
// ProcSet
// Properties
]);
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
var transform = getTransformMatrix(data.rect, bbox, matrix);
- var border = data.border;
-
resourcesPromise.then(function(resources) {
var opList = new OperatorList();
opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
evaluator.getOperatorList(this.appearance, resources, opList);
opList.addOp(OPS.endAnnotation, []);
promise.resolve(opList);
this.appearance.reset();
@@ -3214,17 +3234,16 @@ var TextWidgetAnnotation = (function Tex
var fontName = fontObj.loadedName;
var fontFamily = fontName ? '"' + fontName + '", ' : '';
// Use a reasonable default font if the font doesn't specify a fallback
var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
style.fontFamily = fontFamily + fallbackName;
}
- var parent = WidgetAnnotation.prototype;
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
hasHtml: function TextWidgetAnnotation_hasHtml() {
return !this.data.hasAppearance && !!this.data.fieldValue;
},
getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
assert(!isWorker, 'getHtmlElement() shall be called from main thread');
@@ -3237,17 +3256,17 @@ var TextWidgetAnnotation = (function Tex
content.textContent = item.fieldValue;
var textAlignment = item.textAlignment;
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
content.style.verticalAlign = 'middle';
content.style.display = 'table-cell';
var fontObj = item.fontRefName ?
commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
+ setTextStyles(content, item, fontObj);
element.appendChild(content);
return element;
},
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
if (this.appearance) {
@@ -3269,17 +3288,16 @@ var TextWidgetAnnotation = (function Tex
// Include any font resources found in the default appearance
var stream = new Stream(stringToBytes(defaultAppearance));
evaluator.getOperatorList(stream, this.fieldResources, opList);
var appearanceFnArray = opList.fnArray;
var appearanceArgsArray = opList.argsArray;
var fnArray = [];
- var argsArray = [];
// TODO(mack): Add support for stroke color
data.rgb = [0, 0, 0];
// TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
for (var i = 0, n = fnArray.length; i < n; ++i) {
var fnId = appearanceFnArray[i];
var args = appearanceArgsArray[i];
@@ -3485,17 +3503,16 @@ var TextAnnotation = (function TextAnnot
var toggleAnnotation = function toggleAnnotation() {
if (pinned) {
hideAnnotation(true);
} else {
showAnnotation(true);
}
};
- var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
image.addEventListener('mouseover', function image_mouseOverHandler() {
showAnnotation();
}, false);
image.addEventListener('mouseout', function image_mouseOutHandler() {
hideAnnotation();
@@ -3590,17 +3607,16 @@ var LinkAnnotation = (function LinkAnnot
},
getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
var container = this.initContainer();
container.className = 'annotLink';
var item = this.data;
- var rect = item.rect;
container.style.borderColor = item.colorCssRgb;
container.style.borderStyle = 'solid';
var link = document.createElement('a');
link.href = link.title = this.data.url || '';
container.appendChild(link);
@@ -3737,17 +3753,17 @@ var ChunkedStream = (function ChunkedStr
},
getUint16: function ChunkedStream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
- getUint32: function ChunkedStream_getUint32() {
+ getInt32: function ChunkedStream_getInt32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
// returns subarray of original buffer
@@ -3826,17 +3842,16 @@ var ChunkedStream = (function ChunkedStr
};
return ChunkedStream;
})();
var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
function ChunkedStreamManager(length, chunkSize, url, args) {
- var self = this;
this.stream = new ChunkedStream(length, chunkSize, this);
this.length = length;
this.chunkSize = chunkSize;
this.url = url;
this.disableAutoFetch = args.disableAutoFetch;
var msgHandler = this.msgHandler = args.msgHandler;
if (args.chunkedViewerLoading) {
@@ -5259,16 +5274,40 @@ var Catalog = (function CatalogClosure()
if (!names.hasOwnProperty(name)) {
continue;
}
dests[name] = fetchDestination(names[name]);
}
}
return shadow(this, 'destinations', dests);
},
+ get attachments() {
+ var xref = this.xref;
+ var attachments, nameTreeRef;
+ var obj = this.catDict.get('Names');
+ if (obj) {
+ nameTreeRef = obj.getRaw('EmbeddedFiles');
+ }
+
+ if (nameTreeRef) {
+ var nameTree = new NameTree(nameTreeRef, xref);
+ var names = nameTree.getAll();
+ for (var name in names) {
+ if (!names.hasOwnProperty(name)) {
+ continue;
+ }
+ var fs = new FileSpec(names[name], xref);
+ if (!attachments) {
+ attachments = {};
+ }
+ attachments[stringToPDFString(name)] = fs.serializable;
+ }
+ }
+ return shadow(this, 'attachments', attachments);
+ },
get javaScript() {
var xref = this.xref;
var obj = this.catDict.get('Names');
var javaScript = [];
if (obj && obj.has('JavaScript')) {
var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
var names = nameTree.getAll();
@@ -5745,18 +5784,16 @@ var XRef = (function XRefClosure() {
var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
var stream = this.stream;
stream.pos = 0;
var buffer = stream.getBytes();
var position = stream.start, length = buffer.length;
var trailers = [], xrefStms = [];
- var state = 0;
- var currentToken;
while (position < length) {
var ch = buffer[position];
if (ch === 32 || ch === 9 || ch === 13 || ch === 10) {
++position;
continue;
}
if (ch === 37) { // %-comment
do {
@@ -6123,16 +6160,107 @@ var NameTree = (function NameTreeClosure
}
return dict;
}
};
return NameTree;
})();
/**
+ * "A PDF file can refer to the contents of another file by using a File
+ * Specification (PDF 1.1)", see the spec (7.11) for more details.
+ * NOTE: Only embedded files are supported (as part of the attachments support)
+ * TODO: support the 'URL' file system (with caching if !/V), portable
+ * collections attributes and related files (/RF)
+ */
+var FileSpec = (function FileSpecClosure() {
+ function FileSpec(root, xref) {
+ if (!root || !isDict(root)) {
+ return;
+ }
+ this.xref = xref;
+ this.root = root;
+ if (root.has('FS')) {
+ this.fs = root.get('FS');
+ }
+ this.description = root.has('Desc') ?
+ stringToPDFString(root.get('Desc')) :
+ '';
+ if (root.has('RF')) {
+ warn('Related file specifications are not supported');
+ }
+ this.contentAvailable = true;
+ if (!root.has('EF')) {
+ this.contentAvailable = false;
+ warn('Non-embedded file specifications are not supported');
+ }
+ }
+
+ function pickPlatformItem(dict) {
+ // Look for the filename in this order:
+ // UF, F, Unix, Mac, DOS
+ if (dict.has('UF')) {
+ return dict.get('UF');
+ } else if (dict.has('F')) {
+ return dict.get('F');
+ } else if (dict.has('Unix')) {
+ return dict.get('Unix');
+ } else if (dict.has('Mac')) {
+ return dict.get('Mac');
+ } else if (dict.has('DOS')) {
+ return dict.get('DOS');
+ } else {
+ return null;
+ }
+ }
+
+ FileSpec.prototype = {
+ get filename() {
+ if (!this._filename && this.root) {
+ var filename = pickPlatformItem(this.root) || 'unnamed';
+ this._filename = stringToPDFString(filename).
+ replace(/\\\\/g, '\\').
+ replace(/\\\//g, '/').
+ replace(/\\/g, '/');
+ }
+ return this._filename;
+ },
+ get content() {
+ if (!this.contentAvailable) {
+ return null;
+ }
+ if (!this.contentRef && this.root) {
+ this.contentRef = pickPlatformItem(this.root.get('EF'));
+ }
+ var content = null;
+ if (this.contentRef) {
+ var xref = this.xref;
+ var fileObj = xref.fetchIfRef(this.contentRef);
+ if (fileObj && isStream(fileObj)) {
+ content = fileObj.getBytes();
+ } else {
+ warn('Embedded file specification points to non-existing/invalid ' +
+ 'content');
+ }
+ } else {
+ warn('Embedded file specification does not have a content');
+ }
+ return content;
+ },
+ get serializable() {
+ return {
+ filename: this.filename,
+ content: this.content
+ };
+ }
+ };
+ return FileSpec;
+})();
+
+/**
* A helper for loading missing data in object graphs. It traverses the graph
* depth first and queues up any objects that have missing data. Once it has
* has traversed as many objects that are available it attempts to bundle the
* missing data requests and then resume from the nodes that weren't ready.
*
* NOTE: It provides protection from circular references by keeping track of
* of loaded references. However, you must be careful not to load any graphs
* that have references to the catalog or other pages since that will cause the
@@ -14321,17 +14449,16 @@ Shadings.Mesh = (function MeshClosure()
coords: psPacked,
colors: psPacked
});
}
function decodeType5Shading(mesh, reader, verticesPerRow) {
var coords = mesh.coords;
var colors = mesh.colors;
- var operators = [];
var ps = []; // not maintaining cs since that will match ps
while (reader.hasData) {
var coord = reader.readCoordinate();
var color = reader.readComponents();
ps.push(coords.length);
coords.push(coord);
colors.push(color);
}
@@ -15275,28 +15402,26 @@ var PartialEvaluator = (function Partial
getOperatorList: function PartialEvaluator_getOperatorList(stream,
resources,
operatorList,
initialState) {
var self = this;
var xref = this.xref;
- var handler = this.handler;
var imageCache = {};
operatorList = (operatorList || new OperatorList());
resources = (resources || Dict.empty);
var xobjs = (resources.get('XObject') || Dict.empty);
var patterns = (resources.get('Pattern') || Dict.empty);
var stateManager = new StateManager(initialState || new EvalState());
var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
- var promise = new LegacyPromise();
var operation, i, ii;
while ((operation = preprocessor.read())) {
var args = operation.args;
var fn = operation.fn;
var shading;
switch (fn) {
case OPS.setStrokeColorN:
@@ -15472,17 +15597,16 @@ var PartialEvaluator = (function Partial
resources = (xref.fetchIfRef(resources) || Dict.empty);
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
var xobjs = null;
var xobjsCache = {};
var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
- var res = resources;
var operation;
var textState;
function newTextChunk() {
var font = textState.font;
if (!(font.loadedName in textContent.styles)) {
textContent.styles[font.loadedName] = {
@@ -15534,16 +15658,17 @@ var PartialEvaluator = (function Partial
}
var width = 0;
var height = 0;
var glyphs = font.charsToGlyphs(chars);
var defaultVMetrics = font.defaultVMetrics;
for (var i = 0; i < glyphs.length; i++) {
var glyph = glyphs[i];
if (!glyph) { // Previous glyph was a space.
+ width += textState.wordSpacing * textState.textHScale;
continue;
}
var vMetricX = null;
var vMetricY = null;
var glyphWidth = null;
if (font.vertical) {
if (glyph.vmetric) {
glyphWidth = glyph.vmetric[0];
@@ -15639,40 +15764,41 @@ var PartialEvaluator = (function Partial
break;
case OPS.setTextMatrix:
textState.setTextMatrix(args[0], args[1], args[2], args[3],
args[4], args[5]);
textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
args[4], args[5]);
break;
case OPS.setCharSpacing:
- textState.charSpace = args[0];
+ textState.charSpacing = args[0];
break;
case OPS.setWordSpacing:
- textState.wordSpace = args[0];
+ textState.wordSpacing = args[0];
break;
case OPS.beginText:
textState.textMatrix = IDENTITY_MATRIX.slice();
textState.textLineMatrix = IDENTITY_MATRIX.slice();
break;
case OPS.showSpacedText:
var items = args[0];
var textChunk = newTextChunk();
var offset;
for (var j = 0, jj = items.length; j < jj; j++) {
if (typeof items[j] === 'string') {
buildTextGeometry(items[j], textChunk);
} else {
var val = items[j] / 1000;
if (!textState.font.vertical) {
- offset = -val * textState.fontSize * textState.textHScale;
+ offset = -val * textState.fontSize * textState.textHScale *
+ textState.textMatrix[0];
textState.translateTextMatrix(offset, 0);
textChunk.width += offset;
} else {
- offset = -val * textState.fontSize;
+ offset = -val * textState.fontSize * textState.textMatrix[3];
textState.translateTextMatrix(0, offset);
textChunk.height += offset;
}
if (items[j] < 0 && textState.font.spaceWidth > 0) {
var fakeSpaces = -items[j] / textState.font.spaceWidth;
if (fakeSpaces > MULTI_SPACE_FACTOR) {
fakeSpaces = Math.round(fakeSpaces);
while (fakeSpaces--) {
@@ -15857,17 +15983,16 @@ var PartialEvaluator = (function Partial
properties.differences = differences;
properties.baseEncodingName = baseEncodingName;
properties.dict = dict;
},
readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
var cmapObj = toUnicode;
- var charToUnicode = [];
if (isName(cmapObj)) {
return CMapFactory.create(cmapObj).map;
} else if (isStream(cmapObj)) {
var cmap = CMapFactory.create(cmapObj).map;
// Convert UTF-16BE
// NOTE: cmap can be a sparse array, so use forEach instead of for(;;)
// to iterate over all keys.
cmap.forEach(function(token, i) {
@@ -20222,17 +20347,16 @@ var Font = (function FontClosure() {
* 'charCodeToGlyphId' - maps the new font char codes to glyph ids
*/
function adjustMapping(charCodeToGlyphId, properties) {
var toUnicode = properties.toUnicode;
var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
var isIdentityUnicode = properties.isIdentityUnicode;
var newMap = Object.create(null);
var toFontChar = [];
- var usedCharCodes = [];
var usedFontCharCodes = [];
var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
for (var originalCharCode in charCodeToGlyphId) {
originalCharCode |= 0;
var glyphId = charCodeToGlyphId[originalCharCode];
var fontCharCode = originalCharCode;
// First try to map the value to a unicode position if a non identity map
// was created.
@@ -20340,17 +20464,17 @@ var Font = (function FontClosure() {
// Fill up the 4 parallel arrays describing the segments.
var startCount = '';
var endCount = '';
var idDeltas = '';
var idRangeOffsets = '';
var glyphsIds = '';
var bias = 0;
-
+
var range, start, end, codes;
for (i = 0, ii = bmpLength; i < ii; i++) {
range = ranges[i];
start = range[0];
end = range[1];
startCount += string16(start);
endCount += string16(end);
codes = range[2];
@@ -20664,19 +20788,19 @@ var Font = (function FontClosure() {
}
return data;
},
checkAndRepair: function Font_checkAndRepair(name, font, properties) {
function readTableEntry(file) {
var tag = bytesToString(file.getBytes(4));
- var checksum = file.getUint32();
- var offset = file.getUint32();
- var length = file.getUint32();
+ var checksum = file.getInt32();
+ var offset = file.getInt32() >>> 0;
+ var length = file.getInt32() >>> 0;
// Read the table associated data
var previousPosition = file.pos;
file.pos = file.start ? file.start : 0;
file.skip(offset);
var data = file.getBytes(length);
file.pos = previousPosition;
@@ -20723,17 +20847,17 @@ var Font = (function FontClosure() {
// use:
// - non-symbolic fonts the preference is a 3,1 table then a 1,0 table
// - symbolic fonts the preference is a 3,0 table then a 1,0 table
// The following takes advantage of the fact that the tables are sorted
// to work.
for (var i = 0; i < numTables; i++) {
var platformId = font.getUint16();
var encodingId = font.getUint16();
- var offset = font.getUint32();
+ var offset = font.getInt32() >>> 0;
var useTable = false;
if (platformId == 1 && encodingId === 0) {
useTable = true;
// Continue the loop since there still may be a higher priority
// table.
} else if (!isSymbolicFont && platformId === 3 && encodingId === 1) {
useTable = true;
@@ -20848,18 +20972,16 @@ var Font = (function FontClosure() {
// Format 6 is a 2-bytes dense mapping, which means the font data
// lives glue together even if they are pretty far in the unicode
// table. (This looks weird, so I can have missed something), this
// works on Linux but seems to fails on Mac so let's rewrite the
// cmap table to a 3-1-4 style
var firstCode = font.getUint16();
var entryCount = font.getUint16();
- var glyphs = [];
- var ids = [];
for (j = 0; j < entryCount; j++) {
glyphId = font.getUint16();
var charCode = firstCode + j;
mappings.push({
charCode: charCode,
glyphId: glyphId
});
@@ -21135,17 +21257,17 @@ var Font = (function FontClosure() {
}
}
function readPostScriptTable(post, properties, maxpNumGlyphs) {
var start = (font.start ? font.start : 0) + post.offset;
font.pos = start;
var length = post.length, end = start + length;
- var version = font.getUint32();
+ var version = font.getInt32();
// skip rest to the tables
font.getBytes(28);
var glyphNames;
var valid = true;
var i;
switch (version) {
@@ -21237,17 +21359,16 @@ var Font = (function FontClosure() {
for (i = 0, ii = records.length; i < ii; i++) {
var record = records[i];
var pos = start + stringsStart + record.offset;
if (pos + record.length > end) {
continue; // outside of name table, ignoring
}
font.pos = pos;
var nameIndex = record.name;
- var encoding = record.encoding ? 1 : 0;
if (record.encoding) {
// unicode
var str = '';
for (var j = 0, jj = record.length; j < jj; j += 2) {
str += String.fromCharCode(font.getUint16());
}
names[1][nameIndex] = str;
} else {
@@ -21542,17 +21663,17 @@ var Font = (function FontClosure() {
}
}
if (!tables.maxp) {
error('Required "maxp" table is not found');
}
font.pos = (font.start || 0) + tables.maxp.offset;
- var version = font.getUint32();
+ var version = font.getInt32();
var numGlyphs = font.getUint16();
var maxFunctionDefs = 0;
if (version >= 0x00010000 && tables.maxp.length >= 22) {
// maxZones can be invalid
font.pos += 8;
var maxZones = font.getUint16();
if (maxZones > 2) { // reset to 2 if font has invalid maxZones
tables.maxp.data[14] = 0;
@@ -21829,18 +21950,16 @@ var Font = (function FontClosure() {
return stringToArray(ttf.file);
},
convert: function Font_convert(fontName, font, properties) {
// The offsets object holds at the same time a representation of where
// to write the table entry information about a table and another offset
// representing the offset where to draw the actual data of a particular
// table
- var REQ_TABLES_CNT = 9;
-
var otf = {
file: '',
virtualOffset: 9 * (4 * 4)
};
createOpenTypeHeader('\x4F\x54\x54\x4F', otf, 9);
// TODO: Check the charstring widths to determine this.
@@ -22681,40 +22800,72 @@ var Type1Parser = (function Type1ParserC
/*
* Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
* of Plaintext Bytes. The function took a key as a parameter which can be
* for decrypting the eexec block of for decoding charStrings.
*/
var EEXEC_ENCRYPT_KEY = 55665;
var CHAR_STRS_ENCRYPT_KEY = 4330;
- function decrypt(stream, key, discardNumber) {
- var r = key, c1 = 52845, c2 = 22719;
- var decryptedString = [];
-
- var value = '';
- var count = stream.length;
+ function isHexDigit(code) {
+ return code >= 48 && code <= 57 || // '0'-'9'
+ code >= 65 && code <= 70 || // 'A'-'F'
+ code >= 97 && code <= 102; // 'a'-'f'
+ }
+
+ function decrypt(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length;
+ var decrypted = new Uint8Array(count);
for (var i = 0; i < count; i++) {
- value = stream[i];
- decryptedString[i] = value ^ (r >> 8);
+ var value = data[i];
+ decrypted[i] = value ^ (r >> 8);
r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
}
- return decryptedString.slice(discardNumber);
+ return Array.prototype.slice.call(decrypted, discardNumber);
+ }
+
+ function decryptAscii(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length, maybeLength = count >>> 1;
+ var decrypted = new Uint8Array(maybeLength);
+ var i, j;
+ for (i = 0, j = 0; i < count; i++) {
+ var digit1 = data[i];
+ if (!isHexDigit(digit1)) {
+ continue;
+ }
+ i++;
+ var digit2;
+ while (i < count && !isHexDigit(digit2 = data[i])) {
+ i++;
+ }
+ if (i < count) {
+ var value = parseInt(String.fromCharCode(digit1, digit2), 16);
+ decrypted[j++] = value ^ (r >> 8);
+ r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
+ }
+ }
+ return Array.prototype.slice.call(decrypted, discardNumber, j);
}
function isSpecial(c) {
return c === 0x2F || // '/'
c === 0x5B || c === 0x5D || // '[', ']'
c === 0x7B || c === 0x7D || // '{', '}'
c === 0x28 || c === 0x29; // '(', ')'
}
function Type1Parser(stream, encrypted) {
if (encrypted) {
- stream = new Stream(decrypt(stream.getBytes(), EEXEC_ENCRYPT_KEY, 4));
+ var data = stream.getBytes();
+ var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
+ isHexDigit(data[2]) && isHexDigit(data[3]));
+ stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
+ decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
}
this.stream = stream;
this.nextChar();
}
Type1Parser.prototype = {
readNumberArray: function Type1Parser_readNumberArray() {
this.getToken(); // read '[' or '{' (arrays can start with either)
@@ -23611,17 +23762,16 @@ var CFFParser = (function CFFParserClosu
}
return entries;
},
parseIndex: function CFFParser_parseIndex(pos) {
var cffIndex = new CFFIndex();
var bytes = this.bytes;
var count = (bytes[pos++] << 8) | bytes[pos++];
var offsets = [];
- var start = pos;
var end = pos;
var i, ii;
if (count !== 0) {
var offsetSize = bytes[pos++];
// add 1 for offset to determine size of last object
var startPos = pos + ((count + 1) * offsetSize) - 1;
@@ -23654,17 +23804,17 @@ var CFFParser = (function CFFParserClosu
var c = name[j];
if (j === 0 && c === 0) {
data[j] = c;
continue;
}
if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||
c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||
c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||
- c === 47 /* / */ || c === 37 /* % */) {
+ c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {
data[j] = 95;
continue;
}
data[j] = c;
}
names.push(bytesToString(data));
}
return names;
@@ -23674,18 +23824,16 @@ var CFFParser = (function CFFParserClosu
for (var i = 0, ii = index.count; i < ii; ++i) {
var data = index.get(i);
strings.add(bytesToString(data));
}
return strings;
},
createDict: function CFFParser_createDict(Type, dict, strings) {
var cffDict = new Type(strings);
- var types = cffDict.types;
-
for (var i = 0, ii = dict.length; i < ii; ++i) {
var pair = dict[i];
var key = pair[0];
var value = pair[1];
cffDict.setByKey(key, value);
}
return cffDict;
},
@@ -24243,39 +24391,26 @@ var CFFPrivateDict = (function CFFPrivat
return CFFPrivateDict;
})();
var CFFCharsetPredefinedTypes = {
ISO_ADOBE: 0,
EXPERT: 1,
EXPERT_SUBSET: 2
};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1,
- FORMAT2: 2
-};
var CFFCharset = (function CFFCharsetClosure() {
function CFFCharset(predefined, format, charset, raw) {
this.predefined = predefined;
this.format = format;
this.charset = charset;
this.raw = raw;
}
return CFFCharset;
})();
-var CFFEncodingPredefinedTypes = {
- STANDARD: 0,
- EXPERT: 1
-};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1
-};
var CFFEncoding = (function CFFEncodingClosure() {
function CFFEncoding(predefined, format, encoding, raw) {
this.predefined = predefined;
this.format = format;
this.encoding = encoding;
this.raw = raw;
}
return CFFEncoding;
@@ -24729,17 +24864,16 @@ var CFFCompiler = (function CFFCompilerC
(relativeOffset >> 8) & 0xFF,
relativeOffset & 0xFF);
}
if (objects[i]) {
relativeOffset += objects[i].length;
}
}
- var offset = data.length;
for (i = 0; i < count; i++) {
// Notify the tracker where the object will be offset in the data.
if (trackers[i]) {
trackers[i].offset(data.length);
}
for (var j = 0, jj = objects[i].length; j < jj; j++) {
data.push(objects[i][j]);
@@ -24892,20 +25026,16 @@ var FontRendererFactory = (function Font
}
function quadraticCurveTo(xa, ya, x, y) {
js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
x + ',' + y + ');');
}
var i = 0;
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
- var xMin = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
- var yMin = ((code[i + 4] << 24) | (code[i + 5] << 16)) >> 16;
- var xMax = ((code[i + 6] << 24) | (code[i + 7] << 16)) >> 16;
- var yMax = ((code[i + 8] << 24) | (code[i + 9] << 16)) >> 16;
var flags;
var x = 0, y = 0;
i += 10;
if (numberOfContours < 0) {
// composite glyph
do {
flags = (code[i] << 8) | code[i + 1];
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
@@ -29710,17 +29840,16 @@ var PDFImage = (function PDFImageClosure
return (value < 0 ? 0 : (value > max ? max : value));
}
function PDFImage(xref, res, image, inline, smask, mask, isMask) {
this.image = image;
var dict = image.dict;
if (dict.has('Filter')) {
var filter = dict.get('Filter').name;
if (filter === 'JPXDecode') {
- info('get image params from JPX stream');
var jpxImage = new JpxImage();
jpxImage.parseImageProperties(image.stream);
image.stream.reset();
image.bitsPerComponent = jpxImage.bitsPerComponent;
image.numComps = jpxImage.componentsCount;
} else if (filter === 'JBIG2Decode') {
image.bitsPerComponent = 1;
image.numComps = 1;
@@ -29759,18 +29888,20 @@ var PDFImage = (function PDFImageClosure
info('JPX images (which do not require color spaces)');
switch (image.numComps) {
case 1:
colorSpace = Name.get('DeviceGray');
break;
case 3:
colorSpace = Name.get('DeviceRGB');
break;
+ case 4:
+ colorSpace = Name.get('DeviceCMYK');
+ break;
default:
- // TODO: Find out how four color channels are handled. CMYK? Alpha?
error('JPX images with ' + this.numComps +
' color components not supported.');
}
}
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
this.numComps = this.colorSpace.numComps;
}
@@ -29916,17 +30047,16 @@ var PDFImage = (function PDFImageClosure
},
get drawHeight() {
return Math.max(this.height,
this.smask && this.smask.height || 0,
this.mask && this.mask.height || 0);
},
decodeBuffer: function PDFImage_decodeBuffer(buffer) {
var bpc = this.bpc;
- var decodeMap = this.decode;
var numComps = this.numComps;
var decodeAddends = this.decodeAddends;
var decodeCoefficients = this.decodeCoefficients;
var max = (1 << bpc) - 1;
var i, ii;
if (bpc === 1) {
@@ -33677,17 +33807,16 @@ var Lexer = (function LexerClosure() {
}
} else if (ch === 0x2D) { // '-'
// ignore minus signs in the middle of numbers to match
// Adobe's behavior
warn('Badly formated number');
} else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
// 'E' can be either a scientific notation or the beginning of a new
// operator
- var hasE = true;
ch = this.peekChar();
if (ch === 0x2B || ch === 0x2D) { // '+', '-'
powerValueSign = (ch === 0x2D) ? -1 : 1;
this.nextChar(); // Consume the sign character
} else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
// The 'E' must be the beginning of a new operator
break;
}
@@ -33955,17 +34084,16 @@ var Lexer = (function LexerClosure() {
return false;
}
if (str == 'null') {
return null;
}
return Cmd.get(str);
},
skipToNextLine: function Lexer_skipToNextLine() {
- var stream = this.stream;
var ch = this.currentChar;
while (ch >= 0) {
if (ch === 0x0D) { // CR
ch = this.nextChar();
if (ch === 0x0A) { // LF
this.nextChar();
}
break;
@@ -34175,17 +34303,16 @@ var PostScriptLexer = (function PostScri
this.stream = stream;
this.nextChar();
}
PostScriptLexer.prototype = {
nextChar: function PostScriptLexer_nextChar() {
return (this.currentChar = this.stream.getByte());
},
getToken: function PostScriptLexer_getToken() {
- var s = '';
var comment = false;
var ch = this.currentChar;
// skip comments
while (true) {
if (ch < 0) {
return EOF;
}
@@ -34273,17 +34400,17 @@ var Stream = (function StreamClosure() {
}
return this.bytes[this.pos++];
},
getUint16: function Stream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
- getUint32: function Stream_getUint32() {
+ getInt32: function Stream_getInt32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
// returns subarray of original buffer
// should only be read
@@ -34391,17 +34518,17 @@ var DecodeStream = (function DecodeStrea
}
return this.buffer[this.pos++];
},
getUint16: function DecodeStream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
- getUint32: function DecodeStream_getUint32() {
+ getInt32: function DecodeStream_getInt32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos;
@@ -35169,88 +35296,45 @@ var JpxStream = (function JpxStreamClosu
}
var jpxImage = new JpxImage();
jpxImage.parse(this.bytes);
var width = jpxImage.width;
var height = jpxImage.height;
var componentsCount = jpxImage.componentsCount;
- if (componentsCount != 1 && componentsCount != 3 && componentsCount != 4) {
- error('JPX with ' + componentsCount + ' components is not supported');
- }
-
- var data = new Uint8Array(width * height * componentsCount);
-
- for (var k = 0, kk = jpxImage.tiles.length; k < kk; k++) {
- var tileCompoments = jpxImage.tiles[k];
- var tileWidth = tileCompoments[0].width;
- var tileHeight = tileCompoments[0].height;
- var tileLeft = tileCompoments[0].left;
- var tileTop = tileCompoments[0].top;
-
- var dataPosition, sourcePosition, data0, data1, data2, data3, rowFeed;
- var i, j;
- switch (componentsCount) {
- case 1:
- data0 = tileCompoments[0].items;
-
- dataPosition = width * tileTop + tileLeft;
- rowFeed = width - tileWidth;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition++];
- }
- dataPosition += rowFeed;
- }
- break;
- case 3:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
-
- dataPosition = (width * tileTop + tileLeft) * 3;
- rowFeed = (width - tileWidth) * 3;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
- case 4:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
- data3 = tileCompoments[3].items;
-
- dataPosition = (width * tileTop + tileLeft) * 4;
- rowFeed = (width - tileWidth) * 4;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- data[dataPosition++] = data3[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
- }
- }
-
- this.buffer = data;
- this.bufferLength = data.length;
+ var tileCount = jpxImage.tiles.length;
+ if (tileCount === 1) {
+ this.buffer = jpxImage.tiles[0].items;
+ } else {
+ var data = new Uint8Array(width * height * componentsCount);
+
+ for (var k = 0; k < tileCount; k++) {
+ var tileComponents = jpxImage.tiles[k];
+ var tileWidth = tileComponents.width;
+ var tileHeight = tileComponents.height;
+ var tileLeft = tileComponents.left;
+ var tileTop = tileComponents.top;
+
+ var src = tileComponents.items;
+ var srcPosition = 0;
+ var dataPosition = (width * tileTop + tileLeft) * componentsCount;
+ var imgRowSize = width * componentsCount;
+ var tileRowSize = tileWidth * componentsCount;
+
+ for (var j = 0; j < tileHeight; j++) {
+ var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
+ data.set(rowBytes, dataPosition);
+ srcPosition += tileRowSize;
+ dataPosition += imgRowSize;
+ }
+ }
+ this.buffer = data;
+ }
+ this.bufferLength = this.buffer.length;
this.eof = true;
};
return JpxStream;
})();
/**
* For JBIG2's we use a library to decode these images and
@@ -36439,17 +36523,16 @@ var CCITTFaxStream = (function CCITTFaxS
return EOF;
};
CCITTFaxStream.prototype.getWhiteCode =
function ccittFaxStreamGetWhiteCode() {
var code = 0;
var p;
- var n;
if (this.eoblock) {
code = this.lookBits(12);
if (code == EOF) {
return 1;
}
if ((code >> 5) === 0) {
p = whiteTable1[code];
@@ -36965,16 +37048,24 @@ var WorkerMessageHandler = PDFJS.WorkerM
handler.on('GetDestinations',
function wphSetupGetDestinations(data, deferred) {
pdfManager.ensureCatalog('destinations').then(function(destinations) {
deferred.resolve(destinations);
});
}
);
+ handler.on('GetAttachments',
+ function wphSetupGetAttachments(data, deferred) {
+ pdfManager.ensureCatalog('attachments').then(function(attachments) {
+ deferred.resolve(attachments);
+ }, deferred.reject);
+ }
+ );
+
handler.on('GetData', function wphSetupGetData(data, deferred) {
pdfManager.requestLoadedStream();
pdfManager.onLoadedStream().then(function(stream) {
deferred.resolve(stream.bytes);
});
});
handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
@@ -37309,39 +37400,35 @@ var JpxImage = (function JpxImageClosure
this.parse(data);
if (this.onload) {
this.onload();
}
}).bind(this);
xhr.send(null);
},
parse: function JpxImage_parse(data) {
- function readUint(data, offset, bytes) {
- var n = 0;
- for (var i = 0; i < bytes; i++) {
- n = n * 256 + (data[offset + i] & 0xFF);
- }
- return n;
- }
-
- var head = readUint(data, 0, 2);
+
+ var head = readUint16(data, 0);
// No box header, immediate start of codestream (SOC)
if (head === 0xFF4F) {
this.parseCodestream(data, 0, data.length);
return;
}
var position = 0, length = data.length;
while (position < length) {
var headerSize = 8;
- var lbox = readUint(data, position, 4);
- var tbox = readUint(data, position + 4, 4);
+ var lbox = readUint32(data, position);
+ var tbox = readUint32(data, position + 4);
position += headerSize;
- if (lbox == 1) {
- lbox = readUint(data, position, 8);
+ if (lbox === 1) {
+ // XLBox: read UInt64 according to spec.
+ // JavaScript's int precision of 53 bit should be sufficient here.
+ lbox = readUint32(data, position) * 4294967296 +
+ readUint32(data, position + 4);
position += 8;
headerSize += 8;
}
if (lbox === 0) {
lbox = length - position + headerSize;
}
if (lbox < headerSize) {
error('JPX error: Invalid box field size');
@@ -37372,26 +37459,26 @@ var JpxImage = (function JpxImageClosure
var newByte = stream.getByte();
while (newByte >= 0) {
var oldByte = newByte;
newByte = stream.getByte();
var code = (oldByte << 8) | newByte;
// Image and tile size (SIZ)
if (code == 0xFF51) {
stream.skip(4);
- var Xsiz = stream.getUint32(); // Byte 4
- var Ysiz = stream.getUint32(); // Byte 8
- var XOsiz = stream.getUint32(); // Byte 12
- var YOsiz = stream.getUint32(); // Byte 16
+ var Xsiz = stream.getInt32() >>> 0; // Byte 4
+ var Ysiz = stream.getInt32() >>> 0; // Byte 8
+ var XOsiz = stream.getInt32() >>> 0; // Byte 12
+ var YOsiz = stream.getInt32() >>> 0; // Byte 16
stream.skip(16);
var Csiz = stream.getUint16(); // Byte 36
this.width = Xsiz - XOsiz;
this.height = Ysiz - YOsiz;
this.componentsCount = Csiz;
- // Results are always returned as UInt8Arrays
+ // Results are always returned as Uint8Arrays
this.bitsPerComponent = 8;
return;
}
}
throw 'No size marker found in JPX stream';
} catch (e) {
if (this.failOnCorruptedImage) {
error('JPX error: ' + e);
@@ -37399,17 +37486,17 @@ var JpxImage = (function JpxImageClosure
warn('JPX error: ' + e + '. Trying to recover');
}
}
},
parseCodestream: function JpxImage_parseCodestream(data, start, end) {
var context = {};
try {
var position = start;
- while (position < end) {
+ while (position + 1 < end) {
var code = readUint16(data, position);
position += 2;
var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;
switch (code) {
case 0xFF4F: // Start of codestream (SOC)
context.mainHeader = true;
break;
@@ -37545,17 +37632,16 @@ var JpxImage = (function JpxImageClosure
case 0xFF52: // Coding style default (COD)
length = readUint16(data, position);
var cod = {};
j = position + 2;
var scod = data[j++];
cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
cod.sopMarkerUsed = !!(scod & 2);
cod.ephMarkerUsed = !!(scod & 4);
- var codingStyle = {};
cod.progressionOrder = data[j++];
cod.layersCount = readUint16(data, j);
j += 2;
cod.multipleComponentTransform = data[j++];
cod.decompositionLevelsCount = data[j++];
cod.xcb = (data[j++] & 0xF) + 2;
cod.ycb = (data[j++] & 0xF) + 2;
@@ -37644,31 +37730,16 @@ var JpxImage = (function JpxImageClosure
}
}
this.tiles = transformComponents(context);
this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
this.componentsCount = context.SIZ.Csiz;
}
};
- function readUint32(data, offset) {
- return (data[offset] << 24) | (data[offset + 1] << 16) |
- (data[offset + 2] << 8) | data[offset + 3];
- }
- function readUint16(data, offset) {
- return (data[offset] << 8) | data[offset + 1];
- }
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
- }
- return i;
- }
function calculateComponentDimensions(component, siz) {
// Section B.2 Component mapping
component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
component.width = component.x1 - component.x0;
component.height = component.y1 - component.y0;
@@ -37692,17 +37763,16 @@ var JpxImage = (function JpxImageClosure
tiles.push(tile);
}
}
context.tiles = tiles;
var componentsCount = siz.Csiz;
for (var i = 0, ii = componentsCount; i < ii; i++) {
var component = components[i];
- var tileComponents = [];
for (var j = 0, jj = tiles.length; j < jj; j++) {
var tileComponent = {};
tile = tiles[j];
tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
@@ -37761,17 +37831,17 @@ var JpxImage = (function JpxImageClosure
var codeblockHeight = 1 << ycb_;
var cbx0 = subband.tbx0 >> xcb_;
var cby0 = subband.tby0 >> ycb_;
var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;
var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;
var precinctParameters = subband.resolution.precinctParameters;
var codeblocks = [];
var precincts = [];
- var i, ii, j, codeblock, precinctNumber;
+ var i, j, codeblock, precinctNumber;
for (j = cby0; j < cby1; j++) {
for (i = cbx0; i < cbx1; i++) {
codeblock = {
cbx: i,
cby: j,
tbx0: codeblockWidth * i,
tby0: codeblockHeight * j,
tbx1: codeblockWidth * (i + 1),
@@ -37786,18 +37856,16 @@ var JpxImage = (function JpxImageClosure
precinctParameters.precinctHeight);
precinctNumber = pj + pi * precinctParameters.numprecinctswide;
codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
codeblock.precinctNumber = precinctNumber;
codeblock.subbandType = subband.type;
- var coefficientsLength = (codeblock.tbx1_ - codeblock.tbx0_) *
- (codeblock.tby1_ - codeblock.tby0_);
codeblock.Lblock = 3;
codeblocks.push(codeblock);
// building precinct for the sub-band
var precinct = precincts[precinctNumber];
if (precinct !== undefined) {
if (i < precinct.cbxMin) {
precinct.cbxMin = i;
} else if (i > precinct.cbxMax) {
@@ -38006,17 +38074,16 @@ var JpxImage = (function JpxImageClosure
resolution.subbands = resolutionSubbands;
}
}
component.resolutions = resolutions;
component.subbands = subbands;
}
// Generate the packets sequence
var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
- var packetsIterator;
switch (progressionOrder) {
case 0:
tile.packetsIterator =
new LayerResolutionComponentPositionIterator(context);
break;
case 1:
tile.packetsIterator =
new ResolutionLayerComponentPositionIterator(context);
@@ -38050,34 +38117,32 @@ var JpxImage = (function JpxImageClosure
function alignToByte() {
bufferSize = 0;
if (skipNextBit) {
position++;
skipNextBit = false;
}
}
function readCodingpasses() {
- var value = readBits(1);
- if (value === 0) {
+ if (readBits(1) === 0) {
return 1;
}
- value = (value << 1) | readBits(1);
- if (value == 0x02) {
+ if (readBits(1) === 0) {
return 2;
}
- value = (value << 2) | readBits(2);
- if (value <= 0x0E) {
- return (value & 0x03) + 3;
- }
- value = (value << 5) | readBits(5);
- if (value <= 0x1FE) {
- return (value & 0x1F) + 6;
- }
- value = (value << 7) | readBits(7);
- return (value & 0x7F) + 37;
+ var value = readBits(2);
+ if (value < 3) {
+ return value + 3;
+ }
+ value = readBits(5);
+ if (value < 31) {
+ return value + 6;
+ }
+ value = readBits(7);
+ return value + 37;
}
var tileIndex = context.currentTile.index;
var tile = context.tiles[tileIndex];
var packetsIterator = tile.packetsIterator;
while (position < dataLength) {
var packet = packetsIterator.nextPacket();
if (!readBits(1)) {
alignToByte();
@@ -38173,55 +38238,62 @@ var JpxImage = (function JpxImageClosure
end: offset + position + packetItem.dataLength,
codingpasses: packetItem.codingpasses
});
position += packetItem.dataLength;
}
}
return position;
}
- function copyCoefficients(coefficients, x0, y0, width, height,
- delta, mb, codeblocks, reversible,
- segmentationSymbolUsed) {
+ function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
+ delta, mb, reversible, segmentationSymbolUsed) {
+ var x0 = subband.tbx0;
+ var y0 = subband.tby0;
+ var width = subband.tbx1 - subband.tbx0;
+ var codeblocks = subband.codeblocks;
+ var right = subband.type.charAt(0) === 'H' ? 1 : 0;
+ var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
+
for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
var blockHeight = codeblock.tby1_ - codeblock.tby0_;
if (blockWidth === 0 || blockHeight === 0) {
continue;
}
if (!('data' in codeblock)) {
continue;
}
var bitModel, currentCodingpassType;
bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
- codeblock.zeroBitPlanes);
+ codeblock.zeroBitPlanes, mb);
currentCodingpassType = 2; // first bit plane starts from cleanup
// collect data
var data = codeblock.data, totalLength = 0, codingpasses = 0;
- var q, qq, dataItem;
- for (q = 0, qq = data.length; q < qq; q++) {
- dataItem = data[q];
+ var j, jj, dataItem;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
totalLength += dataItem.end - dataItem.start;
codingpasses += dataItem.codingpasses;
}
- var encodedData = new Uint8Array(totalLength), k = 0;
- for (q = 0, qq = data.length; q < qq; q++) {
- dataItem = data[q];
+ var encodedData = new Uint8Array(totalLength);
+ var position = 0;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
- encodedData.set(chunk, k);
- k += chunk.length;
+ encodedData.set(chunk, position);
+ position += chunk.length;
}
// decoding the item
var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
bitModel.setDecoder(decoder);
- for (q = 0; q < codingpasses; q++) {
+ for (j = 0; j < codingpasses; j++) {
switch (currentCodingpassType) {
case 0:
bitModel.runSignificancePropogationPass();
break;
case 1:
bitModel.runMagnitudeRefinementPass();
break;
case 2:
@@ -38230,35 +38302,41 @@ var JpxImage = (function JpxImageClosure
bitModel.checkSegmentationSymbol();
}
break;
}
currentCodingpassType = (currentCodingpassType + 1) % 3;
}
var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
- var n, nb, correction, position = 0;
- var irreversible = !reversible;
var sign = bitModel.coefficentsSign;
var magnitude = bitModel.coefficentsMagnitude;
var bitsDecoded = bitModel.bitsDecoded;
var magnitudeCorrection = reversible ? 0 : 0.5;
- for (var j = 0; j < blockHeight; j++) {
+ var k, n, nb;
+ position = 0;
+ // Do the interleaving of Section F.3.3 here, so we do not need
+ // to copy later. LL level is not interleaved, just copied.
+ var interleave = (subband.type !== 'LL');
+ for (j = 0; j < blockHeight; j++) {
+ var row = (offset / width) | 0; // row in the non-interleaved subband
+ var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
for (k = 0; k < blockWidth; k++) {
n = magnitude[position];
if (n !== 0) {
n = (n + magnitudeCorrection) * delta;
if (sign[position] !== 0) {
n = -n;
}
nb = bitsDecoded[position];
- if (irreversible || mb > nb) {
- coefficients[offset] = n * (1 << (mb - nb));
+ var pos = interleave ? (levelOffset + (offset << 1)) : offset;
+ if (reversible && (nb >= mb)) {
+ coefficients[pos] = n;
} else {
- coefficients[offset] = n;
+ coefficients[pos] = n * (1 << (mb - nb));
}
}
offset++;
position++;
}
offset += width - blockWidth;
}
}
@@ -38279,50 +38357,54 @@ var JpxImage = (function JpxImageClosure
var transform = (reversible ? new ReversibleTransform() :
new IrreversibleTransform());
var subbandCoefficients = [];
var b = 0;
for (var i = 0; i <= decompositionLevelsCount; i++) {
var resolution = component.resolutions[i];
+ var width = resolution.trx1 - resolution.trx0;
+ var height = resolution.try1 - resolution.try0;
+ // Allocate space for the whole sublevel.
+ var coefficients = new Float32Array(width * height);
+
for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
var mu, epsilon;
if (!scalarExpounded) {
// formula E-5
mu = spqcds[0].mu;
epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
} else {
mu = spqcds[b].mu;
epsilon = spqcds[b].epsilon;
+ b++;
}
var subband = resolution.subbands[j];
- var width = subband.tbx1 - subband.tbx0;
- var height = subband.tby1 - subband.tby0;
var gainLog2 = SubbandsGainLog2[subband.type];
// calulate quantization coefficient (Section E.1.1.1)
var delta = (reversible ? 1 :
Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
var mb = (guardBits + epsilon - 1);
- var coefficients = new Float32Array(width * height);
- copyCoefficients(coefficients, subband.tbx0, subband.tby0,
- width, height, delta, mb, subband.codeblocks, reversible,
- segmentationSymbolUsed);
-
- subbandCoefficients.push({
- width: width,
- height: height,
- items: coefficients
- });
-
- b++;
- }
+ // In the first resolution level, copyCoefficients will fill the
+ // whole array with coefficients. In the succeding passes,
+ // copyCoefficients will consecutively fill in the values that belong
+ // to the interleaved positions of the HL, LH, and HH coefficients.
+ // The LL coefficients will then be interleaved in Transform.iterate().
+ copyCoefficients(coefficients, width, height, subband, delta, mb,
+ reversible, segmentationSymbolUsed);
+ }
+ subbandCoefficients.push({
+ width: width,
+ height: height,
+ items: coefficients
+ });
}
var result = transform.calculate(subbandCoefficients,
component.tcx0, component.tcy0);
return {
left: component.tcx0,
top: component.tcy0,
width: result.width,
@@ -38332,79 +38414,110 @@ var JpxImage = (function JpxImageClosure
}
function transformComponents(context) {
var siz = context.SIZ;
var components = context.components;
var componentsCount = siz.Csiz;
var resultImages = [];
for (var i = 0, ii = context.tiles.length; i < ii; i++) {
var tile = context.tiles[i];
- var result = [];
+ var transformedTiles = [];
var c;
for (c = 0; c < componentsCount; c++) {
- var image = transformTile(context, tile, c);
- result.push(image);
- }
+ transformedTiles[c] = transformTile(context, tile, c);
+ }
+ var tile0 = transformedTiles[0];
+ var out = new Uint8Array(tile0.items.length * componentsCount);
+ var result = {
+ left: tile0.left,
+ top: tile0.top,
+ width: tile0.width,
+ height: tile0.height,
+ items: out
+ };
// Section G.2.2 Inverse multi component transform
- var y0items, y1items, y2items, j, jj, y0, y1, y2;
- var component, offset, tileImage, items;
+ var shift, offset, max, min;
+ var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;
if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
+ var fourComponents = componentsCount === 4;
+ var y0items = transformedTiles[0].items;
+ var y1items = transformedTiles[1].items;
+ var y2items = transformedTiles[2].items;
+ var y3items = fourComponents ? transformedTiles[3].items : null;
+
+ // HACK: The multiple component transform formulas below assume that
+ // all components have the same precision. With this in mind, we
+ // compute shift and offset only once.
+ shift = components[0].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+
var component0 = tile.components[0];
if (!component0.codingStyleParameters.reversibleTransformation) {
// inverse irreversible multiple component transform
- y0items = result[0].items;
- y1items = result[1].items;
- y2items = result[2].items;
for (j = 0, jj = y0items.length; j < jj; ++j) {
- y0 = y0items[j] + 0.5; y1 = y1items[j]; y2 = y2items[j];
- y0items[j] = y0 + 1.402 * y2;
- y1items[j] = y0 - 0.34413 * y1 - 0.71414 * y2;
- y2items[j] = y0 + 1.772 * y1;
+ y0 = y0items[j];
+ y1 = y1items[j];
+ y2 = y2items[j];
+ r = y0 + 1.402 * y2;
+ g = y0 - 0.34413 * y1 - 0.71414 * y2;
+ b = y0 + 1.772 * y1;
+ out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift;
+ out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift;
+ out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift;
+ if (fourComponents) {
+ k = y3items[j];
+ out[pos++] =
+ k <= min ? 0 : k >= max ? 255 : (k + offset) >> shift;
+ }
}
} else {
// inverse reversible multiple component transform
- y0items = result[0].items;
- y1items = result[1].items;
- y2items = result[2].items;
for (j = 0, jj = y0items.length; j < jj; ++j) {
- y0 = y0items[j]; y1 = y1items[j]; y2 = y2items[j];
- var i1 = y0 - ((y2 + y1) >> 2);
- y1items[j] = i1;
- y0items[j] = y2 + i1;
- y2items[j] = y1 + i1;
- }
- }
- }
-
- // To simplify things: shift and clamp output to 8 bit unsigned
- for (c = 0; c < componentsCount; c++) {
- component = components[c];
- var shift = component.precision - 8;
- tileImage = result[c];
- items = tileImage.items;
- var data = new Uint8Array(items.length);
- var low = -(128 << shift);
- var high = 127 << shift;
- for (j = 0, jj = items.length; j < jj; j++) {
- var val = items[j];
- data[j] = val <= low ? 0 : val >= high ? 255 : (val >> shift) + 128;
- }
- result[c].items = data;
- }
-
+ y0 = y0items[j];
+ y1 = y1items[j];
+ y2 = y2items[j];
+ g = y0 - ((y2 + y1) >> 2);
+ r = g + y2;
+ b = g + y1;
+ out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift;
+ out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift;
+ out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift;
+ if (fourComponents) {
+ k = y3items[j];
+ out[pos++] =
+ k <= min ? 0 : k >= max ? 255 : (k + offset) >> shift;
+ }
+ }
+ }
+ } else { // no multi-component transform
+ for (c = 0; c < componentsCount; c++) {
+ var items = transformedTiles[c].items;
+ shift = components[c].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+ for (pos = c, j = 0, jj = items.length; j < jj; j++) {
+ val = items[j];
+ out[pos] = val <= min ? 0 :
+ val >= max ? 255 : (val + offset) >> shift;
+ pos += componentsCount;
+ }
+ }
+ }
resultImages.push(result);
}
return resultImages;
}
function initializeTile(context, tileIndex) {
var siz = context.SIZ;
var componentsCount = siz.Csiz;
var tile = context.tiles[tileIndex];
- var resultTiles = [];
for (var c = 0; c < componentsCount; c++) {
var component = tile.components[c];
var qcdOrQcc = (c in context.currentTile.QCC ?
context.currentTile.QCC[c] : context.currentTile.QCD);
component.quantizationParameters = qcdOrQcc;
var codOrCoc = (c in context.currentTile.COC ?
context.currentTile.COC[c] : context.currentTile.COD);
component.codingStyleParameters = codOrCoc;
@@ -38571,30 +38684,32 @@ var JpxImage = (function JpxImageClosure
4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
]);
var HHContextLabel = new Uint8Array([
0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8
]);
- function BitModel(width, height, subband, zeroBitPlanes) {
+ function BitModel(width, height, subband, zeroBitPlanes, mb) {
this.width = width;
this.height = height;
this.contextLabelTable = (subband == 'HH' ? HHContextLabel :
(subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel));
var coefficientCount = width * height;
// coefficients outside the encoding region treated as insignificant
// add border state cells for significanceState
this.neighborsSignificance = new Uint8Array(coefficientCount);
this.coefficentsSign = new Uint8Array(coefficientCount);
- this.coefficentsMagnitude = new Uint32Array(coefficientCount);
+ this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
+ mb > 6 ? new Uint16Array(coefficientCount) :
+ new Uint8Array(coefficientCount);
this.processingFlags = new Uint8Array(coefficientCount);
var bitsDecoded = new Uint8Array(coefficientCount);
if (zeroBitPlanes !== 0) {
for (var i = 0; i < coefficientCount; i++) {
bitsDecoded[i] = zeroBitPlanes;
}
}
@@ -38657,17 +38772,16 @@ var JpxImage = (function JpxImageClosure
neighborsSignificance[index] |= 0x80;
},
runSignificancePropogationPass:
function BitModel_runSignificancePropogationPass() {
var decoder = this.decoder;
var width = this.width, height = this.height;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
- var contextLabels = this.contextLabels;
var neighborsSignificance = this.neighborsSignificance;
var processingFlags = this.processingFlags;
var contexts = this.contexts;
var labels = this.contextLabelTable;
var bitsDecoded = this.bitsDecoded;
var processedInverseMask = ~1;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
@@ -38795,86 +38909,86 @@ var JpxImage = (function JpxImageClosure
}
}
}
},
runCleanupPass: function BitModel_runCleanupPass() {
var decoder = this.decoder;
var width = this.width, height = this.height;
var neighborsSignificance = this.neighborsSignificance;
- var significanceState = this.significanceState;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
var contexts = this.contexts;
var labels = this.contextLabelTable;
var bitsDecoded = this.bitsDecoded;
var processingFlags = this.processingFlags;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
var oneRowDown = width;
var twoRowsDown = width * 2;
var threeRowsDown = width * 3;
- for (var i0 = 0; i0 < height; i0 += 4) {
+ var iNext;
+ for (var i0 = 0; i0 < height; i0 = iNext) {
+ iNext = Math.min(i0 + 4, height);
+ var indexBase = i0 * width;
+ var checkAllEmpty = i0 + 3 < height;
for (var j = 0; j < width; j++) {
- var index0 = i0 * width + j;
+ var index0 = indexBase + j;
// using the property: labels[neighborsSignificance[index]] == 0
// when neighborsSignificance[index] == 0
- var allEmpty = (i0 + 3 < height &&
+ var allEmpty = (checkAllEmpty &&
processingFlags[index0] === 0 &&
processingFlags[index0 + oneRowDown] === 0 &&
processingFlags[index0 + twoRowsDown] === 0 &&
processingFlags[index0 + threeRowsDown] === 0 &&
neighborsSignificance[index0] === 0 &&
neighborsSignificance[index0 + oneRowDown] === 0 &&
neighborsSignificance[index0 + twoRowsDown] === 0 &&
neighborsSignificance[index0 + threeRowsDown] === 0);
var i1 = 0, index = index0;
- var i, sign;
+ var i = i0, sign;
if (allEmpty) {
var hasSignificantCoefficent =
decoder.readBit(contexts, RUNLENGTH_CONTEXT);
if (!hasSignificantCoefficent) {
bitsDecoded[index0]++;
bitsDecoded[index0 + oneRowDown]++;
bitsDecoded[index0 + twoRowsDown]++;
bitsDecoded[index0 + threeRowsDown]++;
continue; // next column
}
i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
decoder.readBit(contexts, UNIFORM_CONTEXT);
- i = i0 + i1;
- index += i1 * width;
+ if (i1 !== 0) {
+ i = i0 + i1;
+ index += i1 * width;
+ }
sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
index = index0;
for (var i2 = i0; i2 <= i; i2++, index += width) {
bitsDecoded[index]++;
}
i1++;
}
- for (; i1 < 4; i1++, index += width) {
- i = i0 + i1;
- if (i >= height) {
- break;
- }
-
+ for (i = i0 + i1; i < iNext; i++, index += width) {
if (coefficentsMagnitude[index] ||
(processingFlags[index] & processedMask) !== 0) {
continue;
}
var contextLabel = labels[neighborsSignificance[index]];
var decision = decoder.readBit(contexts, contextLabel);
- if (decision == 1) {
+ if (decision === 1) {
sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
}
bitsDecoded[index]++;
}
@@ -38899,72 +39013,51 @@ var JpxImage = (function JpxImageClosure
// Section F, Discrete wavelet transformation
var Transform = (function TransformClosure() {
function Transform() {}
Transform.prototype.calculate =
function transformCalculate(subbands, u0, v0) {
var ll = subbands[0];
- for (var i = 1, ii = subbands.length; i < ii; i += 3) {
- ll = this.iterate(ll, subbands[i], subbands[i + 1],
- subbands[i + 2], u0, v0);
+ for (var i = 1, ii = subbands.length; i < ii; i++) {
+ ll = this.iterate(ll, subbands[i], u0, v0);
}
return ll;
};
Transform.prototype.extend = function extend(buffer, offset, size) {
// Section F.3.7 extending... using max extension of 4
var i1 = offset - 1, j1 = offset + 1;
var i2 = offset + size - 2, j2 = offset + size;
buffer[i1--] = buffer[j1++];
buffer[j2++] = buffer[i2--];
buffer[i1--] = buffer[j1++];
buffer[j2++] = buffer[i2--];
buffer[i1--] = buffer[j1++];
buffer[j2++] = buffer[i2--];
buffer[i1] = buffer[j1];
buffer[j2] = buffer[i2];
};
- Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
- u0, v0) {
+ Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
+ u0, v0) {
var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
- var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
- var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
- var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
-
- // Section F.3.3 interleave
- var width = llWidth + hlWidth;
- var height = llHeight + lhHeight;
- var items = new Float32Array(width * height);
- var i, j, k, l, v, u;
-
- for (i = 0, k = 0; i < llHeight; i++) {
+ var width = hl_lh_hh.width;
+ var height = hl_lh_hh.height;
+ var items = hl_lh_hh.items;
+ var i, j, k, l, u, v;
+
+ // Interleave LL according to Section F.3.3
+ for (k = 0, i = 0; i < llHeight; i++) {
l = i * 2 * width;
for (j = 0; j < llWidth; j++, k++, l += 2) {
items[l] = llItems[k];
}
}
- for (i = 0, k = 0; i < hlHeight; i++) {
- l = i * 2 * width + 1;
- for (j = 0; j < hlWidth; j++, k++, l += 2) {
- items[l] = hlItems[k];
- }
- }
- for (i = 0, k = 0; i < lhHeight; i++) {
- l = (i * 2 + 1) * width;
- for (j = 0; j < lhWidth; j++, k++, l += 2) {
- items[l] = lhItems[k];
- }
- }
- for (i = 0, k = 0; i < hhHeight; i++) {
- l = (i * 2 + 1) * width + 1;
- for (j = 0; j < hhWidth; j++, k++, l += 2) {
- items[l] = hhItems[k];
- }
- }
+ // The LL band is not needed anymore.
+ llItems = ll.items = null;
var bufferPadding = 4;
var rowBuffer = new Float32Array(width + 2 * bufferPadding);
// Section F.3.4 HOR_SR
if (width === 1) {
// if width = 1, when u0 even keep items as is, when odd divide by 2
if ((u0 & 1) !== 0) {
@@ -38972,17 +39065,17 @@ var JpxImage = (function JpxImageClosure
items[k] *= 0.5;
}
}
} else {
for (v = 0, k = 0; v < height; v++, k += width) {
rowBuffer.set(items.subarray(k, k + width), bufferPadding);
this.extend(rowBuffer, bufferPadding, width);
- this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
+ this.filter(rowBuffer, bufferPadding, width);
items.set(
rowBuffer.subarray(bufferPadding, bufferPadding + width),
k);
}
}
// Accesses to the items array can take long, because it may not fit into
@@ -39018,17 +39111,17 @@ var JpxImage = (function JpxImageClosure
}
}
currentBuffer = numBuffers;
}
currentBuffer--;
var buffer = colBuffers[currentBuffer];
this.extend(buffer, bufferPadding, height);
- this.filter(buffer, bufferPadding, height, v0, buffer);
+ this.filter(buffer, bufferPadding, height);
// If this is last buffer in this group of buffers, flush all buffers.
if (currentBuffer === 0) {
k = u - numBuffers + 1;
for (l = bufferPadding; l < ll; k += width, l++) {
for (b = 0; b < numBuffers; b++) {
items[k + b] = colBuffers[b][l];
}
@@ -39049,79 +39142,121 @@ var JpxImage = (function JpxImageClosure
// Section 3.8.2 Irreversible 9-7 filter
var IrreversibleTransform = (function IrreversibleTransformClosure() {
function IrreversibleTransform() {
Transform.call(this);
}
IrreversibleTransform.prototype = Object.create(Transform.prototype);
IrreversibleTransform.prototype.filter =
- function irreversibleTransformFilter(y, offset, length, i0, x) {
+ function irreversibleTransformFilter(x, offset, length) {
var len = length >> 1;
offset = offset | 0;
+ var j, n, current, next;
var alpha = -1.586134342059924;
var beta = -0.052980118572961;
var gamma = 0.882911075530934;
var delta = 0.443506852043971;
var K = 1.230174104914001;
var K_ = 1 / K;
- var j, n, nn;
// step 1 is combined with step 3
// step 2
- for (j = offset - 3, n = len + 4; n--; j += 2) {
- x[j] = K_ * y[j];
+ j = offset - 3;
+ for (n = len + 4; n--; j += 2) {
+ x[j] *= K_;
}
// step 1 & 3
- for (j = offset - 2, n = len + 3; n--; j += 2) {
- x[j] = K * y[j] -
- delta * (x[j - 1] + x[j + 1]);
+ j = offset - 2;
+ current = delta * x[j -1];
+ for (n = len + 3; n--; j += 2) {
+ next = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ if (n--) {
+ j += 2;
+ current = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ } else {
+ break;
+ }
}
// step 4
- for (j = offset - 1, n = len + 2; n--; j += 2) {
- x[j] -= gamma * (x[j - 1] + x[j + 1]);
+ j = offset - 1;
+ current = gamma * x[j - 1];
+ for (n = len + 2; n--; j += 2) {
+ next = gamma * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = gamma * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
}
// step 5
- for (j = offset, n = len + 1; n--; j += 2) {
- x[j] -= beta * (x[j - 1] + x[j + 1]);
+ j = offset;
+ current = beta * x[j - 1];
+ for (n = len + 1; n--; j += 2) {
+ next = beta * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = beta * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
}
// step 6
- for (j = offset + 1, n = len; n--; j += 2) {
- x[j] -= alpha * (x[j - 1] + x[j + 1]);
+ if (len !== 0) {
+ j = offset + 1;
+ current = alpha * x[j - 1];
+ for (n = len; n--; j += 2) {
+ next = alpha * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = alpha * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
+ }
}
};
return IrreversibleTransform;
})();
// Section 3.8.1 Reversible 5-3 filter
var ReversibleTransform = (function ReversibleTransformClosure() {
function ReversibleTransform() {
Transform.call(this);
}
ReversibleTransform.prototype = Object.create(Transform.prototype);
ReversibleTransform.prototype.filter =
- function reversibleTransformFilter(y, offset, length, i0, x) {
+ function reversibleTransformFilter(x, offset, length) {
var len = length >> 1;
offset = offset | 0;
var j, n;
for (j = offset, n = len + 1; n--; j += 2) {
- x[j] = y[j] - ((y[j - 1] + y[j + 1] + 2) >> 2);
+ x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
}
for (j = offset + 1, n = len; n--; j += 2) {
- x[j] = y[j] + ((x[j - 1] + x[j + 1]) >> 1);
+ x[j] += (x[j - 1] + x[j + 1]) >> 1;
}
};
return ReversibleTransform;
})();
return JpxImage;
})();
@@ -39293,43 +39428,16 @@ var Jbig2Image = (function Jbig2ImageClo
0x018B // '011000101' + '1'
];
var RefinementReusedContexts = [
0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
0x0008 // '0000' + '001000'
];
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
- }
- return i;
- }
-
- function readInt32(data, start) {
- return (data[start] << 24) | (data[start + 1] << 16) |
- (data[start + 2] << 8) | data[start + 3];
- }
-
- function readUint32(data, start) {
- var value = readInt32(data, start);
- return value & 0x80000000 ? (value + 4294967296) : value;
- }
-
- function readUint16(data, start) {
- return (data[start] << 8) | data[start + 1];
- }
-
- function readInt8(data, start) {
- return (data[start] << 24) >> 24;
- }
-
// 6.2 Generic Region Decoding Procedure
function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
decodingContext) {
if (mmr) {
error('JBIG2 error: MMR encoding is not supported');
}
var useskip = !!skip;
@@ -39750,17 +39858,17 @@ var Jbig2Image = (function Jbig2ImageClo
segmentHeader.deferredNonRetain = !!(flags & 0x80);
var pageAssociationFieldSize = !!(flags & 0x40);
var referredFlags = data[start + 5];
var referredToCount = (referredFlags >> 5) & 7;
var retainBits = [referredFlags & 31];
var position = start + 6;
if (referredFlags == 7) {
- referredToCount = readInt32(data, position - 1) & 0x1FFFFFFF;
+ referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;
position += 3;
var bytes = (referredToCount + 7) >> 3;
retainBits[0] = data[position++];
while (--bytes > 0) {
retainBits.push(data[position++]);
}
} else if (referredFlags == 5 || referredFlags == 6) {
error('JBIG2 error: invalid referred-to flags');
@@ -40294,56 +40402,16 @@ var bidi = PDFJS.bidi = (function bidiCl
function reverseValues(arr, start, end) {
for (var i = start, j = end - 1; i < j; ++i, --j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
- function mirrorGlyphs(c) {
- /*
- # BidiMirroring-1.txt
- 0028; 0029 # LEFT PARENTHESIS
- 0029; 0028 # RIGHT PARENTHESIS
- 003C; 003E # LESS-THAN SIGN
- 003E; 003C # GREATER-THAN SIGN
- 005B; 005D # LEFT SQUARE BRACKET
- 005D; 005B # RIGHT SQUARE BRACKET
- 007B; 007D # LEFT CURLY BRACKET
- 007D; 007B # RIGHT CURLY BRACKET
- 00AB; 00BB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
- 00BB; 00AB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- */
- switch (c) {
- case '(':
- return ')';
- case ')':
- return '(';
- case '<':
- return '>';
- case '>':
- return '<';
- case ']':
- return '[';
- case '[':
- return ']';
- case '}':
- return '{';
- case '{':
- return '}';
- case '\u00AB':
- return '\u00BB';
- case '\u00BB':
- return '\u00AB';
- default:
- return c;
- }
- }
-
function createBidiText(str, isLTR, vertical) {
return {
str: str,
dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
};
}
// These are used in bidi(), which is called frequently. We re-use them on
--- a/browser/extensions/pdfjs/content/web/debugger.js
+++ b/browser/extensions/pdfjs/content/web/debugger.js
@@ -15,17 +15,16 @@
* limitations under the License.
*/
/* globals PDFJS */
'use strict';
var FontInspector = (function FontInspectorClosure() {
var fonts;
- var panelWidth = 300;
var active = false;
var fontAttribute = 'data-font-name';
function removeSelection() {
var divs = document.querySelectorAll('div[' + fontAttribute + ']');
for (var i = 0, ii = divs.length; i < ii; ++i) {
var div = divs[i];
div.className = '';
}
@@ -322,32 +321,33 @@ var Stepper = (function StepperClosure()
if (!opMap) {
opMap = Object.create(null);
for (var key in PDFJS.OPS) {
opMap[PDFJS.OPS[key]] = key;
}
}
},
updateOperatorList: function updateOperatorList(operatorList) {
+ var self = this;
+
function cboxOnClick() {
var x = +this.dataset.idx;
if (this.checked) {
self.breakPoints.push(x);
} else {
self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
}
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
}
var MAX_OPERATORS_COUNT = 15000;
if (this.operatorListIdx > MAX_OPERATORS_COUNT) {
return;
}
- var self = this;
var chunk = document.createDocumentFragment();
var operatorsToDisplay = Math.min(MAX_OPERATORS_COUNT,
operatorList.fnArray.length);
for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) {
var line = c('tr');
line.className = 'line';
line.dataset.idx = i;
chunk.appendChild(line);
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fcd0b268a475662d421e9144764a09d20faf4155
GIT binary patch
literal 384
zc$@)%0e}99P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0003;Nkl<ZC{tr#
zAP4+c{J-V@rT_c?8=^}H|91eAn*Yvh$YQXZ8u#zqe;yR+e+NFa{@46_c2+8b2vC6k
z$(rvD$kO|7&79);=k(-c20^e0<LBL5O%T$1Z%v=z{^#VRBnE;1hX0HHGySi6vY3Gj
zCcXRS)IPU=$0jF&r2iaW;rYMf(;9t<BmWEj+j)C(x68jHlM;Z^27it=MSZOKyk5<W
zfeEbO_k>4t*wuc`Tb2cq{&%P`@>A8<^(NL(>Ho}s&vtk+Fua<7E9$@Hp92jMpDMqu
z1xm9(o%fjY|H;!pyNX@EE&si$I{ZV$w@o%SaA_c5db|2dDUjx3Fk~?LRQ7GXy(6+T
z5KNBxck+Mrf8+l~|GU4fb8ui_Wk3UhZHZr2{6GKy)RPIe_L$OOB@D*mE*uUFn%Jcw
efQf+-n=k;HAC|A!G+~AS0000<MNUMnLSTX%g~0Cs
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b979e523e742027645e980d8a27c54d0060ebf21
GIT binary patch
literal 871
zc$@)e1DO1YP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0009nNkl<ZNXO;X
zYe-XJ7zgmjsfm##T}4UiLl7)ME2|F$d8w=@G%~9%Mi3EQAT2M1(T8pjLRo1AR#01N
zp^|B~teLBsZcdxc>*n00Qixp6B9(Lgy*p~IIal_z=X^QudHJ1}^E~hK9-{v*5Qt#-
z{wq$zD|}{GH?lE%s@NMj=*7nYb>AD_j2@`4U~2pZK7P|=?WfhWa$EeT3Rw9Hh&-bW
zD8u?uo`(+us$E+sK$!9qNA}mjiannACYWKd9vtP?fqKUMeoc$2Ps8-R%me35Fq%um
zp^WFkGEkSa*@?4|$HO?Jot$^0%Um2BA@|{OVft3P(}fdRlhI{Yy5}3w1-<2wgX227
z?aGN9-apEq*X6k926S2;hJ-VIjji%#jKd#?5Fy-oaTj42)FiKP!+Aa0Eky#q3WHrS
z&iNu3zh*f&F2FF{d|@BC?nrFlJJD(?6nG9g?KO#UW1K5QhplRFIOFG`=iX%>pji{^
z-VU9qz`?m3bl9t%cmdjM&o@Skr{NqrIBnh`3UuYMd>h`IrNZi0&}Nq>jPnO*wLKH~
zS+sLaH;<5OCm;$f(3&M7;b%mwQCjRToVXM^TV?bJZ{;;N57Qi1KA+d1$#g#?oV*YX
z-EUliW?Mx}6!~(QXyG-tk4@l2gQw8={YAt|@*=XGhvvcIU;I9_wsHr@N$8-ymqPR0
z)PAT6YQ-7ycHEmULEV%fa9{2on!Y?4<;}cGa-7_?FlM3wDoO0fsC+L}!%wjSVcZ=w
z_B|H(320F-O(pjyfPNwBQ1@ub$S7d0{uVndbS$Y2pNj>aig$QhoIye4KGFhsC2Bjx
zW8)cOX{s^be77=d(Hem_qP8@hf@#ta^+=)YOLlq^M9V0Q7Lo`l&_G$5;fb@TI)>MS
z6_`FDJ1HzXuVtqxggl2h)K&r|mk+1y2_Ixa4TUU=Lg|m;m9}F@hFV^Mbk@$1Y+oMb
zWvE9@)n9QTb16yvrKn-`XkbaxFs$HTmZbeH7wWfoU3q4&gqNcl)q|C~%exc)`0cLM
xV0mA@ASQ16s;xe2X({<njgP;^kEZbN`w1rY0*o@`?gan<002ovPDHLkV1kKWoksuw
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -528,16 +528,19 @@ html[dir='rtl'] .splitToolbarButton > .t
.toolbarButton.textButton:hover,
.toolbarButton.textButton:focus {
background-color: hsla(0,0%,0%,.2);
box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
0 0 1px hsla(0,0%,100%,.15) inset,
0 0 1px hsla(0,0%,0%,.05);
z-index: 199;
}
+.splitToolbarButton > .toolbarButton {
+ position: relative;
+}
html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child,
html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child {
position: relative;
margin: 0;
margin-right: -1px;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
border-right-color: transparent;
@@ -856,16 +859,20 @@ html[dir='rtl'] .toolbarButton.pageDown:
html[dir="ltr"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-viewOutline.png);
}
html[dir="rtl"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-viewOutline-rtl.png);
}
+#viewAttachments.toolbarButton::before {
+ content: url(images/toolbarButton-viewAttachments.png);
+}
+
#viewFind.toolbarButton::before {
content: url(images/toolbarButton-search.png);
}
.secondaryToolbarButton {
position: relative;
margin: 0 0 4px 0;
padding: 3px 0 1px 0;
@@ -1065,17 +1072,18 @@ a:focus > .thumbnail > .thumbnailSelecti
background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
background-clip: padding-box;
box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
0 0 1px hsla(0,0%,100%,.1) inset,
0 0 1px hsla(0,0%,0%,.2);
color: hsla(0,0%,100%,1);
}
-#outlineView {
+#outlineView,
+#attachmentsView {
position: absolute;
width: 192px;
top: 0;
bottom: 0;
padding: 4px 4px 0;
overflow: auto;
-moz-user-select: none;
}
@@ -1083,39 +1091,43 @@ a:focus > .thumbnail > .thumbnailSelecti
html[dir='ltr'] .outlineItem > .outlineItems {
margin-left: 20px;
}
html[dir='rtl'] .outlineItem > .outlineItems {
margin-right: 20px;
}
-.outlineItem > a {
+.outlineItem > a,
+.attachmentsItem > a {
text-decoration: none;
display: inline-block;
min-width: 95%;
height: auto;
margin-bottom: 1px;
border-radius: 2px;
color: hsla(0,0%,100%,.8);
font-size: 13px;
line-height: 15px;
-moz-user-select: none;
white-space: normal;
}
-html[dir='ltr'] .outlineItem > a {
+html[dir='ltr'] .outlineItem > a,
+html[dir='ltr'] .attachmentsItem > a {
padding: 2px 0 5px 10px;
}
-html[dir='rtl'] .outlineItem > a {
+html[dir='rtl'] .outlineItem > a,
+html[dir='rtl'] .attachmentsItem > a {
padding: 2px 10px 5px 0;
}
-.outlineItem > a:hover {
+.outlineItem > a:hover,
+.attachmentsItem > a:hover {
background-color: hsla(0,0%,100%,.02);
background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
background-clip: padding-box;
box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
0 0 1px hsla(0,0%,100%,.2) inset,
0 0 1px hsla(0,0%,0%,.2);
color: hsla(0,0%,100%,.9);
}
@@ -1636,16 +1648,20 @@ html[dir='rtl'] #documentPropertiesConta
html[dir="ltr"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-viewOutline@2x.png);
}
html[dir="rtl"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-viewOutline-rtl@2x.png);
}
+ #viewAttachments.toolbarButton::before {
+ content: url(images/toolbarButton-viewAttachments@2x.png);
+ }
+
#viewFind.toolbarButton::before {
content: url(images/toolbarButton-search@2x.png);
}
.secondaryToolbarButton.firstPage::before {
content: url(images/secondaryToolbarButton-firstPage@2x.png);
}
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -18,17 +18,17 @@ Adobe CMap resources are covered by thei
http://sourceforge.net/adobe/cmap/wiki/License/
-->
<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>PDF.js viewer</title>
-<!-- This snippet is used in firefox extension, see Makefile -->
+<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
<base href="resource://pdf.js/web/" />
<script type="text/javascript" src="l10n.js"></script>
<script type="text/javascript" src="../build/pdf.js"></script>
<link rel="stylesheet" href="viewer.css"/>
@@ -48,23 +48,28 @@ http://sourceforge.net/adobe/cmap/wiki/L
<div id="toolbarSidebar">
<div class="splitToolbarButton toggled">
<button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
<span data-l10n-id="thumbs_label">Thumbnails</span>
</button>
<button id="viewOutline" class="toolbarButton group" title="Show Document Outline" tabindex="3" data-l10n-id="outline">
<span data-l10n-id="outline_label">Document Outline</span>
</button>
+ <button id="viewAttachments" class="toolbarButton group" title="Show Attachments" tabindex="4" data-l10n-id="attachments">
+ <span data-l10n-id="attachments_label">Attachments</span>
+ </button>
</div>
</div>
<div id="sidebarContent">
<div id="thumbnailView">
</div>
<div id="outlineView" class="hidden">
</div>
+ <div id="attachmentsView" class="hidden">
+ </div>
</div>
</div> <!-- sidebarContainer -->
<div id="mainContainer">
<div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
<label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
<input id="findInput" class="toolbarField" tabindex="41">
<div class="splitToolbarButton">
@@ -80,143 +85,143 @@ http://sourceforge.net/adobe/cmap/wiki/L
<label for="findHighlightAll" class="toolbarLabel" tabindex="44" data-l10n-id="find_highlight">Highlight all</label>
<input type="checkbox" id="findMatchCase" class="toolbarField">
<label for="findMatchCase" class="toolbarLabel" tabindex="45" data-l10n-id="find_match_case_label">Match case</label>
<span id="findMsg" class="toolbarLabel"></span>
</div> <!-- findbar -->
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
<div id="secondaryToolbarButtonContainer">
- <button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="18" data-l10n-id="presentation_mode">
+ <button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="19" data-l10n-id="presentation_mode">
<span data-l10n-id="presentation_mode_label">Presentation Mode</span>
</button>
- <button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView" title="Open File" tabindex="19" data-l10n-id="open_file">
+ <button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView" title="Open File" tabindex="20" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
</button>
- <button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="20" data-l10n-id="print">
+ <button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="21" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
</button>
- <button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="21" data-l10n-id="download">
+ <button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="22" data-l10n-id="download">
<span data-l10n-id="download_label">Download</span>
</button>
- <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="22" data-l10n-id="bookmark">
+ <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="23" data-l10n-id="bookmark">
<span data-l10n-id="bookmark_label">Current View</span>
</a>
<div class="horizontalToolbarSeparator visibleLargeView"></div>
- <button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="23" data-l10n-id="first_page">
+ <button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="24" data-l10n-id="first_page">
<span data-l10n-id="first_page_label">Go to First Page</span>
</button>
- <button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="24" data-l10n-id="last_page">
+ <button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="25" data-l10n-id="last_page">
<span data-l10n-id="last_page_label">Go to Last Page</span>
</button>
<div class="horizontalToolbarSeparator"></div>
- <button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="25" data-l10n-id="page_rotate_cw">
+ <button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="26" data-l10n-id="page_rotate_cw">
<span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
</button>
- <button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="26" data-l10n-id="page_rotate_ccw">
+ <button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="27" data-l10n-id="page_rotate_ccw">
<span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwise</span>
</button>
<div class="horizontalToolbarSeparator"></div>
- <button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="27" data-l10n-id="hand_tool_enable">
+ <button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="28" data-l10n-id="hand_tool_enable">
<span data-l10n-id="hand_tool_enable_label">Enable hand tool</span>
</button>
<div class="horizontalToolbarSeparator"></div>
- <button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="28" data-l10n-id="document_properties">
+ <button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="29" data-l10n-id="document_properties">
<span data-l10n-id="document_properties_label">Document Properties…</span>
</button>
</div>
</div> <!-- secondaryToolbar -->
<div class="toolbar">
<div id="toolbarContainer">
<div id="toolbarViewer">
<div id="toolbarViewerLeft">
- <button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="4" data-l10n-id="toggle_sidebar">
+ <button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="5" data-l10n-id="toggle_sidebar">
<span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
</button>
<div class="toolbarButtonSpacer"></div>
- <button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="5" data-l10n-id="findbar">
+ <button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="6" data-l10n-id="findbar">
<span data-l10n-id="findbar_label">Find</span>
</button>
<div class="splitToolbarButton">
- <button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="6" data-l10n-id="previous">
+ <button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="7" data-l10n-id="previous">
<span data-l10n-id="previous_label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
- <button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="7" data-l10n-id="next">
+ <button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="8" data-l10n-id="next">
<span data-l10n-id="next_label">Next</span>
</button>
</div>
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
- <input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="8">
+ <input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="9">
<span id="numPages" class="toolbarLabel"></span>
</div>
<div id="toolbarViewerRight">
- <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="12" data-l10n-id="presentation_mode">
+ <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="13" data-l10n-id="presentation_mode">
<span data-l10n-id="presentation_mode_label">Presentation Mode</span>
</button>
- <button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="13" data-l10n-id="open_file">
+ <button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="14" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
</button>
- <button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="14" data-l10n-id="print">
+ <button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="15" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
</button>
- <button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="15" data-l10n-id="download">
+ <button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="16" data-l10n-id="download">
<span data-l10n-id="download_label">Download</span>
</button>
<!-- <div class="toolbarButtonSpacer"></div> -->
- <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="16" data-l10n-id="bookmark">
+ <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="17" data-l10n-id="bookmark">
<span data-l10n-id="bookmark_label">Current View</span>
</a>
<div class="verticalToolbarSeparator hiddenSmallView"></div>
- <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="17" data-l10n-id="tools">
+ <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="18" data-l10n-id="tools">
<span data-l10n-id="tools_label">Tools</span>
</button>
</div>
<div class="outerCenter">
<div class="innerCenter" id="toolbarViewerMiddle">
<div class="splitToolbarButton">
- <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="9" data-l10n-id="zoom_out">
+ <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="10" data-l10n-id="zoom_out">
<span data-l10n-id="zoom_out_label">Zoom Out</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
- <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="10" data-l10n-id="zoom_in">
+ <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="11" data-l10n-id="zoom_in">
<span data-l10n-id="zoom_in_label">Zoom In</span>
</button>
</div>
<span id="scaleSelectContainer" class="dropdownToolbarButton">
- <select id="scaleSelect" title="Zoom" tabindex="11" data-l10n-id="zoom">
- <option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
- <option id="pageActualOption" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
- <option id="pageFitOption" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
- <option id="pageWidthOption" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
- <option id="customScaleOption" value="custom"></option>
- <option value="0.5">50%</option>
- <option value="0.75">75%</option>
- <option value="1">100%</option>
- <option value="1.25">125%</option>
- <option value="1.5">150%</option>
- <option value="2">200%</option>
+ <select id="scaleSelect" title="Zoom" tabindex="12" data-l10n-id="zoom">
+ <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
+ <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
+ <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
+ <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
+ <option id="customScaleOption" title="" value="custom"></option>
+ <option title="" value="0.5">50%</option>
+ <option title="" value="0.75">75%</option>
+ <option title="" value="1">100%</option>
+ <option title="" value="1.25">125%</option>
+ <option title="" value="1.5">150%</option>
+ <option title="" value="2">200%</option>
</select>
</span>
</div>
</div>
</div>
<div id="loadingBar">
<div class="progress">
<div class="glimmer">
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -515,16 +515,28 @@ var DownloadManager = (function Download
DownloadManager.prototype = {
downloadUrl: function DownloadManager_downloadUrl(url, filename) {
FirefoxCom.request('download', {
originalUrl: url,
filename: filename
});
},
+ downloadData: function DownloadManager_downloadData(data, filename,
+ contentType) {
+ var blobUrl = PDFJS.createObjectURL(data, contentType);
+
+ FirefoxCom.request('download', {
+ blobUrl: blobUrl,
+ originalUrl: blobUrl,
+ filename: filename,
+ isAttachment: true
+ });
+ },
+
download: function DownloadManager_download(blob, url, filename) {
var blobUrl = window.URL.createObjectURL(blob);
FirefoxCom.request('download', {
blobUrl: blobUrl,
originalUrl: url,
filename: filename
},
@@ -2824,26 +2836,26 @@ var PDFView = {
}
},
setTitle: function pdfViewSetTitle(title) {
document.title = title;
},
close: function pdfViewClose() {
+ var errorWrapper = document.getElementById('errorWrapper');
+ errorWrapper.setAttribute('hidden', 'true');
+
if (!this.pdfDocument) {
return;
}
this.pdfDocument.destroy();
this.pdfDocument = null;
- var errorWrapper = document.getElementById('errorWrapper');
- errorWrapper.setAttribute('hidden', 'true');
-
var thumbsView = document.getElementById('thumbnailView');
while (thumbsView.hasChildNodes()) {
thumbsView.removeChild(thumbsView.lastChild);
}
if ('_loadingInterval' in thumbsView) {
clearInterval(thumbsView._loadingInterval);
}
@@ -2857,21 +2869,20 @@ var PDFView = {
PDFBug.cleanup();
}
},
// TODO(mack): This function signature should really be pdfViewOpen(url, args)
open: function pdfViewOpen(url, scale, password,
pdfDataRangeTransport, args) {
if (this.pdfDocument) {
- this.close();
-
// Reload the preferences if a document was previously opened.
Preferences.reload();
}
+ this.close();
var parameters = {password: password};
if (typeof url === 'string') { // URL
this.setTitleUsingUrl(url);
parameters.url = url;
} else if (url && 'byteLength' in url) { // ArrayBuffer
parameters.data = url;
}
@@ -3302,16 +3313,20 @@ var PDFView = {
if (!self.sidebarOpen) {
document.getElementById('sidebarToggle').click();
}
self.switchSidebarView('outline');
}
});
}
});
+ pdfDocument.getAttachments().then(function(attachments) {
+ self.attachments = new DocumentAttachmentsView(attachments);
+ document.getElementById('viewAttachments').disabled = !attachments;
+ });
});
pdfDocument.getMetadata().then(function(data) {
var info = data.info, metadata = data.metadata;
self.documentInfo = info;
self.metadata = metadata;
// Provides some basic debug information
@@ -3543,70 +3558,91 @@ var PDFView = {
if (dest) {
var currentPage = this.pages[(pageNumber || this.page) - 1];
currentPage.scrollIntoView(dest);
} else if (pageNumber) {
this.page = pageNumber; // simple page
}
if ('pagemode' in params) {
var toggle = document.getElementById('sidebarToggle');
- if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') {
+ if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks' ||
+ params.pagemode === 'attachments') {
if (!this.sidebarOpen) {
toggle.click();
}
- this.switchSidebarView(params.pagemode === 'thumbs' ?
- 'thumbs' : 'outline');
+ this.switchSidebarView(params.pagemode === 'bookmarks' ?
+ 'outline' :
+ params.pagemode);
} else if (params.pagemode === 'none' && this.sidebarOpen) {
toggle.click();
}
}
} else if (/^\d+$/.test(hash)) { // page number
this.page = hash;
} else { // named destination
PDFHistory.updateNextHashParam(unescape(hash));
PDFView.navigateTo(unescape(hash));
}
},
switchSidebarView: function pdfViewSwitchSidebarView(view) {
var thumbsView = document.getElementById('thumbnailView');
var outlineView = document.getElementById('outlineView');
+ var attachmentsView = document.getElementById('attachmentsView');
var thumbsButton = document.getElementById('viewThumbnail');
var outlineButton = document.getElementById('viewOutline');
+ var attachmentsButton = document.getElementById('viewAttachments');
switch (view) {
case 'thumbs':
- var wasOutlineViewVisible = thumbsView.classList.contains('hidden');
+ var wasAnotherViewVisible = thumbsView.classList.contains('hidden');
thumbsButton.classList.add('toggled');
outlineButton.classList.remove('toggled');
+ attachmentsButton.classList.remove('toggled');
thumbsView.classList.remove('hidden');
outlineView.classList.add('hidden');
+ attachmentsView.classList.add('hidden');
PDFView.renderHighestPriority();
- if (wasOutlineViewVisible) {
+ if (wasAnotherViewVisible) {
// Ensure that the thumbnail of the current page is visible
- // when switching from the outline view.
+ // when switching from another view.
scrollIntoView(document.getElementById('thumbnailContainer' +
this.page));
}
break;
case 'outline':
thumbsButton.classList.remove('toggled');
outlineButton.classList.add('toggled');
+ attachmentsButton.classList.remove('toggled');
thumbsView.classList.add('hidden');
outlineView.classList.remove('hidden');
+ attachmentsView.classList.add('hidden');
if (outlineButton.getAttribute('disabled')) {
return;
}
break;
+
+ case 'attachments':
+ thumbsButton.classList.remove('toggled');
+ outlineButton.classList.remove('toggled');
+ attachmentsButton.classList.add('toggled');
+ thumbsView.classList.add('hidden');
+ outlineView.classList.add('hidden');
+ attachmentsView.classList.remove('hidden');
+
+ if (attachmentsButton.getAttribute('disabled')) {
+ return;
+ }
+ break;
}
},
getVisiblePages: function pdfViewGetVisiblePages() {
if (!PresentationMode.active) {
return this.getVisibleElements(this.container, this.pages, true);
} else {
// The algorithm in getVisibleElements doesn't work in all browsers and
@@ -3668,17 +3704,17 @@ var PDFView = {
}
return {first: first, last: last, views: visible};
},
// Helper function to parse query string (e.g. ?param1=value&parm2=...).
parseQueryString: function pdfViewParseQueryString(query) {
var parts = query.split('&');
var params = {};
- for (var i = 0, ii = parts.length; i < parts.length; ++i) {
+ for (var i = 0, ii = parts.length; i < ii; ++i) {
var param = parts[i].split('=');
var key = param[0];
var value = param.length > 1 ? param[1] : null;
params[decodeURIComponent(key)] = decodeURIComponent(value);
}
return params;
},
@@ -3859,37 +3895,46 @@ var PageView = function pageView(contain
this.destroy = function pageViewDestroy() {
this.zoomLayer = null;
this.reset();
if (this.pdfPage) {
this.pdfPage.destroy();
}
};
- this.reset = function pageViewReset() {
+ this.reset = function pageViewReset(keepAnnotations) {
if (this.renderTask) {
this.renderTask.cancel();
}
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
div.style.width = Math.floor(this.viewport.width) + 'px';
div.style.height = Math.floor(this.viewport.height) + 'px';
var childNodes = div.childNodes;
for (var i = div.childNodes.length - 1; i >= 0; i--) {
var node = childNodes[i];
- if (this.zoomLayer && this.zoomLayer === node) {
+ if ((this.zoomLayer && this.zoomLayer === node) ||
+ (keepAnnotations && this.annotationLayer === node)) {
continue;
}
div.removeChild(node);
}
div.removeAttribute('data-loaded');
- this.annotationLayer = null;
+ if (keepAnnotations) {
+ if (this.annotationLayer) {
+ // Hide annotationLayer until all elements are resized
+ // so they are not displayed on the already-resized page
+ this.annotationLayer.setAttribute('hidden', 'true');
+ }
+ } else {
+ this.annotationLayer = null;
+ }
delete this.canvas;
this.loadingIconDiv = document.createElement('div');
this.loadingIconDiv.className = 'loadingIcon';
div.appendChild(this.loadingIconDiv);
};
@@ -3911,17 +3956,17 @@ var PageView = function pageView(contain
return;
} else if (this.canvas && !this.zoomLayer) {
this.zoomLayer = this.canvas.parentNode;
this.zoomLayer.style.position = 'absolute';
}
if (this.zoomLayer) {
this.cssTransform(this.zoomLayer.firstChild);
}
- this.reset();
+ this.reset(true);
};
this.cssTransform = function pageCssTransform(canvas) {
// Scale canvas, canvas wrapper, and page container.
var width = this.viewport.width;
var height = this.viewport.height;
canvas.style.width = canvas.parentNode.style.width = div.style.width =
Math.floor(width) + 'px';
@@ -4060,70 +4105,83 @@ var PageView = function pageView(contain
break; // No action according to spec
}
return false;
};
link.className = 'internalLink';
}
pdfPage.getAnnotations().then(function(annotationsData) {
+ viewport = viewport.clone({ dontFlip: true });
+ var transform = viewport.transform;
+ var transformStr = 'matrix(' + transform.join(',') + ')';
+ var data, element, i, ii;
+
if (self.annotationLayer) {
- // If an annotationLayer already exists, delete it to avoid creating
- // duplicate annotations when rapidly re-zooming the document.
- pageDiv.removeChild(self.annotationLayer);
- self.annotationLayer = null;
- }
- viewport = viewport.clone({ dontFlip: true });
- for (var i = 0; i < annotationsData.length; i++) {
- var data = annotationsData[i];
- var annotation = PDFJS.Annotation.fromData(data);
- if (!annotation || !annotation.hasHtml()) {
- continue;
+ // If an annotationLayer already exists, refresh its children's
+ // transformation matrices
+ for (i = 0, ii = annotationsData.length; i < ii; i++) {
+ data = annotationsData[i];
+ element = self.annotationLayer.querySelector(
+ '[data-annotation-id="' + data.id + '"]');
+ if (element) {
+ CustomStyle.setProp('transform', element, transformStr);
+ }
}
-
- var element = annotation.getHtmlElement(pdfPage.commonObjs);
- mozL10n.translate(element);
-
- data = annotation.getData();
- var rect = data.rect;
- var view = pdfPage.view;
- rect = PDFJS.Util.normalizeRect([
- rect[0],
- view[3] - rect[1] + view[1],
- rect[2],
- view[3] - rect[3] + view[1]
- ]);
- element.style.left = rect[0] + 'px';
- element.style.top = rect[1] + 'px';
- element.style.position = 'absolute';
-
- var transform = viewport.transform;
- var transformStr = 'matrix(' + transform.join(',') + ')';
- CustomStyle.setProp('transform', element, transformStr);
- var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
- CustomStyle.setProp('transformOrigin', element, transformOriginStr);
-
- if (data.subtype === 'Link' && !data.url) {
- var link = element.getElementsByTagName('a')[0];
- if (link) {
- if (data.action) {
- bindNamedAction(link, data.action);
- } else {
- bindLink(link, ('dest' in data) ? data.dest : null);
+ // See this.reset()
+ self.annotationLayer.removeAttribute('hidden');
+ } else {
+ for (i = 0, ii = annotationsData.length; i < ii; i++) {
+ data = annotationsData[i];
+ var annotation = PDFJS.Annotation.fromData(data);
+ if (!annotation || !annotation.hasHtml()) {
+ continue;
+ }
+
+ element = annotation.getHtmlElement(pdfPage.commonObjs);
+ element.setAttribute('data-annotation-id', data.id);
+ mozL10n.translate(element);
+
+ data = annotation.getData();
+ var rect = data.rect;
+ var view = pdfPage.view;
+ rect = PDFJS.Util.normalizeRect([
+ rect[0],
+ view[3] - rect[1] + view[1],
+ rect[2],
+ view[3] - rect[3] + view[1]
+ ]);
+ element.style.left = rect[0] + 'px';
+ element.style.top = rect[1] + 'px';
+ element.style.position = 'absolute';
+
+ CustomStyle.setProp('transform', element, transformStr);
+ var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
+ CustomStyle.setProp('transformOrigin', element, transformOriginStr);
+
+ if (data.subtype === 'Link' && !data.url) {
+ var link = element.getElementsByTagName('a')[0];
+ if (link) {
+ if (data.action) {
+ bindNamedAction(link, data.action);
+ } else {
+ bindLink(link, ('dest' in data) ? data.dest : null);
+ }
}
}
+
+ if (!self.annotationLayer) {
+ var annotationLayerDiv = document.createElement('div');
+ annotationLayerDiv.className = 'annotationLayer';
+ pageDiv.appendChild(annotationLayerDiv);
+ self.annotationLayer = annotationLayerDiv;
+ }
+
+ self.annotationLayer.appendChild(element);
}
-
- if (!self.annotationLayer) {
- var annotationLayerDiv = document.createElement('div');
- annotationLayerDiv.className = 'annotationLayer';
- pageDiv.appendChild(annotationLayerDiv);
- self.annotationLayer = annotationLayerDiv;
- }
- self.annotationLayer.appendChild(element);
}
});
}
this.getPagePoint = function pageViewGetPagePoint(x, y) {
return this.viewport.convertToPdfPoint(x, y);
};
@@ -4249,20 +4307,24 @@ var PageView = function pageView(contain
var canvasWrapper = document.createElement('div');
canvasWrapper.style.width = div.style.width;
canvasWrapper.style.height = div.style.height;
canvasWrapper.classList.add('canvasWrapper');
var canvas = document.createElement('canvas');
canvas.id = 'page' + this.id;
canvasWrapper.appendChild(canvas);
- div.appendChild(canvasWrapper);
+ if (this.annotationLayer) {
+ // annotationLayer needs to stay on top
+ div.insertBefore(canvasWrapper, this.annotationLayer);
+ } else {
+ div.appendChild(canvasWrapper);
+ }
this.canvas = canvas;
- var scale = this.scale;
var ctx = canvas.getContext('2d');
var outputScale = getOutputScale(ctx);
if (USE_ONLY_CSS_ZOOM) {
var actualSizeViewport = viewport.clone({ scale: CSS_UNITS });
// Use a scale that will make the canvas be the original intended size
// of the page.
outputScale.sx *= actualSizeViewport.width / viewport.width;
@@ -4278,17 +4340,22 @@ var PageView = function pageView(contain
canvas._viewport = viewport;
var textLayerDiv = null;
if (!PDFJS.disableTextLayer) {
textLayerDiv = document.createElement('div');
textLayerDiv.className = 'textLayer';
textLayerDiv.style.width = canvas.style.width;
textLayerDiv.style.height = canvas.style.height;
- div.appendChild(textLayerDiv);
+ if (this.annotationLayer) {
+ // annotationLayer needs to stay on top
+ div.insertBefore(textLayerDiv, this.annotationLayer);
+ } else {
+ div.appendChild(textLayerDiv);
+ }
}
var textLayer = this.textLayer =
textLayerDiv ? new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: this.id - 1,
lastScrollSource: PDFView,
viewport: this.viewport,
isViewerInPresentationMode: PresentationMode.active
@@ -4420,17 +4487,16 @@ var PageView = function pageView(contain
var printContainer = document.getElementById('printContainer');
var canvasWrapper = document.createElement('div');
canvasWrapper.style.width = viewport.width + 'pt';
canvasWrapper.style.height = viewport.height + 'pt';
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);
- var self = this;
canvas.mozPrintCallback = function(obj) {
var ctx = obj.context;
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE);
@@ -4789,19 +4855,16 @@ var TextLayerBuilder = function textLaye
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
var i = 0;
var iIndex = 0;
var bidiTexts = this.textContent.items;
var end = bidiTexts.length - 1;
var queryLen = (PDFFindController === null ?
0 : PDFFindController.state.query.length);
- var lastDivIdx = -1;
- var pos;
-
var ret = [];
// Loop over all the matches.
for (var m = 0; m < matches.length; m++) {
var matchIdx = matches[m];
// # Calculate the begin position.
// Loop over the divIdxs.
@@ -4982,17 +5045,16 @@ var TextLayerBuilder = function textLaye
this.renderMatches(this.matches);
};
};
var DocumentOutlineView = function documentOutlineView(outline) {
var outlineView = document.getElementById('outlineView');
- var outlineButton = document.getElementById('viewOutline');
while (outlineView.firstChild) {
outlineView.removeChild(outlineView.firstChild);
}
if (!outline) {
if (!outlineView.classList.contains('hidden')) {
PDFView.switchSidebarView('thumbs');
}
@@ -5028,16 +5090,54 @@ var DocumentOutlineView = function docum
queue.push({parent: itemsDiv, items: item.items});
}
levelData.parent.appendChild(div);
}
}
};
+var DocumentAttachmentsView = function documentAttachmentsView(attachments) {
+ var attachmentsView = document.getElementById('attachmentsView');
+ while (attachmentsView.firstChild) {
+ attachmentsView.removeChild(attachmentsView.firstChild);
+ }
+
+ if (!attachments) {
+ if (!attachmentsView.classList.contains('hidden')) {
+ PDFView.switchSidebarView('thumbs');
+ }
+ return;
+ }
+
+ function bindItemLink(domObj, item) {
+ domObj.href = '#';
+ domObj.onclick = function documentAttachmentsViewOnclick(e) {
+ var downloadManager = new DownloadManager();
+ downloadManager.downloadData(item.content, getFileName(item.filename),
+ '');
+ return false;
+ };
+ }
+
+ var names = Object.keys(attachments).sort(function(a,b) {
+ return a.toLowerCase().localeCompare(b.toLowerCase());
+ });
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ var item = attachments[names[i]];
+ var div = document.createElement('div');
+ div.className = 'attachmentsItem';
+ var a = document.createElement('a');
+ bindItemLink(a, item);
+ a.textContent = getFileName(item.filename);
+ div.appendChild(a);
+ attachmentsView.appendChild(div);
+ }
+};
+
function webViewerLoad(evt) {
PDFView.initialize().then(webViewerInitialized);
}
function webViewerInitialized() {
var file = window.location.href.split('#')[0];
@@ -5161,16 +5261,21 @@ function webViewerInitialized() {
PDFView.switchSidebarView('thumbs');
});
document.getElementById('viewOutline').addEventListener('click',
function() {
PDFView.switchSidebarView('outline');
});
+ document.getElementById('viewAttachments').addEventListener('click',
+ function() {
+ PDFView.switchSidebarView('attachments');
+ });
+
document.getElementById('previous').addEventListener('click',
function() {
PDFView.page--;
});
document.getElementById('next').addEventListener('click',
function() {
PDFView.page++;
--- a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
+++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
@@ -6,55 +6,52 @@ history-panelmenu.label = History
# LOCALIZATION NOTE(history-panelmenu.tooltiptext2): %S is the keyboard shortcut
history-panelmenu.tooltiptext2 = Show your history (%S)
privatebrowsing-button.label = New Private Window
# LOCALIZATION NOTE(privatebrowsing-button.tooltiptext): %S is the keyboard shortcut
privatebrowsing-button.tooltiptext = Open a new Private Browsing window (%S)
save-page-button.label = Save Page
-# LOCALIZATION NOTE(save-page-button.tooltiptext2): %S is the keyboard shortcut
-# Use the unicode ellipsis char, \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
-save-page-button.tooltiptext2 = Save this page… (%S)
+# LOCALIZATION NOTE(save-page-button.tooltiptext3): %S is the keyboard shortcut
+save-page-button.tooltiptext3 = Save this page (%S)
find-button.label = Find
-# LOCALIZATION NOTE(find-button.tooltiptext2): %S is the keyboard shortcut.
-# Use the unicode ellipsis char, \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
-find-button.tooltiptext2 = Find in this page… (%S)
+# LOCALIZATION NOTE(find-button.tooltiptext3): %S is the keyboard shortcut.
+find-button.tooltiptext3 = Find in this page (%S)
open-file-button.label = Open File
-# LOCALIZATION NOTE (open-file-button.tooltiptext2): %S is the keyboard shortcut.
-# Use the unicode ellipsis char, \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
-open-file-button.tooltiptext2 = Open file… (%S)
+# LOCALIZATION NOTE (open-file-button.tooltiptext3): %S is the keyboard shortcut.
+open-file-button.tooltiptext3 = Open a file (%S)
developer-button.label = Developer
# LOCALIZATION NOTE(developer-button.tooltiptext): %S is the keyboard shortcut
-developer-button.tooltiptext = Web Developer Tools (%S)
+developer-button.tooltiptext2 = Open Web developer tools (%S)
sidebar-button.label = Sidebars
-sidebar-button.tooltiptext = Show Sidebars
+sidebar-button.tooltiptext2 = Show sidebars
add-ons-button.label = Add-ons
-# LOCALIZATION NOTE(add-ons-button.tooltiptext2): %S is the keyboard shortcut
-add-ons-button.tooltiptext2 = Open Add-ons Manager (%S)
+# LOCALIZATION NOTE(add-ons-button.tooltiptext3): %S is the keyboard shortcut
+add-ons-button.tooltiptext3 = Manage your add-ons (%S)
switch-to-metro-button2.label = Windows 8 Touch
# LOCALIZATION NOTE(switch-to-metro-button2.tooltiptext): %S is the brand short name
switch-to-metro-button2.tooltiptext = Relaunch in %S for Windows 8 Touch
preferences-button.label = Preferences
-preferences-button.tooltiptext2 = Open Preferences
-preferences-button.tooltiptext.withshortcut = Open Preferences (%S)
+preferences-button.tooltiptext2 = Open preferences
+preferences-button.tooltiptext.withshortcut = Open preferences (%S)
# LOCALIZATION NOTE (preferences-button.labelWin): Windows-only label for Options
preferences-button.labelWin = Options
# LOCALIZATION NOTE (preferences-button.tooltipWin): Windows-only tooltip for Options
-preferences-button.tooltipWin2 = Open Options
+preferences-button.tooltipWin2 = Open options
zoom-controls.label = Zoom Controls
-zoom-controls.tooltiptext = Zoom Controls
+zoom-controls.tooltiptext2 = Zoom controls
zoom-out-button.label = Zoom out
# LOCALIZATION NOTE(zoom-out-button.tooltiptext2): %S is the keyboard shortcut.
zoom-out-button.tooltiptext2 = Zoom out (%S)
# LOCALIZATION NOTE(zoom-reset-button.label): %S is the current zoom level,
# %% will be displayed as a single % character (% is commonly used to define
# format specifiers, so it needs to be escaped).
@@ -62,44 +59,40 @@ zoom-reset-button.label = %S%%
# LOCALIZATION NOTE(zoom-reset-button.tooltiptext2): %S is the keyboard shortcut.
zoom-reset-button.tooltiptext2 = Reset zoom level (%S)
zoom-in-button.label = Zoom in
# LOCALIZATION NOTE(zoom-in-button.tooltiptext2): %S is the keyboard shortcut.
zoom-in-button.tooltiptext2 = Zoom in (%S)
edit-controls.label = Edit Controls
-edit-controls.tooltiptext = Edit Controls
+edit-controls.tooltiptext2 = Edit controls
cut-button.label = Cut
# LOCALIZATION NOTE(cut-button.tooltiptext2): %S is the keyboard shortcut.
cut-button.tooltiptext2 = Cut (%S)
copy-button.label = Copy
# LOCALIZATION NOTE(copy-button.tooltiptext2): %S is the keyboard shortcut.
copy-button.tooltiptext2 = Copy (%S)
paste-button.label = Paste
# LOCALIZATION NOTE(paste-button.tooltiptext2): %S is the keyboard shortcut.
paste-button.tooltiptext2 = Paste (%S)
-# LOCALIZATION NOTE (feed-button.tooltiptext): Use the unicode ellipsis char,
-# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
feed-button.label = Subscribe
-feed-button.tooltiptext = Subscribe to this page…
+feed-button.tooltiptext2 = Subscribe to this page
# LOCALIZATION NOTE (characterencoding-button.label): The \u00ad character at the beginning
# of the string is used to disable auto hyphenation on the button text when it is displayed
# in the menu panel.
characterencoding-button.label = \u00adCharacter Encoding
-characterencoding-button.tooltiptext2 = Show Character Encoding options
+characterencoding-button.tooltiptext2 = Show character encoding options
email-link-button.label = Email Link
-# LOCALIZATION NOTE (email-link-button.tooltiptext2): Use the unicode ellipsis char,
-# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
-email-link-button.tooltiptext2 = Email Link…
+email-link-button.tooltiptext3 = Email a link to this page
# LOCALIZATION NOTE(quit-button.tooltiptext.linux2): %1$S is the brand name (e.g. Firefox),
# %2$S is the keyboard shortcut
quit-button.tooltiptext.linux2 = Quit %1$S (%2$S)
# LOCALIZATION NOTE(quit-button.tooltiptext.mac): %1$S is the brand name (e.g. Firefox),
# %2$S is the keyboard shortcut
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -217,8 +217,13 @@ messageRepeats.tooltip2=#1 repeat;#1 rep
# LOCALIZATION NOTE (openNodeInInspector): the text that is displayed in a
# tooltip when hovering over the inspector icon next to a DOM Node in the console
# output
openNodeInInspector=Click to select the node in the inspector
# LOCALIZATION NOTE (cdFunctionInvalidArgument): the text that is displayed when
# cd() is invoked with an invalid argument.
cdFunctionInvalidArgument=Cannot cd() to the given window. Invalid argument.
+
+# LOCALIZATION NOTE (messageToggleDetails): the text that is displayed when
+# you hover the arrow for expanding/collapsing the message details. For
+# console.error() and other messages we show the stacktrace.
+messageToggleDetails=Show/hide message details.
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -84,16 +84,18 @@ document_properties_close=Close
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
toggle_sidebar.title=Toggle Sidebar
toggle_sidebar_label=Toggle Sidebar
outline.title=Show Document Outline
outline_label=Document Outline
+attachments.title=Show Attachments
+attachments_label=Attachments
thumbs.title=Show Thumbnails
thumbs_label=Thumbnails
findbar.title=Find in Document
findbar_label=Find
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
--- a/browser/themes/shared/devtools/webconsole.inc.css
+++ b/browser/themes/shared/devtools/webconsole.inc.css
@@ -33,20 +33,18 @@ a {
background: -moz-image-rect(url(chrome://browser/skin/devtools/webconsole.png), 0, 1, 0, 0) no-repeat;
background-position: center 0.5em;
flex: 0 0 auto;
margin: 0 6px;
padding: 0 4px;
width: 8px;
}
-.message > .body {
+.message > .message-body-wrapper {
flex: 1 1 100%;
- white-space: pre-wrap;
- word-wrap: break-word;
margin-top: 4px;
}
/* The red bubble that shows the number of times a message is repeated */
.message-repeats {
-moz-user-select: none;
flex: 0 0 auto;
margin: 2px 6px;
@@ -66,17 +64,17 @@ a {
.message-location {
-moz-margin-start: 6px;
display: flex;
flex: 0 0 auto;
align-self: flex-start;
justify-content: flex-end;
width: 10em;
- margin-top: 4px;
+ margin: 3px 0;
color: -moz-nativehyperlinktext;
text-decoration: none;
white-space: nowrap;
}
.message-location:hover,
.message-location:focus {
text-decoration: underline;
@@ -87,16 +85,30 @@ a {
text-align: end;
overflow: hidden;
}
.message-location > .line-number {
flex: 0 0 auto;
}
+.message-flex-body {
+ display: flex;
+}
+
+.message-body {
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+.message-flex-body > .message-body {
+ display: block;
+ flex: 1 1 auto;
+}
+
.jsterm-input-container {
border-top-width: 1px;
border-top-style: solid;
}
#output-wrapper {
direction: ltr;
overflow: auto;
@@ -148,25 +160,33 @@ a {
}
/* Network styles */
.webconsole-filter-button[category="net"] > .toolbarbutton-menubutton-button:before {
background-image: linear-gradient(#444444, #000000);
border-color: #777;
}
+.theme-light .message[severity=error] {
+ background-color: rgba(255, 150, 150, 0.3);
+}
+
+.theme-dark .message[severity=error] {
+ background-color: rgba(255, 100, 100, 0.3);
+}
+
.message[category=network] > .icon {
-moz-border-start: solid #000 6px;
}
.message[category=network][severity=error] > .icon {
background-image: -moz-image-rect(url(chrome://browser/skin/devtools/webconsole.png), 0, 16, 8, 8);
}
-.message[category=network] > .body {
+.message[category=network] > .message-body {
display: flex;
}
.message[category=network] .method {
flex: 0 0 auto;
}
.message[category=network]:not(.navigation-marker) .url {
@@ -279,17 +299,17 @@ a {
background: -moz-image-rect(url("chrome://browser/skin/devtools/commandline-icon.png"), 0, 32, 16, 16) no-repeat;
}
:-moz-any(.jsterm-input-node,
.jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
overflow-x: hidden;
}
-.inlined-variables-view .body {
+.inlined-variables-view .message-body {
display: flex;
flex-direction: column;
}
.inlined-variables-view iframe {
display: block;
flex: 1;
margin-top: 5px;
margin-bottom: 15px;
@@ -335,35 +355,43 @@ a {
font-size: 0.9em;
}
.navigation-marker .url {
-moz-padding-end: 9px;
text-decoration: none;
}
-.consoleTrace .body > div {
- display: flex;
- margin-bottom: 5px;
-}
-
-.consoleTrace .title {
- display: block;
- flex: 1 1 auto;
+.stacktrace {
+ display: none;
+ list-style: none;
+ padding: 0 1em 0 1.5em;
+ margin: 5px 0 0 0;
+ max-height: 10em;
+ overflow-y: auto;
+ border: 1px solid rgb(200,200,200);
+ border-radius: 3px;
}
-.stacktrace {
- list-style: none;
- padding: 0 1em 0 1.5em;
- margin: 0;
- max-height: 10em;
- overflow-y: auto;
+.theme-light .message[severity=error] .stacktrace {
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+.theme-dark .message[severity=error] .stacktrace {
+ background-color: rgba(0, 0, 0, 0.5);
+}
- border: 1px solid rgba(128, 128, 128, .5);
- border-radius: 3px;
+.message[open] .stacktrace {
+ display: block;
+}
+
+.message .theme-twisty {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 2px 3px 0 0;
}
.stacktrace li {
display: flex;
margin: 0;
}
.stacktrace .function {
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -351,26 +351,16 @@ abstract public class BrowserApp extends
if (mBrowserToolbar.onKey(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
- void handleReaderListCountRequest() {
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @Override
- public void run() {
- final int count = BrowserDB.getReadingListCount(getContentResolver());
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountReturn", Integer.toString(count)));
- }
- });
- }
-
void handleReaderListStatusRequest(final String url) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final int inReadingList = BrowserDB.isReadingListItem(getContentResolver(), url) ? 1 : 0;
final JSONObject json = new JSONObject();
try {
@@ -397,19 +387,16 @@ abstract public class BrowserApp extends
return;
}
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
BrowserDB.addReadingListItem(getContentResolver(), values);
showToast(R.string.reading_list_added, Toast.LENGTH_SHORT);
-
- final int count = BrowserDB.getReadingListCount(getContentResolver());
- GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(count)));
}
});
}
private ContentValues messageToReadingListContentValues(JSONObject message) {
final ContentValues values = new ContentValues();
values.put(ReadingListItems.URL, message.optString("url"));
values.put(ReadingListItems.TITLE, message.optString("title"));
@@ -1201,18 +1188,16 @@ abstract public class BrowserApp extends
DataReportingNotification.checkAndNotifyPolicy(GeckoAppShell.getContext());
}
} else if (event.equals("Telemetry:Gather")) {
Telemetry.HistogramAdd("PLACES_PAGES_COUNT", BrowserDB.getCount(getContentResolver(), "history"));
Telemetry.HistogramAdd("PLACES_BOOKMARKS_COUNT", BrowserDB.getCount(getContentResolver(), "bookmarks"));
Telemetry.HistogramAdd("FENNEC_FAVICONS_COUNT", BrowserDB.getCount(getContentResolver(), "favicons"));
Telemetry.HistogramAdd("FENNEC_THUMBNAILS_COUNT", BrowserDB.getCount(getContentResolver(), "thumbnails"));
- } else if (event.equals("Reader:ListCountRequest")) {
- handleReaderListCountRequest();
} else if (event.equals("Reader:ListStatusRequest")) {
handleReaderListStatusRequest(message.getString("url"));
} else if (event.equals("Reader:Added")) {
final int result = message.getInt("result");
handleReaderAdded(result, messageToReadingListContentValues(message));
} else if (event.equals("Reader:Removed")) {
final String url = message.getString("url");
handleReaderRemoved(url);
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1567,17 +1567,16 @@ public abstract class GeckoApp
startActivity(settingsIntent);
}
//app state callbacks
mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>();
//register for events
registerEventListener("log");
- registerEventListener("Reader:ListCountRequest");
registerEventListener("Reader:ListStatusRequest");
registerEventListener("Reader:Added");
registerEventListener("Reader:Removed");
registerEventListener("Reader:Share");
registerEventListener("Reader:FaviconRequest");
registerEventListener("onCameraCapture");
registerEventListener("Gecko:Ready");
registerEventListener("Gecko:DelayedStartup");
@@ -2102,17 +2101,16 @@ public abstract class GeckoApp
super.onRestart();
}
@Override
public void onDestroy()
{
unregisterEventListener("log");
- unregisterEventListener("Reader:ListCountRequest");
unregisterEventListener("Reader:ListStatusRequest");
unregisterEventListener("Reader:Added");
unregisterEventListener("Reader:Removed");
unregisterEventListener("Reader:Share");
unregisterEventListener("Reader:FaviconRequest");
unregisterEventListener("onCameraCapture");
unregisterEventListener("Gecko:Ready");
unregisterEventListener("Gecko:DelayedStartup");
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -141,17 +141,17 @@ public class BrowserToolbar extends Them
private boolean shouldShrinkURLBar = false;
private OnActivateListener activateListener;
private OnFocusChangeListener focusChangeListener;
private OnStartEditingListener startEditingListener;
private OnStopEditingListener stopEditingListener;
- final private BrowserApp activity;
+ private final BrowserApp activity;
private boolean hasSoftMenuButton;
private UIMode uiMode;
private boolean isAnimatingEntry;
private int urlBarViewOffset;
private int defaultForwardMargin;
@@ -576,17 +576,17 @@ public class BrowserToolbar extends Them
if (!isEditing() && selectedTab.getState() == Tab.STATE_LOADING) {
progressBar.setProgress(progress);
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
}
- public boolean isVisible() {
+ private boolean isVisible() {
return ViewHelper.getTranslationY(this) == 0;
}
@Override
public void setNextFocusDownId(int nextId) {
super.setNextFocusDownId(nextId);
tabsButton.setNextFocusDownId(nextId);
backButton.setNextFocusDownId(nextId);
@@ -1195,17 +1195,17 @@ public class BrowserToolbar extends Them
updateTabCountAndAnimate(Tabs.getInstance().getDisplayCount());
}
});
isAnimatingEntry = true;
contentAnimator.start();
}
- public void setButtonEnabled(ImageButton button, boolean enabled) {
+ private void setButtonEnabled(ImageButton button, boolean enabled) {
final Drawable drawable = button.getDrawable();
if (drawable != null) {
// This alpha value has to be in sync with the one used
// in updateChildrenForEditing().
drawable.setAlpha(enabled ? 255 : 61);
}
button.setEnabled(enabled);
--- a/mobile/android/base/toolbar/CanvasDelegate.java
+++ b/mobile/android/base/toolbar/CanvasDelegate.java
@@ -8,39 +8,39 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.os.Build;
-public class CanvasDelegate {
+class CanvasDelegate {
Paint mPaint;
PorterDuffXfermode mMode;
DrawManager mDrawManager;
// DrawManager would do a default draw of the background.
- public static interface DrawManager {
+ static interface DrawManager {
public void defaultDraw(Canvas cavas);
}
- public CanvasDelegate(DrawManager drawManager, Mode mode) {
+ CanvasDelegate(DrawManager drawManager, Mode mode) {
mDrawManager = drawManager;
// DST_IN masks, DST_OUT clips.
mMode = new PorterDuffXfermode(mode);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStrokeWidth(0.0f);
}
- public void draw(Canvas canvas, Path path, int width, int height) {
+ void draw(Canvas canvas, Path path, int width, int height) {
// Save the canvas. All PorterDuff operations should be done in a offscreen bitmap.
int count = canvas.saveLayer(0, 0, width, height, null,
Canvas.MATRIX_SAVE_FLAG |
Canvas.CLIP_SAVE_FLAG |
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
@@ -65,12 +65,12 @@ public class CanvasDelegate {
mPaint.setXfermode(null);
}
}
// Restore the canvas.
canvas.restoreToCount(count);
}
- public void setShader(Shader shader) {
+ void setShader(Shader shader) {
mPaint.setShader(shader);
}
}
--- a/mobile/android/base/toolbar/PageActionLayout.java
+++ b/mobile/android/base/toolbar/PageActionLayout.java
@@ -59,17 +59,17 @@ public class PageActionLayout extends Li
mPageActionList = new ArrayList<PageAction>();
setNumberShown(DEFAULT_PAGE_ACTIONS_SHOWN);
refreshPageActionIcons();
registerEventListener("PageActions:Add");
registerEventListener("PageActions:Remove");
}
- public void setNumberShown(int count) {
+ private void setNumberShown(int count) {
mMaxVisiblePageActions = count;
for(int index = 0; index < count; index++) {
if ((this.getChildCount() - 1) < index) {
mLayout.addView(createImageButton());
}
}
}
@@ -113,17 +113,17 @@ public class PageActionLayout extends Li
removePageAction(id);
}
} catch(JSONException ex) {
Log.e(LOGTAG, "Error deocding", ex);
}
}
- public void addPageAction(final String id, final String title, final String imageData, final OnPageActionClickListeners mOnPageActionClickListeners, boolean mImportant) {
+ private void addPageAction(final String id, final String title, final String imageData, final OnPageActionClickListeners mOnPageActionClickListeners, boolean mImportant) {
final PageAction pageAction = new PageAction(id, title, null, mOnPageActionClickListeners, mImportant);
int insertAt = mPageActionList.size();
while(insertAt > 0 && mPageActionList.get(insertAt-1).isImportant()) {
insertAt--;
}
mPageActionList.add(insertAt, pageAction);
@@ -133,17 +133,17 @@ public class PageActionLayout extends Li
if (mPageActionList.contains(pageAction)) {
pageAction.setDrawable(d);
refreshPageActionIcons();
}
}
});
}
- public void removePageAction(String id) {
+ private void removePageAction(String id) {
for(int i = 0; i < mPageActionList.size(); i++) {
if (mPageActionList.get(i).getID().equals(id)) {
mPageActionList.remove(i);
refreshPageActionIcons();
return;
}
}
}
@@ -286,17 +286,17 @@ public class PageActionLayout extends Li
PageAction pageAction = mPageActionList.get(i);
MenuItem item = menu.add(Menu.NONE, pageAction.key(), Menu.NONE, pageAction.getTitle());
item.setIcon(pageAction.getDrawable());
}
}
mPageActionsMenu.show();
}
- public static interface OnPageActionClickListeners {
+ private static interface OnPageActionClickListeners {
public void onClick(String id);
public boolean onLongClick(String id);
}
private static class PageAction {
private OnPageActionClickListeners mOnPageActionClickListeners;
private Drawable mDrawable;
private String mTitle;
--- a/mobile/android/base/toolbar/TabCounter.java
+++ b/mobile/android/base/toolbar/TabCounter.java
@@ -62,17 +62,17 @@ public class TabCounter extends ThemedTe
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {}
});
}
}
- public void setCountWithAnimation(int count) {
+ void setCountWithAnimation(int count) {
// Don't animate from initial state
if (mCount == 0) {
setCount(count);
return;
}
if (mCount == count) {
return;
@@ -92,17 +92,17 @@ public class TabCounter extends ThemedTe
// Set In value, trigger animation to Out value
setCurrentText(String.valueOf(mCount));
setText(String.valueOf(count));
mCount = count;
}
- public void setCount(int count) {
+ void setCount(int count) {
setCurrentText(String.valueOf(count));
mCount = count;
}
// Alpha animations in editing mode cause action bar corruption on the
// Nexus 7 (bug 961749). As a workaround, skip these animations in editing
// mode.
void onEnterEditingMode() {
--- a/mobile/android/base/toolbar/ToolbarDisplayLayout.java
+++ b/mobile/android/base/toolbar/ToolbarDisplayLayout.java
@@ -90,17 +90,17 @@ public class ToolbarDisplayLayout extend
interface OnStopListener {
public Tab onStop();
}
interface OnTitleChangeListener {
public void onTitleChange(CharSequence title);
}
- final private BrowserApp mActivity;
+ private final BrowserApp mActivity;
private UIMode mUiMode;
private ThemedTextView mTitle;
private int mTitlePadding;
private ToolbarTitlePrefs mTitlePrefs;
private OnTitleChangeListener mTitleChangeListener;
--- a/mobile/android/base/toolbar/ToolbarTitlePrefs.java
+++ b/mobile/android/base/toolbar/ToolbarTitlePrefs.java
@@ -6,18 +6,18 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.util.ThreadUtils;
class ToolbarTitlePrefs {
- public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
- public static final String PREF_TRIM_URLS = "browser.urlbar.trimURLs";
+ static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
+ static final String PREF_TRIM_URLS = "browser.urlbar.trimURLs";
interface OnChangeListener {
public void onChange();
}
final String[] prefs = {
PREF_TITLEBAR_MODE,
PREF_TRIM_URLS
--- a/mobile/android/chrome/content/aboutReader.html
+++ b/mobile/android/chrome/content/aboutReader.html
@@ -29,15 +29,14 @@
<li class="dropdown-popup">
<ul id="font-type-buttons"></ul>
<hr></hr>
<ul id="font-size-buttons" class="segmented-button"></ul>
<hr></hr>
<ul id="color-scheme-buttons" class="segmented-button"></ul>
</li>
</ul>
- <li><a id="list-button" class="button list-button" href="#"></a></li>
<li><a id="toggle-button" class="button toggle-button" href="#"></a></li>
</ul>
</body>
</html>
--- a/mobile/android/chrome/content/aboutReader.js
+++ b/mobile/android/chrome/content/aboutReader.js
@@ -2,19 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm")
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-// Panel ID defined in HomeConfig.java.
-const READING_LIST_PANEL_ID = "20f4549a-64ad-4c32-93e4-1dcef792733b";
-
XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow));
@@ -29,18 +26,16 @@ let AboutReader = function(doc, win) {
dump("Init()");
this._docRef = Cu.getWeakReference(doc);
this._winRef = Cu.getWeakReference(win);
Services.obs.addObserver(this, "Reader:FaviconReturn", false);
Services.obs.addObserver(this, "Reader:Add", false);
Services.obs.addObserver(this, "Reader:Remove", false);
- Services.obs.addObserver(this, "Reader:ListCountReturn", false);
- Services.obs.addObserver(this, "Reader:ListCountUpdated", false);
Services.obs.addObserver(this, "Reader:ListStatusReturn", false);
this._article = null;
dump("Feching toolbar, header and content notes from about:reader");
this._headerElementRef = Cu.getWeakReference(doc.getElementById("reader-header"));
this._domainElementRef = Cu.getWeakReference(doc.getElementById("reader-domain"));
this._titleElementRef = Cu.getWeakReference(doc.getElementById("reader-title"));
@@ -59,17 +54,16 @@ let AboutReader = function(doc, win) {
win.addEventListener("unload", this, false);
win.addEventListener("scroll", this, false);
win.addEventListener("popstate", this, false);
win.addEventListener("resize", this, false);
this._setupAllDropdowns();
this._setupButton("toggle-button", this._onReaderToggle.bind(this));
- this._setupButton("list-button", this._onList.bind(this));
this._setupButton("share-button", this._onShare.bind(this));
let colorSchemeOptions = [
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeDark"),
value: "dark"},
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeLight"),
value: "light"},
{ name: gStrings.GetStringFromName("aboutReader.colorSchemeAuto"),
@@ -122,21 +116,16 @@ let AboutReader = function(doc, win) {
dump("Decoding query arguments");
let queryArgs = this._decodeQueryString(win.location.href);
// Track status of reader toolbar add/remove toggle button
this._isReadingListItem = -1;
this._updateToggleButton();
- // Track status of reader toolbar list button
- this._readingListCount = -1;
- this._updateListButton();
- this._requestReadingListCount();
-
let url = queryArgs.url;
let tabId = queryArgs.tabId;
if (tabId) {
dump("Loading from tab with ID: " + tabId + ", URL: " + url);
this._loadFromTab(tabId, url);
} else {
dump("Fetching page with URL: " + url);
this._loadFromURL(url);
@@ -210,37 +199,16 @@ AboutReader.prototype = {
if (this._isReadingListItem != 0) {
this._isReadingListItem = 0;
this._updateToggleButton();
}
}
break;
}
- case "Reader:ListCountReturn":
- case "Reader:ListCountUpdated": {
- let count = parseInt(aData);
- if (this._readingListCount != count) {
- let isInitialStateChange = (this._readingListCount == -1);
- this._readingListCount = count;
- this._updateListButton();
-
- // Display the toolbar when all its initial component states are known
- if (isInitialStateChange) {
- this._setToolbarVisibility(true);
- }
-
- // Initial readinglist count is requested before any page is displayed
- if (this._article) {
- this._requestReadingListStatus();
- }
- }
- break;
- }
-
case "Reader:ListStatusReturn": {
let args = JSON.parse(aData);
if (args.url == this._article.url) {
if (this._isReadingListItem != args.inReadingList) {
let isInitialStateChange = (this._isReadingListItem == -1);
this._isReadingListItem = args.inReadingList;
this._updateToggleButton();
@@ -284,47 +252,31 @@ AboutReader.prototype = {
case "devicelight":
this._handleDeviceLight(aEvent.value);
break;
case "unload":
Services.obs.removeObserver(this, "Reader:Add");
Services.obs.removeObserver(this, "Reader:Remove");
- Services.obs.removeObserver(this, "Reader:ListCountReturn");
- Services.obs.removeObserver(this, "Reader:ListCountUpdated");
Services.obs.removeObserver(this, "Reader:ListStatusReturn");
break;
}
},
_updateToggleButton: function Reader_updateToggleButton() {
let classes = this._doc.getElementById("toggle-button").classList;
if (this._isReadingListItem == 1) {
classes.add("on");
} else {
classes.remove("on");
}
},
- _updateListButton: function Reader_updateListButton() {
- let classes = this._doc.getElementById("list-button").classList;
-
- if (this._readingListCount > 0) {
- classes.add("on");
- } else {
- classes.remove("on");
- }
- },
-
- _requestReadingListCount: function Reader_requestReadingListCount() {
- gChromeWin.sendMessageToJava({ type: "Reader:ListCountRequest" });
- },
-
_requestReadingListStatus: function Reader_requestReadingListStatus() {
gChromeWin.sendMessageToJava({
type: "Reader:ListStatusRequest",
url: this._article.url
});
},
_onReaderToggle: function Reader_onToggle() {
@@ -356,23 +308,16 @@ AboutReader.prototype = {
} else {
// In addition to removing the article from the cache (handled in
// browser.js), sending this message will cause the toggle button to be
// updated (handled in this file).
Services.obs.notifyObservers(null, "Reader:Remove", this._article.url);
}
},
- _onList: function Reader_onList() {
- if (!this._article || this._readingListCount < 1)
- return;
-
- gChromeWin.BrowserApp.loadURI("about:home?panel=" + READING_LIST_PANEL_ID);
- },
-
_onShare: function Reader_onShare() {
if (!this._article)
return;
gChromeWin.sendMessageToJava({
type: "Reader:Share",
url: this._article.url,
title: this._article.title
@@ -489,17 +434,17 @@ AboutReader.prototype = {
let win = this._win;
if (win.history.state)
win.history.back();
if (!this._toolbarEnabled)
return;
// Don't allow visible toolbar until banner state is known
- if (this._readingListCount == -1 || this._isReadingListItem == -1)
+ if (this._isReadingListItem == -1)
return;
if (this._getToolbarVisibility() === visible)
return;
this._toolbarElement.classList.toggle("toolbar-hidden");
this._setSystemUIVisibility(visible);
--- a/mobile/android/themes/core/aboutReader.css
+++ b/mobile/android/themes/core/aboutReader.css
@@ -341,17 +341,17 @@ body {
transition-property: visibility, opacity;
transition-duration: 0.7s;
visibility: hidden;
opacity: 0.0;
}
.toolbar > * {
float: right;
- width: 25%;
+ width: 33%;
}
.button {
color: white;
display: block;
background-position: center;
background-size: 30px 24px;
background-repeat: no-repeat;
@@ -491,24 +491,16 @@ body {
.toggle-button.on {
background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-mdpi.png');
}
.toggle-button {
background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-mdpi.png');
}
-.list-button.on {
- background-image: url('chrome://browser/skin/images/reader-list-on-icon-mdpi.png');
-}
-
-.list-button {
- background-image: url('chrome://browser/skin/images/reader-list-off-icon-mdpi.png');
-}
-
.share-button {
background-image: url('chrome://browser/skin/images/reader-share-icon-mdpi.png');
}
.style-button {
background-image: url('chrome://browser/skin/images/reader-style-icon-mdpi.png');
}
@@ -528,24 +520,16 @@ body {
.toggle-button.on {
background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-hdpi.png');
}
.toggle-button {
background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-hdpi.png');
}
- .list-button.on {
- background-image: url('chrome://browser/skin/images/reader-list-on-icon-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-off-icon-hdpi.png');
- }
-
.share-button {
background-image: url('chrome://browser/skin/images/reader-share-icon-hdpi.png');
}
.style-button {
background-image: url('chrome://browser/skin/images/reader-style-icon-hdpi.png');
}
}
@@ -566,24 +550,16 @@ body {
.toggle-button.on {
background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xhdpi.png');
}
.toggle-button {
background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xhdpi.png');
}
- .list-button.on {
- background-image: url('chrome://browser/skin/images/reader-list-on-icon-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-off-icon-xhdpi.png');
- }
-
.share-button {
background-image: url('chrome://browser/skin/images/reader-share-icon-xhdpi.png');
}
.style-button {
background-image: url('chrome://browser/skin/images/reader-style-icon-xhdpi.png');
}
}
deleted file mode 100644
index 0242843558b138642a03210b3b2d7d12b2e586eb..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index bcc26589ef113a7662b452aa1f0fce1d621000a5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index a356191a2312d7f839fc145ffac7dbc7a2759d82..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 52afbcff61f152fd28fd3a2bc82903a5faca551d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c93b4d6fe80011ee1abb0db457db44c4cc7e8e8f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f71552d8ffe560ec04f8548a003cd96fecb35b07..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/mobile/android/themes/core/jar.mn
+++ b/mobile/android/themes/core/jar.mn
@@ -74,22 +74,16 @@ chrome.jar:
skin/images/reader-plus-icon-hdpi.png (images/reader-plus-icon-hdpi.png)
skin/images/reader-plus-icon-xhdpi.png (images/reader-plus-icon-xhdpi.png)
skin/images/reader-minus-icon-mdpi.png (images/reader-minus-icon-mdpi.png)
skin/images/reader-minus-icon-hdpi.png (images/reader-minus-icon-hdpi.png)
skin/images/reader-minus-icon-xhdpi.png (images/reader-minus-icon-xhdpi.png)
skin/images/reader-dropdown-arrow-mdpi.png (images/reader-dropdown-arrow-mdpi.png)
skin/images/reader-dropdown-arrow-hdpi.png (images/reader-dropdown-arrow-hdpi.png)
skin/images/reader-dropdown-arrow-xhdpi.png (images/reader-dropdown-arrow-xhdpi.png)
- skin/images/reader-list-on-icon-mdpi.png (images/reader-list-on-icon-mdpi.png)
- skin/images/reader-list-on-icon-hdpi.png (images/reader-list-on-icon-hdpi.png)
- skin/images/reader-list-on-icon-xhdpi.png (images/reader-list-on-icon-xhdpi.png)
- skin/images/reader-list-off-icon-mdpi.png (images/reader-list-off-icon-mdpi.png)
- skin/images/reader-list-off-icon-hdpi.png (images/reader-list-off-icon-hdpi.png)
- skin/images/reader-list-off-icon-xhdpi.png (images/reader-list-off-icon-xhdpi.png)
skin/images/reader-toggle-on-icon-mdpi.png (images/reader-toggle-on-icon-mdpi.png)
skin/images/reader-toggle-on-icon-hdpi.png (images/reader-toggle-on-icon-hdpi.png)
skin/images/reader-toggle-on-icon-xhdpi.png (images/reader-toggle-on-icon-xhdpi.png)
skin/images/reader-toggle-off-icon-mdpi.png (images/reader-toggle-off-icon-mdpi.png)
skin/images/reader-toggle-off-icon-hdpi.png (images/reader-toggle-off-icon-hdpi.png)
skin/images/reader-toggle-off-icon-xhdpi.png (images/reader-toggle-off-icon-xhdpi.png)
skin/images/reader-share-icon-mdpi.png (images/reader-share-icon-mdpi.png)
skin/images/reader-share-icon-hdpi.png (images/reader-share-icon-hdpi.png)
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -540,48 +540,55 @@ FxAccountsInternal.prototype = {
* kA: An encryption key from the FxA server
* kB: An encryption key derived from the user's FxA password
* verified: email verification status
* }
* or null if no user is signed in
*/
getKeys: function() {
let currentState = this.currentAccountState;
- return currentState.getUserAccountData().then((data) => {
- if (!data) {
+ return currentState.getUserAccountData().then((userData) => {
+ if (!userData) {
throw new Error("Can't get keys; User is not signed in");
}
- if (data.kA && data.kB) {
- return data;
+ if (userData.kA && userData.kB) {
+ return userData;
}
if (!currentState.whenKeysReadyDeferred) {
currentState.whenKeysReadyDeferred = Promise.defer();
- this.fetchAndUnwrapKeys(data.keyFetchToken).then(
- data => {
- if (!data.kA || !data.kB) {
- currentState.whenKeysReadyDeferred.reject(
- new Error("user data missing kA or kB")
- );
- return;
+ if (userData.keyFetchToken) {
+ this.fetchAndUnwrapKeys(userData.keyFetchToken).then(
+ (dataWithKeys) => {
+ if (!dataWithKeys.kA || !dataWithKeys.kB) {
+ currentState.whenKeysReadyDeferred.reject(
+ new Error("user data missing kA or kB")
+ );
+ return;
+ }
+ currentState.whenKeysReadyDeferred.resolve(dataWithKeys);
+ },
+ (err) => {
+ currentState.whenKeysReadyDeferred.reject(err);
}
- currentState.whenKeysReadyDeferred.resolve(data);
- },
- err => currentState.whenKeysReadyDeferred.reject(err)
- );
+ );
+ } else {
+ currentState.whenKeysReadyDeferred.reject('No keyFetchToken');
+ }
}
return currentState.whenKeysReadyDeferred.promise;
}).then(result => currentState.resolve(result));
},
fetchAndUnwrapKeys: function(keyFetchToken) {
log.debug("fetchAndUnwrapKeys: token: " + keyFetchToken);
let currentState = this.currentAccountState;
return Task.spawn(function* task() {
// Sign out if we don't have a key fetch token.
if (!keyFetchToken) {
+ log.warn("improper fetchAndUnwrapKeys() call: token missing");
yield this.signOut();
return null;
}
let {kA, wrapKB} = yield this.fetchKeys(keyFetchToken);
let data = yield currentState.getUserAccountData();
--- a/services/fxaccounts/tests/xpcshell/test_accounts.js
+++ b/services/fxaccounts/tests/xpcshell/test_accounts.js
@@ -300,34 +300,34 @@ add_test(function test_getKeys() {
do_test_finished();
run_next_test();
});
});
});
});
});
-// getKeys with no keyFetchToken should trigger signOut
-add_test(function test_getKeys_no_token() {
+// fetchAndUnwrapKeys with no keyFetchToken should trigger signOut
+add_test(function test_fetchAndUnwrapKeys_no_token() {
do_test_pending();
let fxa = new MockFxAccounts();
let user = getTestUser("lettuce.protheroe");
delete user.keyFetchToken
makeObserver(ONLOGOUT_NOTIFICATION, function() {
- log.debug("test_getKeys_no_token observed logout");
+ log.debug("test_fetchAndUnwrapKeys_no_token observed logout");
fxa.internal.getUserAccountData().then(user => {
do_test_finished();
run_next_test();
});
});
fxa.setSignedInUser(user).then((user) => {
- fxa.internal.getKeys();
+ fxa.internal.fetchAndUnwrapKeys();
});
});
// Alice (User A) signs up but never verifies her email. Then Bob (User B)
// signs in with a verified email. Ensure that no sign-in events are triggered
// on Alice's behalf. In the end, Bob should be the signed-in user.
add_test(function test_overlapping_signins() {
do_test_pending();
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -555,16 +555,17 @@ add_task(function test_getKeysMissing()
_("BrowserIDManager correctly handles getKeys succeeding but not returning keys.");
let browseridManager = new BrowserIDManager();
let identityConfig = makeIdentityConfig();
// our mock identity config already has kA and kB - remove them or we never
// try and fetch them.
delete identityConfig.fxaccount.user.kA;
delete identityConfig.fxaccount.user.kB;
+ identityConfig.fxaccount.user.keyFetchToken = 'keyFetchToken';
configureFxAccountIdentity(browseridManager, identityConfig);
// Mock a fxAccounts object that returns no keys
let fxa = new FxAccounts({
fetchAndUnwrapKeys: function () {
return Promise.resolve({});
},
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -24,17 +24,17 @@ this.EXPORTED_SYMBOLS = ["DebuggerTransp
"EnvironmentClient",
"ObjectClient"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
+let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js").Promise;
const { defer, resolve, reject } = promise;
XPCOMUtils.defineLazyServiceGetter(this, "socketTransportService",
"@mozilla.org/network/socket-transport-service;1",
"nsISocketTransportService");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/deprecated-sync-thenables.js
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * THIS MODULE IS DEPRECATED. IMPORT "Promise.jsm" INSTEAD.
+ */
+
+"use strict";
+
+this.Promise = {};
+
+if (typeof(require) === "function") {
+ module.exports = Promise;
+} else {
+ this.EXPORTED_SYMBOLS = ["Promise"];
+}
+
+function fulfilled(value) {
+ return { then: function then(fulfill) { fulfill(value); } };
+}
+
+function rejected(reason) {
+ return { then: function then(fulfill, reject) { reject(reason); } };
+}
+
+function isPromise(value) {
+ return value && typeof(value.then) === 'function';
+}
+
+function defer() {
+ var observers = [];
+ var result = null;
+ var promise = {
+ then: function then(onFulfill, onError) {
+ var deferred = defer();
+
+ function resolve(value) {
+ try {
+ deferred.resolve(onFulfill ? onFulfill(value) : value);
+ } catch (error) {
+ deferred.resolve(rejected(error));
+ }
+ }
+
+ function reject(reason) {
+ try {
+ if (onError) deferred.resolve(onError(reason));
+ else deferred.resolve(rejected(reason));
+ } catch (error) {
+ deferred.resolve(rejected(error));
+ }
+ }
+
+ if (observers) {
+ observers.push({ resolve: resolve, reject: reject });
+ } else {
+ result.then(resolve, reject);
+ }
+
+ return deferred.promise;
+ }
+ };
+
+ var deferred = {
+ promise: promise,
+ resolve: function resolve(value) {
+ if (!result) {
+ result = isPromise(value) ? value : fulfilled(value);
+ while (observers.length) {
+ var observer = observers.shift();
+ result.then(observer.resolve, observer.reject);
+ }
+ observers = null;
+ }
+ },
+ reject: function reject(reason) {
+ deferred.resolve(rejected(reason));
+ }
+ };
+
+ return deferred;
+}
+Promise.defer = defer;
+
+function resolve(value) {
+ var deferred = defer();
+ deferred.resolve(value);
+ return deferred.promise;
+}
+Promise.resolve = resolve;
+
+function reject(reason) {
+ var deferred = defer();
+ deferred.reject(reason);
+ return deferred.promise;
+}
+Promise.reject = reject;
+
+var promised = (function() {
+ var call = Function.call;
+ var concat = Array.prototype.concat;
+ function execute(args) { return call.apply(call, args) }
+ function promisedConcat(promises, unknown) {
+ return promises.then(function(values) {
+ return resolve(unknown).then(function(value) {
+ return values.concat([ value ]);
+ });
+ });
+ }
+ return function promised(f) {
+ return function promised() {
+ return concat.apply([ f, this ], arguments).
+ reduce(promisedConcat, resolve([])).
+ then(execute);
+ };
+ }
+})();
+Promise.all = promised(Array);
--- a/toolkit/devtools/gcli/source/lib/gcli/util/promise.js
+++ b/toolkit/devtools/gcli/source/lib/gcli/util/promise.js
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var Cu = require('chrome').Cu;
module.exports = exports =
- Cu.import('resource://gre/modules/commonjs/sdk/core/promise.js', {}).Promise;
+ Cu.import('resource://gre/modules/devtools/deprecated-sync-thenables.js', {}).Promise;
// When we've solved the debugger/sdk/promise/gcli/helpers/overlap problem then
// we should use this instead:
// module.exports = exports = require('resource://gre/modules/Promise.jsm').Promise;
--- a/toolkit/devtools/server/actors/childtab.js
+++ b/toolkit/devtools/server/actors/childtab.js
@@ -17,27 +17,28 @@
*
* @param connection DebuggerServerConnection
* The conection to the client.
* @param chromeGlobal
* The content script global holding |content| and |docShell| properties for a tab.
*/
function ContentActor(connection, chromeGlobal)
{
+ this._chromeGlobal = chromeGlobal;
TabActor.call(this, connection, chromeGlobal);
this.traits.reconfigure = false;
}
ContentActor.prototype = Object.create(TabActor.prototype);
ContentActor.prototype.constructor = ContentActor;
Object.defineProperty(ContentActor.prototype, "docShell", {
get: function() {
- return this.chromeEventHandler.docShell;
+ return this._chromeGlobal.docShell;
},
enumerable: true,
configurable: false
});
ContentActor.prototype.exit = function() {
TabActor.prototype.exit.call(this);
};
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -771,74 +771,16 @@ let traversalMethod = {
whatToShow: Option(1)
},
response: {
node: RetVal("nullable:domnode")
}
}
/**
- * We need to know when a document is navigating away so that we can kill
- * the nodes underneath it. We also need to know when a document is
- * navigated to so that we can send a mutation event for the iframe node.
- *
- * The nsIWebProgressListener is the easiest/best way to watch these
- * loads that works correctly with the bfcache.
- *
- * See nsIWebProgressListener for details
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIWebProgressListener
- */
-var ProgressListener = Class({
- extends: Unknown,
- interfaces: ["nsIWebProgressListener", "nsISupportsWeakReference"],
-
- initialize: function(tabActor) {
- Unknown.prototype.initialize.call(this);
- this.webProgress = tabActor.webProgress;
- this.webProgress.addProgressListener(
- this, Ci.nsIWebProgress.NOTIFY_ALL
- );
- },
-
- destroy: function() {
- try {
- this.webProgress.removeProgressListener(this);
- } catch(ex) {
- // This can throw during browser shutdown.
- }
- this.webProgress = null;
- },
-
- onStateChange: makeInfallible(function stateChange(progress, request, flags, status) {
- if (!this.webProgress) {
- console.warn("got an onStateChange after destruction");
- return;
- }
-
- let isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
- let isDocument = flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
- if (!(isWindow || isDocument)) {
- return;
- }
-
- if (isDocument && (flags & Ci.nsIWebProgressListener.STATE_START)) {
- events.emit(this, "windowchange-start", progress.DOMWindow);
- }
- if (isWindow && (flags & Ci.nsIWebProgressListener.STATE_STOP)) {
- events.emit(this, "windowchange-stop", progress.DOMWindow);
- }
- }),
-
- onProgressChange: function() {},
- onSecurityChange: function() {},
- onStatusChange: function() {},
- onLocationChange: function() {},
-});
-
-/**
* Server side of the DOM walker.
*/
var WalkerActor = protocol.ActorClass({
typeName: "domwalker",
events: {
"new-mutations" : {
type: "newMutations"
@@ -884,20 +826,18 @@ var WalkerActor = protocol.ActorClass({
// even when it is orphaned with the `retainNode` method. This
// list contains orphaned nodes that were so retained.
this._retainedOrphans = new Set();
this.onMutations = this.onMutations.bind(this);
this.onFrameLoad = this.onFrameLoad.bind(this);
this.onFrameUnload = this.onFrameUnload.bind(this);
- this.progressListener = ProgressListener(tabActor);
-
- events.on(this.progressListener, "windowchange-start", this.onFrameUnload);
- events.on(this.progressListener, "windowchange-stop", this.onFrameLoad);
+ events.on(tabActor, "will-navigate", this.onFrameUnload);
+ events.on(tabActor, "navigate", this.onFrameLoad);
// Ensure that the root document node actor is ready and
// managed.
this.rootNode = this.document();
},
// Returns the JSON representation of this object over the wire.
form: function() {
@@ -910,17 +850,16 @@ var WalkerActor = protocol.ActorClass({
toString: function() {
return "[WalkerActor " + this.actorID + "]";
},
destroy: function() {
this._hoveredNode = null;
this.clearPseudoClassLocks();
this._activePseudoClassLocks = null;
- this.progressListener.destroy();
this.rootDoc = null;
events.emit(this, "destroyed");
protocol.Actor.prototype.destroy.call(this);
},
release: method(function() {}, { release: true }),
unmanage: function(actor) {
@@ -1961,27 +1900,26 @@ var WalkerActor = protocol.ActorClass({
mutation.numChildren = change.target.childNodes.length;
mutation.removed = removedActors;
mutation.added = addedActors;
}
this.queueMutation(mutation);
}
},
- onFrameLoad: function(window) {
- let frame = this.layoutHelpers.getFrameElement(window);
- let isTopLevel = this.layoutHelpers.isTopLevelWindow(window);
- if (!frame && !this.rootDoc && isTopLevel) {
+ onFrameLoad: function({ window, isTopLevel }) {
+ if (!this.rootDoc && isTopLevel) {
this.rootDoc = window.document;
this.rootNode = this.document();
this.queueMutation({
type: "newRoot",
target: this.rootNode.form()
});
}
+ let frame = this.layoutHelpers.getFrameElement(window);
let frameActor = this._refMap.get(frame);
if (!frameActor) {
return;
}
this.queueMutation({
type: "frameLoad",
target: frameActor.actorID,
@@ -2003,17 +1941,17 @@ var WalkerActor = protocol.ActorClass({
if (win === window) {
return true;
}
win = this.layoutHelpers.getFrameElement(win);
}
return false;
},
- onFrameUnload: function(window) {
+ onFrameUnload: function({ window }) {
// Any retained orphans that belong to this document
// or its children need to be released, and a mutation sent
// to notify of that.
let releasedOrphans = [];
for (let retained of this._retainedOrphans) {
if (Cu.isDeadWrapper(retained.rawNode) ||
this._childOfWindow(window, retained.rawNode)) {
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -5,16 +5,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let {Cu} = require("chrome");
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
+// Assumptions on events module:
+// events needs to be dispatched synchronously,
+// by calling the listeners in the order or registration.
+XPCOMUtils.defineLazyGetter(this, "events", () => {
+ return devtools.require("sdk/event/core");
+});
+
/**
* Browser-specific actors.
*/
/**
* Yield all windows of type |aWindowType|, from the oldest window to the
* youngest, using nsIWindowMediator::getEnumerator. We're usually
* interested in "navigator:browser" windows.
@@ -480,36 +487,34 @@ BrowserTabList.prototype.onCloseWindow =
* ContentActor. Subclasses are expected to implement a getter
* the docShell properties.
*
* @param aConnection DebuggerServerConnection
* The conection to the client.
* @param aChromeEventHandler
* An object on which listen for DOMWindowCreated and pageshow events.
*/
-function TabActor(aConnection, aChromeEventHandler)
+function TabActor(aConnection)
{
this.conn = aConnection;
- this._chromeEventHandler = aChromeEventHandler;
this._tabActorPool = null;
// A map of actor names to actor instances provided by extensions.
this._extraActors = {};
-
- this._onWindowCreated = this.onWindowCreated.bind(this);
+ this._exited = false;
this.traits = { reconfigure: true };
}
// XXX (bug 710213): TabActor attach/detach/exit/disconnect is a
// *complete* mess, needs to be rethought asap.
TabActor.prototype = {
traits: null,
- get exited() { return !this._chromeEventHandler; },
+ get exited() { return this._exited; },
get attached() { return !!this._attached; },
_tabPool: null,
get tabActorPool() { return this._tabPool; },
_contextPool: null,
get contextActorPool() { return this._contextPool; },
@@ -517,17 +522,20 @@ TabActor.prototype = {
// A constant prefix that will be used to form the actor ID by the server.
actorPrefix: "tab",
/**
* An object on which listen for DOMWindowCreated and pageshow events.
*/
get chromeEventHandler() {
- return this._chromeEventHandler;
+ // TODO: bug 992778, fix docShell.chromeEventHandler in child processes
+ return this.docShell.chromeEventHandler ||
+ this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIContentFrameMessageManager);
},
/**
* Getter for the nsIMessageManager associated to the tab.
*/
get messageManager() {
return this._chromeEventHandler;
},
@@ -626,33 +634,33 @@ TabActor.prototype = {
},
/**
* Called when the actor is removed from the connection.
*/
disconnect: function BTA_disconnect() {
this._detach();
this._extraActors = null;
- this._chromeEventHandler = null;
+ this._exited = true;
},
/**
* Called by the root actor when the underlying tab is closed.
*/
exit: function BTA_exit() {
if (this.exited) {
return;
}
if (this._detach()) {
this.conn.send({ from: this.actorID,
type: "tabDetached" });
}
- this._chromeEventHandler = null;
+ this._exited = true;
},
/* Support for DebuggerServer.addTabActor. */
_createExtraActors: CommonCreateExtraActors,
_appendExtraActors: CommonAppendExtraActors,
/**
* Does the actual work of attching to a tab.
@@ -665,20 +673,18 @@ TabActor.prototype = {
// Create a pool for tab-lifetime actors.
dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
this._tabPool = new ActorPool(this.conn);
this.conn.addActorPool(this._tabPool);
// ... and a pool for context-lifetime actors.
this._pushContext();
- // Watch for globals being created in this tab.
- this.chromeEventHandler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
- this.chromeEventHandler.addEventListener("pageshow", this._onWindowCreated, true);
this._progressListener = new DebuggerProgressListener(this);
+ this._progressListener.watch(this.docShell);
this._attached = true;
},
/**
* Creates a thread actor and a pool for context-lifetime actors. It then sets
* up the content window for debugging.
*/
@@ -710,20 +716,22 @@ TabActor.prototype = {
*
* @returns false if the tab wasn't attached or true of detahing succeeds.
*/
_detach: function BTA_detach() {
if (!this.attached) {
return false;
}
- this._progressListener.destroy();
-
- this.chromeEventHandler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
- this.chromeEventHandler.removeEventListener("pageshow", this._onWindowCreated, true);
+ // Check for docShell availability, as it can be already gone
+ // during Firefox shutdown.
+ if (this.docShell) {
+ this._progressListener.unwatch(this.docShell);
+ }
+ this._progressListener = null;
this._popContext();
// Shut down actors that belong to this tab's pool.
this.conn.removeActorPool(this._tabPool);
this._tabPool = null;
if (this._tabActorPool) {
this.conn.removeActorPool(this._tabActorPool);
@@ -904,38 +912,126 @@ TabActor.prototype = {
}
},
/**
* Handle location changes, by clearing the previous debuggees and enabling
* debugging, which may have been disabled temporarily by the
* DebuggerProgressListener.
*/
- onWindowCreated:
- DevToolsUtils.makeInfallible(function BTA_onWindowCreated(evt) {
- // pageshow events for non-persisted pages have already been handled by a
- // prior DOMWindowCreated event.
- if (!this._attached || (evt.type == "pageshow" && !evt.persisted)) {
- return;
- }
- if (evt.target === this.contentDocument) {
- this.threadActor.clearDebuggees();
- if (this.threadActor.dbg) {
- this.threadActor.dbg.enabled = true;
- this.threadActor.global = evt.target.defaultView;
- this.threadActor.maybePauseOnExceptions();
+ _windowReady: function (window) {
+ let isTopLevel = window == this.window;
+ dumpn("window-ready: " + window.location + " isTopLevel:" + isTopLevel);
+
+ events.emit(this, "window-ready", {
+ window: window,
+ isTopLevel: isTopLevel
+ });
+
+ // TODO bug 997119: move that code to ThreadActor by listening to window-ready
+ let threadActor = this.threadActor;
+ if (isTopLevel) {
+ threadActor.clearDebuggees();
+ if (threadActor.dbg) {
+ threadActor.dbg.enabled = true;
+ threadActor.global = window;
+ threadActor.maybePauseOnExceptions();
}
}
// Refresh the debuggee list when a new window object appears (top window or
// iframe).
- if (this.threadActor.attached) {
- this.threadActor.findGlobals();
+ if (threadActor.attached) {
+ threadActor.findGlobals();
+ }
+ },
+
+ /**
+ * Start notifying server codebase and client about a new document
+ * being loaded in the currently targeted context.
+ */
+ _willNavigate: function (window, newURI, request) {
+ let isTopLevel = window == this.window;
+
+ // will-navigate event needs to be dispatched synchronously,
+ // by calling the listeners in the order or registration.
+ // This event fires once navigation starts,
+ // (all pending user prompts are dealt with),
+ // but before the first request starts.
+ events.emit(this, "will-navigate", {
+ window: window,
+ isTopLevel: isTopLevel,
+ newURI: newURI,
+ request: request
+ });
+
+
+ // We don't do anything for inner frames in TabActor.
+ // (we will only update thread actor on window-ready)
+ if (!isTopLevel) {
+ return;
+ }
+
+ // Proceed normally only if the debuggee is not paused.
+ // TODO bug 997119: move that code to ThreadActor by listening to will-navigate
+ let threadActor = this.threadActor;
+ if (request && threadActor.state == "paused") {
+ request.suspend();
+ threadActor.onResume();
+ threadActor.dbg.enabled = false;
+ this._pendingNavigation = request;
}
- }, "TabActor.prototype.onWindowCreated"),
+ threadActor.disableAllBreakpoints();
+
+ this.conn.send({
+ from: this.actorID,
+ type: "tabNavigated",
+ url: newURI,
+ nativeConsoleAPI: true,
+ state: "start"
+ });
+ },
+
+ /**
+ * Notify server and client about a new document done loading in the current
+ * targeted context.
+ */
+ _navigate: function (window) {
+ let isTopLevel = window == this.window;
+
+ // navigate event needs to be dispatched synchronously,
+ // by calling the listeners in the order or registration.
+ // This event is fired once the document is loaded,
+ // after the load event, it's document ready-state is 'complete'.
+ events.emit(this, "navigate", {
+ window: window,
+ isTopLevel: isTopLevel
+ });
+
+ // We don't do anything for inner frames in TabActor.
+ // (we will only update thread actor on window-ready)
+ if (!isTopLevel) {
+ return;
+ }
+
+ // TODO bug 997119: move that code to ThreadActor by listening to navigate
+ let threadActor = this.threadActor;
+ if (threadActor.state == "running") {
+ threadActor.dbg.enabled = true;
+ }
+
+ this.conn.send({
+ from: this.actorID,
+ type: "tabNavigated",
+ url: this.url,
+ title: this.title,
+ nativeConsoleAPI: this.hasNativeConsoleAPI(this.window),
+ state: "stop"
+ });
+ },
/**
* Tells if the window.console object is native or overwritten by script in
* the page.
*
* @param nsIDOMWindow aWindow
* The window object you want to check.
* @return boolean
@@ -994,22 +1090,25 @@ Object.defineProperty(BrowserTabActor.pr
return this._browser.messageManager;
},
enumerable: true,
configurable: false
});
Object.defineProperty(BrowserTabActor.prototype, "title", {
get: function() {
- let title = this.contentDocument.contentTitle;
+ let title = this.contentDocument.title || this._browser.contentTitle;
// If contentTitle is empty (e.g. on a not-yet-restored tab), but there is a
// tabbrowser (i.e. desktop Firefox, but not Fennec), we can use the label
// as the title.
if (!title && this._tabbrowser) {
- title = this._tabbrowser._getTabForContentWindow(this.window).label;
+ let tab = this._tabbrowser._getTabForContentWindow(this.window);
+ if (tab) {
+ title = tab.label;
+ }
}
return title;
},
enumerable: true,
configurable: false
});
Object.defineProperty(BrowserTabActor.prototype, "browser", {
@@ -1249,87 +1348,91 @@ BrowserAddonActor.prototype.requestTypes
* navigate away from a paused page, the listener makes sure that the debuggee
* is resumed before the navigation begins.
*
* @param TabActor aTabActor
* The tab actor associated with this listener.
*/
function DebuggerProgressListener(aTabActor) {
this._tabActor = aTabActor;
- this._tabActor.webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_ALL);
- let EventEmitter = devtools.require("devtools/toolkit/event-emitter");
- EventEmitter.decorate(this);
+ this._onWindowCreated = this.onWindowCreated.bind(this);
}
DebuggerProgressListener.prototype = {
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference,
Ci.nsISupports,
]),
- onStateChange:
- DevToolsUtils.makeInfallible(function DPL_onStateChange(aProgress, aRequest, aFlag, aStatus) {
- let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
- let isStop = aFlag & Ci.nsIWebProgressListener.STATE_STOP;
- let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
- let isNetwork = aFlag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
- let isRequest = aFlag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
- let isWindow = aFlag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
+ watch: function DPL_watch(docShell) {
+ let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebProgress);
+ webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATUS |
+ Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
+ Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+
+ // TODO: fix docShell.chromeEventHandler in child processes!
+ let chromeEventHandler = docShell.chromeEventHandler ||
+ docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIContentFrameMessageManager);
+
+ // Watch for globals being created in this docshell tree.
+ chromeEventHandler.addEventListener("DOMWindowCreated",
+ this._onWindowCreated, true);
+ chromeEventHandler.addEventListener("pageshow",
+ this._onWindowCreated, true);
+ },
- // Skip non-interesting states.
- if (!isWindow || !isNetwork ||
- aProgress.DOMWindow != this._tabActor.window) {
+ unwatch: function DPL_unwatch(docShell) {
+ let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebProgress);
+ webProgress.removeProgressListener(this);
+
+ // TODO: fix docShell.chromeEventHandler in child processes!
+ let chromeEventHandler = docShell.chromeEventHandler ||
+ docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIContentFrameMessageManager);
+ chromeEventHandler.removeEventListener("DOMWindowCreated",
+ this._onWindowCreated, true);
+ chromeEventHandler.removeEventListener("pageshow",
+ this._onWindowCreated, true);
+ },
+
+ onWindowCreated:
+ DevToolsUtils.makeInfallible(function DPL_onWindowCreated(evt) {
+ // Ignore any event if the tab actor isn't attached.
+ if (!this._tabActor.attached) {
return;
}
- if (isStart && aRequest instanceof Ci.nsIChannel) {
- // Proceed normally only if the debuggee is not paused.
- if (this._tabActor.threadActor.state == "paused") {
- aRequest.suspend();
- this._tabActor.threadActor.onResume();
- this._tabActor.threadActor.dbg.enabled = false;
- this._tabActor._pendingNavigation = aRequest;
- }
-
- let packet = {
- from: this._tabActor.actorID,
- type: "tabNavigated",
- url: aRequest.URI.spec,
- nativeConsoleAPI: true,
- state: "start"
- };
- this._tabActor.threadActor.disableAllBreakpoints();
- this._tabActor.conn.send(packet);
- this.emit("will-navigate", packet);
- } else if (isStop) {
- if (this._tabActor.threadActor.state == "running") {
- this._tabActor.threadActor.dbg.enabled = true;
- }
-
- let window = this._tabActor.window;
- let packet = {
- from: this._tabActor.actorID,
- type: "tabNavigated",
- url: this._tabActor.url,
- title: this._tabActor.title,
- nativeConsoleAPI: this._tabActor.hasNativeConsoleAPI(window),
- state: "stop"
- };
- this._tabActor.conn.send(packet);
- this.emit("navigate", packet);
- }
- }, "DebuggerProgressListener.prototype.onStateChange"),
-
- /**
- * Destroy the progress listener instance.
- */
- destroy: function DPL_destroy() {
- try {
- this._tabActor.webProgress.removeProgressListener(this);
- } catch (ex) {
- // This can throw during browser shutdown.
+ // pageshow events for non-persisted pages have already been handled by a
+ // prior DOMWindowCreated event.
+ if (evt.type == "pageshow" && !evt.persisted) {
+ return;
}
- this._tabActor._progressListener = null;
- this._tabActor = null;
- }
+ let window = evt.target.defaultView;
+ this._tabActor._windowReady(window);
+ }, "DebuggerProgressListener.prototype.onWindowCreated"),
+
+ onStateChange:
+ DevToolsUtils.makeInfallible(function DPL_onStateChange(aProgress, aRequest, aFlag, aStatus) {
+ // Ignore any event if the tab actor isn't attached.
+ if (!this._tabActor.attached) {
+ return;
+ }
+
+ let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
+ let isStop = aFlag & Ci.nsIWebProgressListener.STATE_STOP;
+ let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
+ let isWindow = aFlag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
+
+ let window = aProgress.DOMWindow;
+ if (isDocument && isStart) {
+ let newURI = aRequest instanceof Ci.nsIChannel ? aRequest.URI.spec : null;
+ this._tabActor._willNavigate(window, newURI, aRequest);
+ }
+ if (isWindow && isStop) {
+ this._tabActor._navigate(window);
+ }
+ }, "DebuggerProgressListener.prototype.onStateChange")
};
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -232,18 +232,18 @@ WebConsoleActor.prototype =
_evalWindow: null,
get evalWindow() {
return this._evalWindow || this.window;
},
set evalWindow(aWindow) {
this._evalWindow = aWindow;
- if (!this._progressListenerActive && this.parentActor._progressListener) {
- this.parentActor._progressListener.once("will-navigate", this._onWillNavigate);
+ if (!this._progressListenerActive) {
+ events.on(this.parentActor, "will-navigate", this._onWillNavigate);
this._progressListenerActive = true;
}
},
/**
* Flag used to track if we are listening for events from the progress
* listener of the tab actor. We use the progress listener to clear
* this.evalWindow on page navigation.
@@ -1369,20 +1369,23 @@ WebConsoleActor.prototype =
break;
}
},
/**
* The "will-navigate" progress listener. This is used to clear the current
* eval scope.
*/
- _onWillNavigate: function WCA__onWillNavigate()
+ _onWillNavigate: function WCA__onWillNavigate({ window, isTopLevel })
{
- this._evalWindow = null;
- this._progressListenerActive = false;
+ if (isTopLevel) {
+ this._evalWindow = null;
+ events.off(this.parentActor, "will-navigate", this._onWillNavigate);
+ this._progressListenerActive = false;
+ }
},
};
WebConsoleActor.prototype.requestTypes =
{
startListeners: WebConsoleActor.prototype.onStartListeners,
stopListeners: WebConsoleActor.prototype.onStopListeners,
getCachedMessages: WebConsoleActor.prototype.onGetCachedMessages,
--- a/toolkit/devtools/server/main.js
+++ b/toolkit/devtools/server/main.js
@@ -42,17 +42,17 @@ Object.defineProperty(this, "Components"
const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties";
const nsFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
Cu.import("resource://gre/modules/reflect.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
dumpn.wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
-Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
+Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js");
function loadSubScript(aURL)
{
try {
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript(aURL, this);
} catch(e) {
@@ -61,21 +61,20 @@ function loadSubScript(aURL)
e + " - " + e.stack + "\n";
dump(errorStr);
Cu.reportError(errorStr);
throw e;
}
}
let events = require("sdk/event/core");
-let {defer, resolve, reject, promised, all} = require("sdk/core/promise");
+let {defer, resolve, reject, all} = require("devtools/toolkit/deprecated-sync-thenables");
this.defer = defer;
this.resolve = resolve;
this.reject = reject;
-this.promised = promised;
this.all = all;
Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
XPCOMUtils.defineLazyGetter(this, "NetworkMonitorManager", () => {
--- a/toolkit/devtools/server/protocol.js
+++ b/toolkit/devtools/server/protocol.js
@@ -1,17 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let {Cu} = require("chrome");
let Services = require("Services");
-let promise = require("sdk/core/promise");
+let promise = require("devtools/toolkit/deprecated-sync-thenables");
let {Class} = require("sdk/core/heritage");
let {EventTarget} = require("sdk/event/target");
let events = require("sdk/event/core");
let object = require("sdk/util/object");
// Waiting for promise.done() to be added, see bug 851321
function promiseDone(err) {
console.error(err);
--- a/toolkit/devtools/server/tests/browser/browser.ini
+++ b/toolkit/devtools/server/tests/browser/browser.ini
@@ -3,12 +3,15 @@ skip-if = e10s # Bug ?????? - devtools t
subsuite = devtools
support-files =
head.js
storage-dynamic-windows.html
storage-listings.html
storage-unsecured-iframe.html
storage-updates.html
storage-secured-iframe.html
+ navigate-first.html
+ navigate-second.html
[browser_storage_dynamic_windows.js]
[browser_storage_listings.js]
[browser_storage_updates.js]
+[browser_navigateEvents.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/browser/browser_navigateEvents.js
@@ -0,0 +1,169 @@
+
+let Cu = Components.utils;
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+
+const URL1 = MAIN_DOMAIN + "navigate-first.html";
+const URL2 = MAIN_DOMAIN + "navigate-second.html";
+
+let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
+let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+
+let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+let events = devtools.require("sdk/event/core");
+
+let client;
+
+// State machine to check events order
+let i = 0;
+function assertEvent(event, data) {
+ let x = 0;
+ switch(i++) {
+ case x++:
+ is(event, "request", "Get first page load");
+ is(data, URL1);
+ break;
+ case x++:
+ is(event, "load-new-document", "Ask to load the second page");
+ break;
+ case x++:
+ is(event, "unload-dialog", "We get the dialog on first page unload");
+ break;
+ case x++:
+ is(event, "will-navigate", "The very first event is will-navigate on server side");
+ is(data.newURI, URL2, "newURI property is correct");
+ break;
+ case x++:
+ is(event, "tabNavigated", "Right after will-navigate, the client receive tabNavigated");
+ is(data.state, "start", "state is start");
+ is(data.url, URL2, "url property is correct");
+ break;
+ case x++:
+ is(event, "request", "Given that locally, the Debugger protocol is sync, the request happens after tabNavigated");
+ is(data, URL2);
+ break;
+ case x++:
+ is(event, "DOMContentLoaded");
+ is(content.document.readyState, "interactive");
+ break;
+ case x++:
+ is(event, "load");
+ is(content.document.readyState, "complete");
+ break;
+ case x++:
+ is(event, "navigate", "Then once the second doc is loaded, we get the navigate event");
+ is(content.document.readyState, "complete", "navigate is emitted only once the document is fully loaded");
+ break;
+ case x++:
+ is(event, "tabNavigated", "Finally, the receive the client event");
+ is(data.state, "stop", "state is stop");
+ is(data.url, URL2, "url property is correct");
+
+ // End of test!
+ cleanup();
+ break;
+ }
+}
+
+function waitForOnBeforeUnloadDialog(browser, callback) {
+ browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() {
+ browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true);
+
+ executeSoon(() => {
+ let stack = browser.parentNode;
+ let dialogs = stack.getElementsByTagName("tabmodalprompt");
+ let {button0, button1} = dialogs[0].ui;
+ callback(button0, button1);
+ });
+ }, true);
+}
+
+let httpObserver = function (subject, topic, state) {
+ let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+ let url = channel.URI.spec;
+ // Only listen for our document request, as many other requests can happen
+ if (url == URL1 || url == URL2) {
+ assertEvent("request", url);
+ }
+};
+Services.obs.addObserver(httpObserver, "http-on-modify-request", false);
+
+function onDOMContentLoaded() {
+ assertEvent("DOMContentLoaded");
+}
+function onLoad() {
+ assertEvent("load");
+}
+
+function getServerTabActor(callback) {
+ // Ensure having a minimal server
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init(function () { return true; });
+ DebuggerServer.addBrowserActors();
+ }
+
+ // Connect to this tab
+ let transport = DebuggerServer.connectPipe();
+ client = new DebuggerClient(transport);
+ client.connect(function onConnect() {
+ client.listTabs(function onListTabs(aResponse) {
+ // Fetch the BrowserTabActor for this tab
+ let actorID = aResponse.tabs[aResponse.selected].actor;
+ client.attachTab(actorID, function(aResponse, aTabClient) {
+ // !Hack! Retrieve a server side object, the BrowserTabActor instance
+ let conn = transport._serverConnection;
+ let tabActor = conn.getActor(actorID);
+ callback(tabActor);
+ });
+ });
+ });
+
+ client.addListener("tabNavigated", function (aEvent, aPacket) {
+ assertEvent("tabNavigated", aPacket);
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ // Open a test tab
+ addTab(URL1, function(doc) {
+ getServerTabActor(function (tabActor) {
+ // In order to listen to internal will-navigate/navigate events
+ events.on(tabActor, "will-navigate", function (data) {
+ assertEvent("will-navigate", data);
+ });
+ events.on(tabActor, "navigate", function (data) {
+ assertEvent("navigate", data);
+ });
+
+ // Start listening for page load events
+ let browser = gBrowser.selectedTab.linkedBrowser;
+ browser.addEventListener("DOMContentLoaded", onDOMContentLoaded, true);
+ browser.addEventListener("load", onLoad, true);
+
+ // Listen for alert() call being made in navigate-first during unload
+ waitForOnBeforeUnloadDialog(browser, function (btnLeave, btnStay) {
+ assertEvent("unload-dialog");
+ // accept to quit this page to another
+ btnLeave.click();
+ });
+
+ // Load another document in this doc to dispatch these events
+ assertEvent("load-new-document");
+ content.location = URL2;
+ });
+
+ });
+}
+
+function cleanup() {
+ let browser = gBrowser.selectedTab.linkedBrowser;
+ browser.removeEventListener("DOMContentLoaded", onDOMContentLoaded);
+ browser.removeEventListener("load", onLoad);
+ client.close(function () {
+ Services.obs.addObserver(httpObserver, "http-on-modify-request", false);
+ DebuggerServer.destroy();
+ finish();
+ });
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/browser/navigate-first.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+First
+<script>
+
+window.onbeforeunload=function(e){
+ e.returnValue="?";
+};
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/browser/navigate-second.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+Second
+</body>
+</html>
--- a/toolkit/devtools/server/tests/mochitest/inspector-helpers.js
+++ b/toolkit/devtools/server/tests/mochitest/inspector-helpers.js
@@ -56,22 +56,24 @@ function attachURL(url, callback) {
window.addEventListener("message", function loadListener(event) {
if (event.data === "ready") {
client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect((applicationType, traits) => {
client.listTabs(response => {
for (let tab of response.tabs) {
if (tab.url === url) {
window.removeEventListener("message", loadListener, false);
- try {
- callback(null, client, tab, win.document);
- } catch(ex) {
- Cu.reportError(ex);
- dump(ex);
- }
+ client.attachTab(tab.actor, function(aResponse, aTabClient) {
+ try {
+ callback(null, client, tab, win.document);
+ } catch(ex) {
+ Cu.reportError(ex);
+ dump(ex);
+ }
+ });
break;
}
}
});
});
}
}, false);
--- a/toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
+++ b/toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
@@ -18,17 +18,17 @@
<body>
<script type="application/javascript;version=1.8">
"use strict";
const { utils: Cu } = Components;
const { Promise: promise } =
- Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+ Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
const { EventEmitter } =
Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
SimpleTest.waitForExplicitFinish();
testEmitter();
testEmitter({});