mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-05 00:02:37 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
bd7620cf36
@ -11,8 +11,7 @@ module.metadata = {
|
||||
const { Cu } = require("chrome");
|
||||
const { Class } = require("../sdk/core/heritage");
|
||||
const { MessagePort, MessageChannel } = require("../sdk/messaging");
|
||||
const { require: devtoolsRequire } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
const { DevToolsShim } = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
const outputs = new WeakMap();
|
||||
const inputs = new WeakMap();
|
||||
@ -49,12 +48,8 @@ const Debuggee = Class({
|
||||
if (target.isLocalTab) {
|
||||
// Since a remote protocol connection will be made, let's start the
|
||||
// DebuggerServer here, once and for all tools.
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
transports.set(this, DebuggerServer.connectPipe());
|
||||
let transport = DevToolsShim.connectDebuggerServer();
|
||||
transports.set(this, transport);
|
||||
}
|
||||
// TODO: Implement support for remote connections (See Bug 980421)
|
||||
else {
|
||||
|
@ -15,7 +15,7 @@ const { contract, validate } = require("../sdk/util/contract");
|
||||
const { each, pairs, values } = require("../sdk/util/sequence");
|
||||
const { onEnable, onDisable } = require("../dev/theme/hooks");
|
||||
|
||||
const { gDevTools } = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
|
||||
const { DevToolsShim } = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
// This is temporary workaround to allow loading of the developer tools client - volcan
|
||||
// into a toolbox panel, this hack won't be necessary as soon as devtools patch will be
|
||||
@ -46,7 +46,7 @@ const Tool = Class({
|
||||
invertIconForDarkTheme } = validate(Panel.prototype);
|
||||
const { id } = Panel.prototype;
|
||||
|
||||
gDevTools.registerTool({
|
||||
DevToolsShim.registerTool({
|
||||
id: id,
|
||||
url: "about:blank",
|
||||
label: label,
|
||||
@ -70,7 +70,7 @@ const Tool = Class({
|
||||
validate(theme);
|
||||
setup(theme);
|
||||
|
||||
gDevTools.registerTheme({
|
||||
DevToolsShim.registerTheme({
|
||||
id: theme.id,
|
||||
label: theme.label,
|
||||
stylesheets: theme.getStyles(),
|
||||
@ -87,10 +87,10 @@ const Tool = Class({
|
||||
}, pairs(themes));
|
||||
},
|
||||
dispose: function() {
|
||||
each(Panel => gDevTools.unregisterTool(Panel.prototype.id),
|
||||
each(Panel => DevToolsShim.unregisterTool(Panel.prototype.id),
|
||||
values(this.panels));
|
||||
|
||||
each(Theme => gDevTools.unregisterTheme(Theme.prototype.id),
|
||||
each(Theme => DevToolsShim.unregisterTheme(Theme.prototype.id),
|
||||
values(this.themes));
|
||||
}
|
||||
});
|
||||
|
@ -5,15 +5,14 @@
|
||||
"use strict";
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { gDevTools } = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
|
||||
const { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { DevToolsShim } = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
const { getActiveTab } = require("../sdk/tabs/utils");
|
||||
const { getMostRecentBrowserWindow } = require("../sdk/window/utils");
|
||||
|
||||
const targetFor = target => {
|
||||
target = target || getActiveTab(getMostRecentBrowserWindow());
|
||||
return devtools.TargetFactory.forTab(target);
|
||||
return DevToolsShim.getTargetForTab(target);
|
||||
};
|
||||
|
||||
const getId = id => ((id.prototype && id.prototype.id) || id.id || id);
|
||||
@ -23,18 +22,18 @@ exports.getCurrentPanel = getCurrentPanel;
|
||||
|
||||
const openToolbox = (id, tab) => {
|
||||
id = getId(id);
|
||||
return gDevTools.showToolbox(targetFor(tab), id);
|
||||
return DevToolsShim.showToolbox(targetFor(tab), id);
|
||||
};
|
||||
exports.openToolbox = openToolbox;
|
||||
|
||||
const closeToolbox = tab => gDevTools.closeToolbox(targetFor(tab));
|
||||
const closeToolbox = tab => DevToolsShim.closeToolbox(targetFor(tab));
|
||||
exports.closeToolbox = closeToolbox;
|
||||
|
||||
const getToolbox = tab => gDevTools.getToolbox(targetFor(tab));
|
||||
const getToolbox = tab => DevToolsShim.getToolbox(targetFor(tab));
|
||||
exports.getToolbox = getToolbox;
|
||||
|
||||
const openToolboxPanel = (id, tab) => {
|
||||
id = getId(id);
|
||||
return gDevTools.showToolbox(targetFor(tab), id).then(getCurrentPanel);
|
||||
return DevToolsShim.showToolbox(targetFor(tab), id).then(getCurrentPanel);
|
||||
};
|
||||
exports.openToolboxPanel = openToolboxPanel;
|
||||
|
@ -19,9 +19,9 @@ const { preferences } = metadata;
|
||||
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
|
||||
return Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}).
|
||||
BrowserToolboxProcess;
|
||||
XPCOMUtils.defineLazyGetter(this, "DevToolsShim", function () {
|
||||
return Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {}).
|
||||
DevToolsShim;
|
||||
});
|
||||
|
||||
// Initializes default preferences
|
||||
@ -156,7 +156,7 @@ function run(options) {
|
||||
}
|
||||
|
||||
if (get("extensions." + id + ".sdk.debug.show", false)) {
|
||||
BrowserToolboxProcess.init({ addonID: id });
|
||||
DevToolsShim.initBrowserToolboxProcessForAddon(id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.exception(error);
|
||||
|
@ -12,9 +12,7 @@ const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { require: devtoolsRequire } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
const { DebuggerClient } = devtoolsRequire("devtools/shared/client/main");
|
||||
const { DevToolsShim } = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
var gClient;
|
||||
var ok;
|
||||
@ -29,13 +27,7 @@ exports.testDebugger = function(assert, done) {
|
||||
assert.pass('starting test');
|
||||
set('devtools.debugger.log', true);
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient = DevToolsShim.createDebuggerClient();
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
|
@ -12,9 +12,7 @@ const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { require: devtoolsRequire } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
const { DebuggerClient } = devtoolsRequire("devtools/shared/client/main");
|
||||
const { DevToolsShim } = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
var gClient;
|
||||
var ok;
|
||||
@ -36,13 +34,7 @@ exports.testDebugger = function(assert, done) {
|
||||
});
|
||||
ok(true, 'PageMod was created');
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient = DevToolsShim.createDebuggerClient();
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
|
@ -1217,8 +1217,6 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
|
||||
// user's tabs and bookmarks. Note this pref is also synced.
|
||||
pref("services.sync.syncedTabs.showRemoteIcons", true);
|
||||
|
||||
pref("services.sync.sendTabToDevice.enabled", true);
|
||||
|
||||
// Developer edition preferences
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
sticky_pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
|
||||
|
@ -40,8 +40,12 @@ var gSync = {
|
||||
);
|
||||
},
|
||||
|
||||
get sendTabToDeviceEnabled() {
|
||||
return Services.prefs.getBoolPref("services.sync.sendTabToDevice.enabled");
|
||||
get syncReady() {
|
||||
return Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject.ready;
|
||||
},
|
||||
|
||||
get isSignedIn() {
|
||||
return UIState.get().status == UIState.STATUS_SIGNED_IN;
|
||||
},
|
||||
|
||||
get remoteClients() {
|
||||
@ -297,40 +301,40 @@ var gSync = {
|
||||
}
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
if (this.syncReady) {
|
||||
const onTargetDeviceCommand = (event) => {
|
||||
let clients = event.target.getAttribute("clientId") ?
|
||||
[event.target.getAttribute("clientId")] :
|
||||
this.remoteClients.map(client => client.id);
|
||||
|
||||
const onTargetDeviceCommand = (event) => {
|
||||
let clients = event.target.getAttribute("clientId") ?
|
||||
[event.target.getAttribute("clientId")] :
|
||||
this.remoteClients.map(client => client.id);
|
||||
clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
|
||||
gPageActionButton.panel.hidePopup();
|
||||
}
|
||||
|
||||
clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
|
||||
gPageActionButton.panel.hidePopup();
|
||||
function addTargetDevice(clientId, name, clientType) {
|
||||
const targetDevice = createDeviceNodeFn(clientId, name, clientType);
|
||||
targetDevice.addEventListener("command", onTargetDeviceCommand, true);
|
||||
targetDevice.classList.add("sync-menuitem", "sendtab-target");
|
||||
targetDevice.setAttribute("clientId", clientId);
|
||||
targetDevice.setAttribute("clientType", clientType);
|
||||
targetDevice.setAttribute("label", name);
|
||||
fragment.appendChild(targetDevice);
|
||||
}
|
||||
|
||||
const clients = this.remoteClients;
|
||||
for (let client of clients) {
|
||||
addTargetDevice(client.id, client.name, client.type);
|
||||
}
|
||||
|
||||
// "All devices" menu item
|
||||
if (clients.length > 1) {
|
||||
const separator = createDeviceNodeFn();
|
||||
separator.classList.add("sync-menuitem");
|
||||
fragment.appendChild(separator);
|
||||
const allDevicesLabel = this.fxaStrings.GetStringFromName("sendTabToAllDevices.menuitem");
|
||||
addTargetDevice("", allDevicesLabel, "");
|
||||
}
|
||||
}
|
||||
|
||||
function addTargetDevice(clientId, name, clientType) {
|
||||
const targetDevice = createDeviceNodeFn(clientId, name, clientType);
|
||||
targetDevice.addEventListener("command", onTargetDeviceCommand, true);
|
||||
targetDevice.classList.add("sync-menuitem", "sendtab-target");
|
||||
targetDevice.setAttribute("clientId", clientId);
|
||||
targetDevice.setAttribute("clientType", clientType);
|
||||
targetDevice.setAttribute("label", name);
|
||||
fragment.appendChild(targetDevice);
|
||||
}
|
||||
|
||||
const clients = this.remoteClients;
|
||||
for (let client of clients) {
|
||||
addTargetDevice(client.id, client.name, client.type);
|
||||
}
|
||||
|
||||
// "All devices" menu item
|
||||
if (clients.length > 1) {
|
||||
const separator = createDeviceNodeFn();
|
||||
separator.classList.add("sync-menuitem");
|
||||
fragment.appendChild(separator);
|
||||
const allDevicesLabel = this.fxaStrings.GetStringFromName("sendTabToAllDevices.menuitem");
|
||||
addTargetDevice("", allDevicesLabel, "");
|
||||
}
|
||||
|
||||
devicesPopup.appendChild(fragment);
|
||||
},
|
||||
|
||||
@ -356,24 +360,19 @@ var gSync = {
|
||||
}
|
||||
},
|
||||
|
||||
// "Send Tab to Device" menu item
|
||||
updateTabContextMenu(aPopupMenu, aTargetTab) {
|
||||
if (!this.sendTabToDeviceEnabled || !this.weaveService.ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetURI = aTargetTab.linkedBrowser.currentURI.spec;
|
||||
const showSendTab = this.remoteClients.length > 0 && this.isSendableURI(targetURI);
|
||||
const show = this.syncReady &&
|
||||
this.remoteClients.length > 0 &&
|
||||
this.isSendableURI(aTargetTab.linkedBrowser.currentURI.spec);
|
||||
|
||||
["context_sendTabToDevice", "context_sendTabToDevice_separator"]
|
||||
.forEach(id => { document.getElementById(id).hidden = !showSendTab });
|
||||
.forEach(id => document.getElementById(id).hidden = !show);
|
||||
},
|
||||
|
||||
// "Send Page to Device" and "Send Link to Device" menu items
|
||||
initPageContextMenu(contextMenu) {
|
||||
if (!this.sendTabToDeviceEnabled || !this.weaveService.ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
const remoteClientPresent = this.remoteClients.length > 0;
|
||||
const remoteClientPresent = this.syncReady && this.remoteClients.length > 0;
|
||||
// showSendLink and showSendPage are mutually exclusive
|
||||
let showSendLink = remoteClientPresent
|
||||
&& (contextMenu.onSaveableLink || contextMenu.onPlainTextLink);
|
||||
@ -567,9 +566,3 @@ var gSync = {
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(gSync, "weaveService", function() {
|
||||
return Components.classes["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
});
|
||||
|
@ -1325,9 +1325,9 @@ toolbarpaletteitem[place="palette"][hidden] {
|
||||
}
|
||||
|
||||
/* Page action menu */
|
||||
#page-action-sendToDeviceView-body[signedin] > #page-action-sendToDevice-fxa-button,
|
||||
#page-action-sendToDeviceView-body:not([signedin]) > #page-action-no-devices-button,
|
||||
#page-action-sendToDeviceView-body[hasdevices] > #page-action-no-devices-button {
|
||||
#page-action-sendToDeviceView-body:not([state="notsignedin"]) > #page-action-sendToDevice-fxa-button,
|
||||
#page-action-sendToDeviceView-body:not([state="nodevice"]) > #page-action-no-devices-button,
|
||||
#page-action-sendToDeviceView-body:not([state="notready"]) > #page-action-sync-not-ready-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -7847,11 +7847,17 @@ var gPageActionButton = {
|
||||
},
|
||||
|
||||
showSendToDeviceView(subviewButton) {
|
||||
this.setupSendToDeviceView();
|
||||
PanelUI.showSubView("page-action-sendToDeviceView", subviewButton);
|
||||
},
|
||||
|
||||
setupSendToDeviceView() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let url = browser.currentURI.spec;
|
||||
let title = browser.contentTitle;
|
||||
let body = this.sendToDeviceBody;
|
||||
|
||||
// This is on top because it also clears the device list between state changes.
|
||||
gSync.populateSendTabToDevicesMenu(body, url, title, (clientId, name, clientType) => {
|
||||
if (!name) {
|
||||
return document.createElement("toolbarseparator");
|
||||
@ -7865,19 +7871,31 @@ var gPageActionButton = {
|
||||
return item;
|
||||
});
|
||||
|
||||
if (gSync.remoteClients.length) {
|
||||
body.setAttribute("hasdevices", "true");
|
||||
} else {
|
||||
body.removeAttribute("hasdevices");
|
||||
if (!gSync.isSignedIn) {
|
||||
// Could be unconfigured or unverified
|
||||
body.setAttribute("state", "notsignedin");
|
||||
return;
|
||||
}
|
||||
|
||||
if (UIState.get().status == UIState.STATUS_SIGNED_IN) {
|
||||
body.setAttribute("signedin", "true");
|
||||
} else {
|
||||
body.removeAttribute("signedin");
|
||||
// In the first ~10 sec after startup, Sync may not be loaded and the list
|
||||
// of devices will be empty.
|
||||
if (!gSync.syncReady) {
|
||||
body.setAttribute("state", "notready");
|
||||
// Force a background Sync
|
||||
Services.tm.dispatchToMainThread(() => {
|
||||
Weave.Service.sync([]); // [] = clients engine only
|
||||
if (!window.closed && gSync.syncReady) {
|
||||
this.setupSendToDeviceView();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!gSync.remoteClients.length) {
|
||||
body.setAttribute("state", "nodevice");
|
||||
return;
|
||||
}
|
||||
|
||||
PanelUI.showSubView("page-action-sendToDeviceView", subviewButton);
|
||||
body.setAttribute("state", "signedin");
|
||||
},
|
||||
|
||||
fxaButtonClicked() {
|
||||
|
@ -102,9 +102,9 @@
|
||||
hidden="true"
|
||||
oncommand="gBrowser.openNonRemoteWindow(TabContextMenu.contextTab);"/>
|
||||
#endif
|
||||
<menuseparator id="context_sendTabToDevice_separator" hidden="true"/>
|
||||
<menuseparator id="context_sendTabToDevice_separator"/>
|
||||
<menu id="context_sendTabToDevice" label="&sendTabToDevice.label;"
|
||||
accesskey="&sendTabToDevice.accesskey;" hidden="true">
|
||||
accesskey="&sendTabToDevice.accesskey;">
|
||||
<menupopup id="context_sendTabToDevicePopupMenu"
|
||||
onpopupshowing="gSync.populateSendTabToDevicesMenu(event.target, TabContextMenu.contextTab.linkedBrowser.currentURI.spec, TabContextMenu.contextTab.linkedBrowser.contentTitle);"/>
|
||||
</menu>
|
||||
@ -494,6 +494,10 @@
|
||||
class="subviewbutton"
|
||||
label="&sendToDevice.noDevices.label;"
|
||||
disabled="true"/>
|
||||
<toolbarbutton id="page-action-sync-not-ready-button"
|
||||
class="subviewbutton"
|
||||
label="&sendToDevice.syncNotReady.label;"
|
||||
disabled="true"/>
|
||||
</vbox>
|
||||
</panelview>
|
||||
</photonpanelmultiview>
|
||||
|
@ -73,7 +73,8 @@
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="addon-webext-permissions-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical">
|
||||
<popupnotificationcontent class="addon-webext-perm-notification-content" orient="vertical">
|
||||
<description id="addon-webext-perm-header" class="addon-webext-perm-header"/>
|
||||
<description id="addon-webext-perm-text" class="addon-webext-perm-text"/>
|
||||
<label id="addon-webext-perm-intro" class="addon-webext-perm-text"/>
|
||||
<html:ul id="addon-webext-perm-list" class="addon-webext-perm-list"/>
|
||||
|
@ -906,84 +906,6 @@ add_task(async function test_input_spell_false() {
|
||||
*/
|
||||
});
|
||||
|
||||
const remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
|
||||
|
||||
add_task(async function test_plaintext_sendpagetodevice() {
|
||||
if (!gSync.sendTabToDeviceEnabled) {
|
||||
return;
|
||||
}
|
||||
await ensureSyncReady();
|
||||
const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
|
||||
|
||||
let plainTextItemsWithSendPage =
|
||||
["context-navigation", null,
|
||||
["context-back", false,
|
||||
"context-forward", false,
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-savepage", true,
|
||||
...(hasPocket ? ["context-pocket", true] : []),
|
||||
"---", null,
|
||||
"context-sendpagetodevice", true,
|
||||
["*Foo", true,
|
||||
"*Bar", true,
|
||||
"---", null,
|
||||
"*All Devices", true], null,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-viewsource", true,
|
||||
"context-viewinfo", true
|
||||
];
|
||||
await test_contextmenu("#test-text", plainTextItemsWithSendPage, {
|
||||
maybeScreenshotsPresent: true,
|
||||
async onContextMenuShown() {
|
||||
await openMenuItemSubmenu("context-sendpagetodevice");
|
||||
}
|
||||
});
|
||||
|
||||
restoreRemoteClients(oldGetter);
|
||||
});
|
||||
|
||||
add_task(async function test_link_sendlinktodevice() {
|
||||
if (!gSync.sendTabToDeviceEnabled) {
|
||||
return;
|
||||
}
|
||||
await ensureSyncReady();
|
||||
const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
|
||||
|
||||
await test_contextmenu("#test-link",
|
||||
["context-openlinkintab", true,
|
||||
...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
|
||||
// We need a blank entry here because the containers submenu is
|
||||
// dynamically generated with no ids.
|
||||
...(hasContainers ? ["", null] : []),
|
||||
"context-openlink", true,
|
||||
"context-openlinkprivate", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-savelink", true,
|
||||
...(hasPocket ? ["context-savelinktopocket", true] : []),
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true,
|
||||
"---", null,
|
||||
"context-sendlinktodevice", true,
|
||||
["*Foo", true,
|
||||
"*Bar", true,
|
||||
"---", null,
|
||||
"*All Devices", true], null,
|
||||
],
|
||||
{
|
||||
async onContextMenuShown() {
|
||||
await openMenuItemSubmenu("context-sendlinktodevice");
|
||||
}
|
||||
});
|
||||
|
||||
restoreRemoteClients(oldGetter);
|
||||
});
|
||||
|
||||
add_task(async function test_svg_link() {
|
||||
await test_contextmenu("#svg-with-link > a",
|
||||
["context-openlinkintab", true,
|
||||
@ -1062,10 +984,3 @@ async function selectText(selector) {
|
||||
win.getSelection().addRange(div);
|
||||
});
|
||||
}
|
||||
|
||||
function ensureSyncReady() {
|
||||
let service = Cc["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
return service.whenLoaded();
|
||||
}
|
||||
|
@ -16,28 +16,6 @@ add_task(async function test() {
|
||||
is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled");
|
||||
is(document.getElementById("context_reloadAllTabs").disabled, false, "Reload All Tabs is enabled");
|
||||
|
||||
|
||||
if (gSync.sendTabToDeviceEnabled) {
|
||||
const origIsSendableURI = gSync.isSendableURI;
|
||||
gSync.isSendableURI = () => true;
|
||||
// Check the send tab to device menu item
|
||||
await ensureSyncReady();
|
||||
const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
|
||||
await updateTabContextMenu(origTab, async function() {
|
||||
await openMenuItemSubmenu("context_sendTabToDevice");
|
||||
});
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, false, "Send tab to device is shown");
|
||||
let targets = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
|
||||
is(targets[0].getAttribute("label"), "Foo", "Foo target is present");
|
||||
is(targets[1].getAttribute("label"), "Bar", "Bar target is present");
|
||||
is(targets[3].getAttribute("label"), "All Devices", "All Devices target is present");
|
||||
gSync.isSendableURI = () => false;
|
||||
updateTabContextMenu(origTab);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
|
||||
restoreRemoteClients(oldGetter);
|
||||
gSync.isSendableURI = origIsSendableURI;
|
||||
}
|
||||
|
||||
// Hide the original tab.
|
||||
gBrowser.selectedTab = testTab;
|
||||
gBrowser.showOnlyTheseTabs([testTab]);
|
||||
@ -77,10 +55,3 @@ add_task(async function test() {
|
||||
gBrowser.removeTab(pinned);
|
||||
});
|
||||
|
||||
function ensureSyncReady() {
|
||||
let service = Cc["@mozilla.org/weave/service;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
return service.whenLoaded();
|
||||
}
|
||||
|
||||
|
@ -831,26 +831,3 @@ function getCertExceptionDialog(aLocation) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function setupRemoteClientsFixture(fixture) {
|
||||
let oldRemoteClientsGetter =
|
||||
Object.getOwnPropertyDescriptor(gSync, "remoteClients").get;
|
||||
|
||||
Object.defineProperty(gSync, "remoteClients", {
|
||||
get() { return fixture; }
|
||||
});
|
||||
return oldRemoteClientsGetter;
|
||||
}
|
||||
|
||||
function restoreRemoteClients(getter) {
|
||||
Object.defineProperty(gSync, "remoteClients", {
|
||||
get: getter
|
||||
});
|
||||
}
|
||||
|
||||
async function openMenuItemSubmenu(id) {
|
||||
let menuPopup = document.getElementById(id).menupopup;
|
||||
let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
|
||||
menuPopup.showPopup();
|
||||
await menuPopupPromise;
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
|
||||
[browser_sync.js]
|
||||
[browser_contextmenu_sendtab.js]
|
||||
[browser_contextmenu_sendpage.js]
|
||||
[browser_fxa_web_channel.js]
|
||||
support-files=
|
||||
browser_fxa_web_channel.html
|
||||
|
@ -0,0 +1,92 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
|
||||
|
||||
const origRemoteClients = mockReturn(gSync, "remoteClients", remoteClientsFixture);
|
||||
const origSyncReady = mockReturn(gSync, "syncReady", true);
|
||||
const origIsSendableURI = mockReturn(gSync, "isSendableURI", true);
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
|
||||
});
|
||||
|
||||
add_task(async function test_page_contextmenu() {
|
||||
await updateContentContextMenu("#moztext", "context-sendpagetodevice");
|
||||
is(document.getElementById("context-sendpagetodevice").hidden, false, "Send tab to device is shown");
|
||||
is(document.getElementById("context-sendpagetodevice").disabled, false, "Send tab to device is enabled");
|
||||
let devices = document.getElementById("context-sendpagetodevice-popup").childNodes;
|
||||
is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
|
||||
is(devices[1].getAttribute("label"), "Bar", "Bar target is present");
|
||||
is(devices[3].getAttribute("label"), "All Devices", "All Devices target is present");
|
||||
});
|
||||
|
||||
add_task(async function test_page_contextmenu_notsendable() {
|
||||
const isSendableURIMock = mockReturn(gSync, "isSendableURI", false);
|
||||
|
||||
await updateContentContextMenu("#moztext");
|
||||
is(document.getElementById("context-sendpagetodevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context-sendpagetodevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
isSendableURIMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_page_contextmenu_sendtab_no_remote_clients() {
|
||||
let remoteClientsMock = mockReturn(gSync, "remoteClients", []);
|
||||
|
||||
await updateContentContextMenu("#moztext");
|
||||
is(document.getElementById("context-sendpagetodevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context-sendpagetodevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
remoteClientsMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_page_contextmenu_sync_not_ready() {
|
||||
const syncReadyMock = mockReturn(gSync, "syncReady", false);
|
||||
|
||||
await updateContentContextMenu("#moztext");
|
||||
is(document.getElementById("context-sendpagetodevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context-sendpagetodevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
syncReadyMock.restore();
|
||||
});
|
||||
|
||||
// We are not going to bother testing the states of context-sendlinktodevice since they use
|
||||
// the exact same code.
|
||||
// However, browser_contextmenu.js contains tests that verify the menu item is present.
|
||||
|
||||
add_task(async function cleanup() {
|
||||
gBrowser.removeCurrentTab();
|
||||
origSyncReady.restore();
|
||||
origRemoteClients.restore();
|
||||
origIsSendableURI.restore();
|
||||
});
|
||||
|
||||
async function updateContentContextMenu(selector, openSubmenuId = null) {
|
||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
is(contextMenu.state, "closed", "checking if popup is closed");
|
||||
|
||||
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
await BrowserTestUtils.synthesizeMouse(selector, 0, 0, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
shiftkey: false,
|
||||
centered: true
|
||||
},
|
||||
gBrowser.selectedBrowser);
|
||||
await awaitPopupShown;
|
||||
|
||||
if (openSubmenuId) {
|
||||
let menuPopup = document.getElementById(openSubmenuId).menupopup;
|
||||
let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
|
||||
menuPopup.showPopup();
|
||||
await menuPopupPromise;
|
||||
}
|
||||
|
||||
let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
|
||||
contextMenu.hidePopup();
|
||||
await awaitPopupHidden;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const chrome_base = "chrome://mochitests/content/browser/browser/base/content/test/general/";
|
||||
Services.scriptloader.loadSubScript(chrome_base + "head.js", this);
|
||||
/* import-globals-from ../general/head.js */
|
||||
|
||||
const remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
|
||||
|
||||
const origRemoteClients = mockReturn(gSync, "remoteClients", remoteClientsFixture);
|
||||
const origSyncReady = mockReturn(gSync, "syncReady", true);
|
||||
const origIsSendableURI = mockReturn(gSync, "isSendableURI", true);
|
||||
let [testTab] = gBrowser.visibleTabs;
|
||||
|
||||
add_task(async function setup() {
|
||||
is(gBrowser.visibleTabs.length, 1, "there is one visible tab");
|
||||
});
|
||||
|
||||
add_task(async function test_tab_contextmenu() {
|
||||
await updateTabContextMenu(testTab, openSendTabTargetsSubmenu);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, false, "Send tab to device is shown");
|
||||
is(document.getElementById("context_sendTabToDevice").disabled, false, "Send tab to device is enabled");
|
||||
let devices = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
|
||||
is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
|
||||
is(devices[1].getAttribute("label"), "Bar", "Bar target is present");
|
||||
is(devices[3].getAttribute("label"), "All Devices", "All Devices target is present");
|
||||
});
|
||||
|
||||
add_task(async function test_tab_contextmenu_only_one_remote_device() {
|
||||
const remoteClientsMock = mockReturn(gSync, "remoteClients", [{ id: 1, name: "Foo"}]);
|
||||
|
||||
await updateTabContextMenu(testTab, openSendTabTargetsSubmenu);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, false, "Send tab to device is shown");
|
||||
is(document.getElementById("context_sendTabToDevice").disabled, false, "Send tab to device is enabled");
|
||||
let devices = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
|
||||
is(devices.length, 1, "There should not be any separator or All Devices item");
|
||||
is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
|
||||
|
||||
remoteClientsMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_tab_contextmenu_not_sendable() {
|
||||
const isSendableURIMock = mockReturn(gSync, "isSendableURI", false);
|
||||
|
||||
updateTabContextMenu(testTab);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context_sendTabToDevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
isSendableURIMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_tab_contextmenu_no_remote_clients() {
|
||||
let remoteClientsMock = mockReturn(gSync, "remoteClients", []);
|
||||
|
||||
updateTabContextMenu(testTab);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context_sendTabToDevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
remoteClientsMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_tab_contextmenu_sync_not_ready() {
|
||||
const syncReadyMock = mockReturn(gSync, "syncReady", false);
|
||||
|
||||
updateTabContextMenu(testTab);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
|
||||
is(document.getElementById("context_sendTabToDevice").disabled, false, "Send tab to device is enabled");
|
||||
|
||||
syncReadyMock.restore();
|
||||
});
|
||||
|
||||
add_task(async function cleanup() {
|
||||
origSyncReady.restore();
|
||||
origRemoteClients.restore();
|
||||
origIsSendableURI.restore();
|
||||
});
|
||||
|
||||
async function openSendTabTargetsSubmenu() {
|
||||
let menuPopup = document.getElementById("context_sendTabToDevice").menupopup;
|
||||
let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
|
||||
menuPopup.showPopup();
|
||||
await menuPopupPromise;
|
||||
}
|
24
browser/base/content/test/sync/head.js
Normal file
24
browser/base/content/test/sync/head.js
Normal file
@ -0,0 +1,24 @@
|
||||
// Mocks a getter or a function
|
||||
// This is basically sinon.js (our in-tree version doesn't do getters :/) (see bug 1369855)
|
||||
function mockReturn(obj, symbol, fixture) {
|
||||
let getter = Object.getOwnPropertyDescriptor(obj, symbol).get;
|
||||
if (getter) {
|
||||
Object.defineProperty(obj, symbol, {
|
||||
get() { return fixture; }
|
||||
});
|
||||
return {
|
||||
restore() {
|
||||
Object.defineProperty(obj, symbol, {
|
||||
get: getter
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let func = obj[symbol];
|
||||
obj[symbol] = () => fixture;
|
||||
return {
|
||||
restore() {
|
||||
obj[symbol] = func;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,12 @@
|
||||
|
||||
let gPanel = document.getElementById("page-action-panel");
|
||||
|
||||
const mockRemoteClients = [
|
||||
{ id: "0", name: "foo", type: "mobile" },
|
||||
{ id: "1", name: "bar", type: "desktop" },
|
||||
{ id: "2", name: "baz", type: "mobile" },
|
||||
];
|
||||
|
||||
add_task(async function bookmark() {
|
||||
// Open a unique page.
|
||||
let url = "http://example.com/browser_page_action_menu";
|
||||
@ -128,6 +134,112 @@ add_task(async function sendToDevice_nonSendable() {
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function sendToDevice_syncNotReady() {
|
||||
// Open a tab that's sendable.
|
||||
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
||||
let syncReadyMock = mockReturn(gSync, "syncReady", false);
|
||||
let signedInMock = mockReturn(gSync, "isSignedIn", true);
|
||||
|
||||
let remoteClientsMock;
|
||||
let origSync = Weave.Service.sync;
|
||||
Weave.Service.sync = () => {
|
||||
mockReturn(gSync, "syncReady", true);
|
||||
remoteClientsMock = mockReturn(gSync, "remoteClients", mockRemoteClients);
|
||||
};
|
||||
|
||||
let origSetupSendToDeviceView = gPageActionButton.setupSendToDeviceView;
|
||||
gPageActionButton.setupSendToDeviceView = () => {
|
||||
this.numCall++ || (this.numCall = 1);
|
||||
origSetupSendToDeviceView.call(gPageActionButton);
|
||||
testSendTabToDeviceMenu(this.numCall);
|
||||
}
|
||||
|
||||
let cleanUp = () => {
|
||||
Weave.Service.sync = origSync;
|
||||
gPageActionButton.setupSendToDeviceView = origSetupSendToDeviceView;
|
||||
signedInMock.restore();
|
||||
syncReadyMock.restore();
|
||||
remoteClientsMock.restore();
|
||||
};
|
||||
registerCleanupFunction(cleanUp);
|
||||
|
||||
// Open the panel.
|
||||
await promisePanelOpen();
|
||||
let sendToDeviceButton =
|
||||
document.getElementById("page-action-send-to-device-button");
|
||||
Assert.ok(!sendToDeviceButton.disabled);
|
||||
|
||||
// Click Send to Device.
|
||||
let viewPromise = promiseViewShown();
|
||||
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
||||
let view = await viewPromise;
|
||||
Assert.equal(view.id, "page-action-sendToDeviceView");
|
||||
|
||||
function testSendTabToDeviceMenu(numCall) {
|
||||
if (numCall == 1) {
|
||||
// The Fxa button should be shown.
|
||||
checkSendToDeviceItems([
|
||||
{
|
||||
id: "page-action-sendToDevice-fxa-button",
|
||||
display: "none",
|
||||
},
|
||||
{
|
||||
id: "page-action-no-devices-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "page-action-sync-not-ready-button",
|
||||
disabled: true,
|
||||
},
|
||||
]);
|
||||
} else if (numCall == 2) {
|
||||
// The devices should be shown in the subview.
|
||||
let expectedItems = [
|
||||
{
|
||||
id: "page-action-sendToDevice-fxa-button",
|
||||
display: "none",
|
||||
},
|
||||
{
|
||||
id: "page-action-no-devices-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "page-action-sync-not-ready-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
];
|
||||
for (let client of mockRemoteClients) {
|
||||
expectedItems.push({
|
||||
attrs: {
|
||||
clientId: client.id,
|
||||
label: client.name,
|
||||
clientType: client.type,
|
||||
},
|
||||
});
|
||||
}
|
||||
expectedItems.push(
|
||||
null,
|
||||
{
|
||||
label: "All Devices",
|
||||
}
|
||||
);
|
||||
checkSendToDeviceItems(expectedItems);
|
||||
} else {
|
||||
ok(false, "This should never happen");
|
||||
}
|
||||
}
|
||||
|
||||
// Done, hide the panel.
|
||||
let hiddenPromise = promisePanelHidden();
|
||||
gPanel.hidePopup();
|
||||
await hiddenPromise;
|
||||
cleanUp();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function sendToDevice_notSignedIn() {
|
||||
// Open a tab that's sendable.
|
||||
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
||||
@ -155,6 +267,11 @@ add_task(async function sendToDevice_notSignedIn() {
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "page-action-sync-not-ready-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
// Click the Fxa button.
|
||||
@ -206,6 +323,11 @@ add_task(async function sendToDevice_noDevices() {
|
||||
id: "page-action-no-devices-button",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "page-action-sync-not-ready-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
]);
|
||||
|
||||
// Done, hide the panel.
|
||||
@ -224,20 +346,9 @@ add_task(async function sendToDevice_devices() {
|
||||
UIState._internal._state = { status: UIState.STATUS_SIGNED_IN };
|
||||
|
||||
// Set up mock remote clients.
|
||||
let mockRemoteClients = [
|
||||
{ id: "0", name: "foo", type: "mobile" },
|
||||
{ id: "1", name: "bar", type: "desktop" },
|
||||
{ id: "2", name: "baz", type: "mobile" },
|
||||
];
|
||||
let originalGetter =
|
||||
Object.getOwnPropertyDescriptor(gSync, "remoteClients").get;
|
||||
Object.defineProperty(gSync, "remoteClients", {
|
||||
get() { return mockRemoteClients; }
|
||||
});
|
||||
let remoteClientsMock = mockReturn(gSync, "remoteClients", mockRemoteClients);
|
||||
let cleanUp = () => {
|
||||
Object.defineProperty(gSync, "remoteClients", {
|
||||
get: originalGetter
|
||||
});
|
||||
remoteClientsMock.restore();
|
||||
};
|
||||
registerCleanupFunction(cleanUp);
|
||||
|
||||
@ -264,6 +375,11 @@ add_task(async function sendToDevice_devices() {
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "page-action-sync-not-ready-button",
|
||||
display: "none",
|
||||
disabled: true,
|
||||
},
|
||||
];
|
||||
for (let client of mockRemoteClients) {
|
||||
expectedItems.push({
|
||||
@ -381,3 +497,27 @@ function checkSendToDeviceItems(expectedItems) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from test/sync/head.js (see bug 1369855)
|
||||
function mockReturn(obj, symbol, fixture) {
|
||||
let getter = Object.getOwnPropertyDescriptor(obj, symbol).get;
|
||||
if (getter) {
|
||||
Object.defineProperty(obj, symbol, {
|
||||
get() { return fixture; }
|
||||
});
|
||||
return {
|
||||
restore() {
|
||||
Object.defineProperty(obj, symbol, {
|
||||
get: getter
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let func = obj[symbol];
|
||||
obj[symbol] = () => fixture;
|
||||
return {
|
||||
restore() {
|
||||
obj[symbol] = func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
|
||||
|
||||
Cu.import("resource://gre/modules/EventEmitter.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gPhotonStructure", "browser.photon.structure.enabled");
|
||||
|
||||
var {
|
||||
DefaultWeakMap,
|
||||
} = ExtensionUtils;
|
||||
@ -52,7 +54,7 @@ const browserActionMap = new WeakMap();
|
||||
XPCOMUtils.defineLazyGetter(this, "browserAreas", () => {
|
||||
return {
|
||||
"navbar": CustomizableUI.AREA_NAVBAR,
|
||||
"menupanel": CustomizableUI.AREA_PANEL,
|
||||
"menupanel": gPhotonStructure ? CustomizableUI.AREA_FIXED_OVERFLOW_PANEL : CustomizableUI.AREA_PANEL,
|
||||
"tabstrip": CustomizableUI.AREA_TABSTRIP,
|
||||
"personaltoolbar": CustomizableUI.AREA_BOOKMARKS,
|
||||
};
|
||||
@ -218,7 +220,11 @@ this.browserAction = class extends ExtensionAPI {
|
||||
// Google Chrome onClicked extension API.
|
||||
if (this.getProperty(tab, "popup")) {
|
||||
if (this.widget.areaType == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
await window.PanelUI.show();
|
||||
if (gPhotonStructure) {
|
||||
await window.document.getElementById("nav-bar").overflowable.show();
|
||||
} else {
|
||||
await window.PanelUI.show();
|
||||
}
|
||||
}
|
||||
|
||||
let event = new window.CustomEvent("command", {bubbles: true, cancelable: true});
|
||||
|
@ -61,7 +61,7 @@
|
||||
"windowId": {"type": "integer", "minimum": 0, "description": "The ID of the window the tab is contained within."},
|
||||
"openerTabId": {"unsupported": true, "type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists."},
|
||||
"selected": {"type": "boolean", "description": "Whether the tab is selected.", "deprecated": "Please use $(ref:tabs.Tab.highlighted).", "unsupported": true},
|
||||
"highlighted": {"type": "boolean", "description": "Whether the tab is highlighted."},
|
||||
"highlighted": {"type": "boolean", "description": "Whether the tab is highlighted. Works as an alias of active"},
|
||||
"active": {"type": "boolean", "description": "Whether the tab is active in its window. (Does not necessarily mean the window is focused.)"},
|
||||
"pinned": {"type": "boolean", "description": "Whether the tab is pinned."},
|
||||
"audible": {"type": "boolean", "optional": true, "description": "Whether the tab has produced sound over the past couple of seconds (but it might not be heard if also muted). Equivalent to whether the speaker audio indicator is showing."},
|
||||
@ -474,7 +474,7 @@
|
||||
"highlighted": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "Whether the tabs are highlighted."
|
||||
"description": "Whether the tabs are highlighted. Works as an alias of active."
|
||||
},
|
||||
"currentWindow": {
|
||||
"type": "boolean",
|
||||
@ -548,6 +548,7 @@
|
||||
"type": "function",
|
||||
"description": "Highlights the given tabs.",
|
||||
"async": "callback",
|
||||
"unsupported": "true",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "object",
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
var browserAreas = {
|
||||
"navbar": CustomizableUI.AREA_NAVBAR,
|
||||
"menupanel": CustomizableUI.AREA_PANEL,
|
||||
"menupanel": getCustomizableUIPanelID(),
|
||||
"tabstrip": CustomizableUI.AREA_TABSTRIP,
|
||||
"personaltoolbar": CustomizableUI.AREA_BOOKMARKS,
|
||||
};
|
||||
|
@ -295,28 +295,30 @@ add_task(async function testDetailsObjects() {
|
||||
}
|
||||
|
||||
|
||||
// Test icon sizes in the menu panel.
|
||||
CustomizableUI.addWidgetToArea(browserActionWidget.id,
|
||||
CustomizableUI.AREA_PANEL);
|
||||
if (!gPhotonStructure) {
|
||||
// Test icon sizes in the menu panel.
|
||||
CustomizableUI.addWidgetToArea(browserActionWidget.id,
|
||||
CustomizableUI.AREA_PANEL);
|
||||
|
||||
await showBrowserAction(extension);
|
||||
browserActionButton = browserActionWidget.forWindow(window).node;
|
||||
await showBrowserAction(extension);
|
||||
browserActionButton = browserActionWidget.forWindow(window).node;
|
||||
|
||||
for (let resolution of Object.keys(test.menuResolutions)) {
|
||||
await SpecialPowers.pushPrefEnv({set: [[RESOLUTION_PREF, resolution]]});
|
||||
for (let resolution of Object.keys(test.menuResolutions)) {
|
||||
await SpecialPowers.pushPrefEnv({set: [[RESOLUTION_PREF, resolution]]});
|
||||
|
||||
is(window.devicePixelRatio, +resolution, "window has the required resolution");
|
||||
is(window.devicePixelRatio, +resolution, "window has the required resolution");
|
||||
|
||||
let imageURL = test.menuResolutions[resolution];
|
||||
is(getListStyleImage(browserActionButton), imageURL, `browser action has the correct menu image at ${resolution}x resolution`);
|
||||
let imageURL = test.menuResolutions[resolution];
|
||||
is(getListStyleImage(browserActionButton), imageURL, `browser action has the correct menu image at ${resolution}x resolution`);
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
|
||||
await closeBrowserAction(extension);
|
||||
|
||||
CustomizableUI.addWidgetToArea(browserActionWidget.id,
|
||||
CustomizableUI.AREA_NAVBAR);
|
||||
}
|
||||
|
||||
await closeBrowserAction(extension);
|
||||
|
||||
CustomizableUI.addWidgetToArea(browserActionWidget.id,
|
||||
CustomizableUI.AREA_NAVBAR);
|
||||
}
|
||||
|
||||
await extension.unload();
|
||||
|
@ -233,5 +233,5 @@ add_task(async function testBrowserActionInToolbar() {
|
||||
});
|
||||
|
||||
add_task(async function testBrowserActionInPanel() {
|
||||
await testInArea(CustomizableUI.AREA_PANEL);
|
||||
await testInArea(getCustomizableUIPanelID());
|
||||
});
|
||||
|
@ -148,11 +148,11 @@ async function testPopupSize(standardsMode, browserWin = window, arrowSide = "to
|
||||
|
||||
// Test the PanelUI panel for a menu panel button.
|
||||
let widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||
CustomizableUI.addWidgetToArea(widget.id, getCustomizableUIPanelID());
|
||||
|
||||
let browser = await openPanel(extension, browserWin);
|
||||
|
||||
let {panel} = browserWin.PanelUI;
|
||||
let panel = gPhotonStructure ? browserWin.PanelUI.overflowPanel : browserWin.PanelUI.panel;
|
||||
let origPanelRect = panel.getBoundingClientRect();
|
||||
|
||||
// Check that the panel is still positioned as expected.
|
||||
@ -276,7 +276,7 @@ add_task(async function testBrowserActionMenuResizeQuirks() {
|
||||
// rather than below, its button.
|
||||
add_task(async function testBrowserActionMenuResizeBottomArrow() {
|
||||
const WIDTH = 800;
|
||||
const HEIGHT = 300;
|
||||
const HEIGHT = 80;
|
||||
|
||||
let left = screen.availLeft + screen.availWidth - WIDTH;
|
||||
let top = screen.availTop + screen.availHeight - HEIGHT;
|
||||
|
@ -111,12 +111,12 @@ add_task(async function test_execute_browser_action_without_popup() {
|
||||
add_task(async function test_execute_browser_action_in_hamburger_menu_with_popup() {
|
||||
await testExecuteBrowserActionWithOptions({
|
||||
withPopup: true,
|
||||
inArea: CustomizableUI.AREA_PANEL,
|
||||
inArea: getCustomizableUIPanelID(),
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_execute_browser_action_in_hamburger_menu_without_popup() {
|
||||
await testExecuteBrowserActionWithOptions({
|
||||
inArea: CustomizableUI.AREA_PANEL,
|
||||
inArea: getCustomizableUIPanelID(),
|
||||
});
|
||||
});
|
||||
|
@ -112,7 +112,7 @@ add_task(async function testPopupBackground() {
|
||||
info("Test menu panel browserAction popup");
|
||||
|
||||
let widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||
CustomizableUI.addWidgetToArea(widget.id, getCustomizableUIPanelID());
|
||||
|
||||
clickBrowserAction(extension);
|
||||
let browser = await awaitExtensionPanel(extension);
|
||||
|
@ -77,7 +77,7 @@ add_task(async function testPopupBorderRadius() {
|
||||
info("Test menu panel browserAction popup");
|
||||
|
||||
let widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||
CustomizableUI.addWidgetToArea(widget.id, getCustomizableUIPanelID());
|
||||
|
||||
clickBrowserAction(extension);
|
||||
let browser = await awaitExtensionPanel(extension);
|
||||
|
@ -51,7 +51,7 @@ add_task(async function testMenuPanelBrowserAction() {
|
||||
await extension.awaitMessage("pageAction ready");
|
||||
|
||||
let widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
|
||||
CustomizableUI.addWidgetToArea(widget.id, getCustomizableUIPanelID());
|
||||
|
||||
clickBrowserAction(extension);
|
||||
let browser = await awaitExtensionPanel(extension);
|
||||
|
@ -163,18 +163,20 @@ async function runTestWithIcons(icons) {
|
||||
|
||||
checkButtons(icons, ICON_INFO, "toolbar");
|
||||
|
||||
for (let button of ICON_INFO) {
|
||||
if (button[2]) {
|
||||
CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_PANEL);
|
||||
if (!gPhotonStructure) {
|
||||
for (let button of ICON_INFO) {
|
||||
if (button[2]) {
|
||||
CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_PANEL);
|
||||
}
|
||||
}
|
||||
|
||||
await PanelUI.show();
|
||||
|
||||
checkButtons(icons, ICON_INFO, "panel");
|
||||
|
||||
await PanelUI.hide();
|
||||
}
|
||||
|
||||
await PanelUI.show();
|
||||
|
||||
checkButtons(icons, ICON_INFO, "panel");
|
||||
|
||||
await PanelUI.hide();
|
||||
|
||||
await extension.unload();
|
||||
|
||||
for (let button of ICON_INFO) {
|
||||
|
@ -18,7 +18,7 @@
|
||||
* awaitExtensionPanel awaitPopupResize
|
||||
* promiseContentDimensions alterContent
|
||||
* promisePrefChangeObserved openContextMenuInFrame
|
||||
* promiseAnimationFrame
|
||||
* promiseAnimationFrame getCustomizableUIPanelID
|
||||
*/
|
||||
|
||||
const {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
|
||||
@ -201,6 +201,11 @@ var awaitExtensionPanel = async function(extension, win = window, awaitLoad = tr
|
||||
return browser;
|
||||
};
|
||||
|
||||
function getCustomizableUIPanelID() {
|
||||
return gPhotonStructure ? CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
|
||||
: CustomizableUI.AREA_PANEL;
|
||||
}
|
||||
|
||||
function getBrowserActionWidget(extension) {
|
||||
return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
|
||||
}
|
||||
@ -211,7 +216,7 @@ function getBrowserActionPopup(extension, win = window) {
|
||||
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
|
||||
return win.document.getElementById("customizationui-widget-panel");
|
||||
}
|
||||
return win.PanelUI.panel;
|
||||
return gPhotonStructure ? win.PanelUI.overflowPanel : win.PanelUI.panel;
|
||||
}
|
||||
|
||||
var showBrowserAction = async function(extension, win = window) {
|
||||
@ -221,7 +226,14 @@ var showBrowserAction = async function(extension, win = window) {
|
||||
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
|
||||
ok(!widget.overflowed, "Expect widget not to be overflowed");
|
||||
} else if (group.areaType == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
await win.PanelUI.show();
|
||||
// Show the right panel. After Photon is turned on permanently, this
|
||||
// can be re-simplified. This is unfortunately easier than getting
|
||||
// and using the panel (area) ID out of CustomizableUI for the widget.
|
||||
if (gPhotonStructure) {
|
||||
await win.document.getElementById("nav-bar").overflowable.show();
|
||||
} else {
|
||||
await win.PanelUI.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,6 @@ let expectedBackgroundApisTargetSpecific = [
|
||||
"tabs.getCurrent",
|
||||
"tabs.getZoom",
|
||||
"tabs.getZoomSettings",
|
||||
"tabs.highlight",
|
||||
"tabs.insertCSS",
|
||||
"tabs.move",
|
||||
"tabs.onActivated",
|
||||
|
@ -968,3 +968,4 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
||||
<!ENTITY sendToDevice.viewTitle "Send to Device">
|
||||
<!ENTITY sendToDevice.fxaRequired.label "Required">
|
||||
<!ENTITY sendToDevice.noDevices.label "No Devices Available">
|
||||
<!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
|
||||
|
@ -377,10 +377,8 @@ this.ExtensionsUI = {
|
||||
showPermissionsPrompt(browser, strings, icon, histkey) {
|
||||
function eventCallback(topic) {
|
||||
let doc = this.browser.ownerDocument;
|
||||
if (topic == "shown") {
|
||||
doc.getElementById("addon-webext-permissions-notification")
|
||||
.description.innerHTML = strings.header;
|
||||
} else if (topic == "showing") {
|
||||
if (topic == "showing") {
|
||||
doc.getElementById("addon-webext-perm-header").innerHTML = strings.header;
|
||||
let textEl = doc.getElementById("addon-webext-perm-text");
|
||||
textEl.innerHTML = strings.text;
|
||||
textEl.hidden = !strings.text;
|
||||
@ -437,12 +435,7 @@ this.ExtensionsUI = {
|
||||
},
|
||||
];
|
||||
|
||||
// Get the text value of strings.header to pre-populate the header. This will get
|
||||
// overwritten with the HTML version later.
|
||||
let escapeHeader = browser.ownerDocument.createElement("div");
|
||||
escapeHeader.innerHTML = strings.header;
|
||||
win.PopupNotifications.show(browser, "addon-webext-permissions",
|
||||
escapeHeader.textContent,
|
||||
win.PopupNotifications.show(browser, "addon-webext-permissions", "",
|
||||
"addons-notification-icon",
|
||||
action, secondaryActions, popupOptions);
|
||||
});
|
||||
|
@ -495,19 +495,22 @@ html|*.addon-webext-perm-list {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"] {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"],
|
||||
.popup-notification-description[popupid="addon-installed"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addon-webext-perm-notification-content,
|
||||
.addon-installed-notification-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#addon-webext-perm-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#addon-installed-notification-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
|
@ -22,7 +22,11 @@
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-button {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
|
||||
%else
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download.svg");
|
||||
%endif
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon {
|
||||
|
@ -1986,19 +1986,22 @@ html|*.addon-webext-perm-list {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"] {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"],
|
||||
.popup-notification-description[popupid="addon-installed"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addon-webext-perm-notification-content,
|
||||
.addon-installed-notification-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#addon-webext-perm-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#addon-installed-notification-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
|
@ -27,7 +27,11 @@
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-button {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
|
||||
%else
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download.svg");
|
||||
%endif
|
||||
}
|
||||
|
||||
#downloads-indicator-icon {
|
||||
|
6
browser/themes/shared/icons/download-arrow-with-bar.svg
Normal file
6
browser/themes/shared/icons/download-arrow-with-bar.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" d="M13 14H3a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2zm-5.707-1.275a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.605V1.019a1 1 0 0 0-2 0v8.586L3.707 6.312a1 1 0 0 0-1.414 1.413l5 5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 510 B |
@ -118,7 +118,11 @@
|
||||
skin/classic/browser/developer.svg (../shared/icons/developer.svg)
|
||||
skin/classic/browser/device-mobile.svg (../shared/icons/device-mobile.svg)
|
||||
skin/classic/browser/device-desktop.svg (../shared/icons/device-desktop.svg)
|
||||
#ifdef MOZ_PHOTON_THEME
|
||||
skin/classic/browser/download-arrow-with-bar.svg (../shared/icons/download-arrow-with-bar.svg)
|
||||
#else
|
||||
skin/classic/browser/download.svg (../shared/icons/download.svg)
|
||||
#endif
|
||||
skin/classic/browser/edit-copy.svg (../shared/icons/edit-copy.svg)
|
||||
skin/classic/browser/edit-cut.svg (../shared/icons/edit-cut.svg)
|
||||
skin/classic/browser/edit-paste.svg (../shared/icons/edit-paste.svg)
|
||||
|
@ -31,7 +31,11 @@
|
||||
<path id="save" d="M346.25,30h-20.5A1.755,1.755,0,0,1,324,28.25V3.75A1.755,1.755,0,0,1,325.75,2h13.5a5.164,5.164,0,0,1,3.033,1.19L346.717,7.3A4.6,4.6,0,0,1,348,10.241V28.25A1.755,1.755,0,0,1,346.25,30ZM345.774,9.293l-5-4.586C340.347,4.318,340,4.45,340,5v5h5.455C346.055,10,346.2,9.682,345.774,9.293Z"/>
|
||||
<path id="open" d="M319.749,13.924a67.491,67.491,0,0,0-1.34,7.977,37.552,37.552,0,0,0-.4,6.4,0.708,0.708,0,0,1-.714.7H290.679a0.709,0.709,0,0,1-.715-0.7,37.552,37.552,0,0,0-.4-6.4,67.491,67.491,0,0,0-1.34-7.977C287.973,12.779,288.606,12,289,12h29.974C319.368,12,320,12.779,319.749,13.924Zm-29.682-6.9h-0.076V5.019a1.987,1.987,0,0,1,1.968-2.006h8.105c1.087,0,2.276,1.755,2.276,1.755l1.635,2.222,13-.009a1.012,1.012,0,0,1,1.025,1V11H290.048Z"/>
|
||||
<path id="addOns" d="M277.051,30.97a1.987,1.987,0,0,0,1.977-2V21.86s0.3-1.829,1.515-1.829,1.088,1.934,3.356,1.934c1.133,0,3.085-.581,3.085-4.082s-1.952-3.924-3.085-3.924c-2.268,0-2.138,1.828-3.356,1.828s-1.515-1.881-1.515-1.881V10.994a1.988,1.988,0,0,0-1.977-2h-5.2s-1.725-.3-1.725-1.515,1.882-1.3,1.882-3.565c0-1.131-.632-2.926-4.135-2.926s-3.977,1.8-3.977,2.926c0,2.268,1.724,2.349,1.724,3.565S263.9,8.993,263.9,8.993h-4.951a1.989,1.989,0,0,0-1.976,2l0,3.906s-0.211,3.015,2.213,3.015c1.528,0,1.732-2.057,3.742-2.057,1,0,2.019.941,2.019,3.02S263.932,22,262.932,22c-2.01,0-2.214-2.055-3.742-2.055-2.424,0-2.213,2.909-2.213,2.909l0,6.115a1.988,1.988,0,0,0,1.976,2h6.638s3.154,0.212,3.154-2.214c0-1.528-1.991-1.824-1.991-3.835,0-1,1.109-2.238,3.19-2.238s3.314,1.238,3.314,2.238c0,2.012-1.928,2.307-1.928,3.835,0,2.425,3.154,2.214,3.154,2.214h2.572Z"/>
|
||||
#ifdef MOZ_PHOTON_THEME
|
||||
<path id="downloads" d="M248.7 26.1h-17.5c-1 0-1.8.8-1.8 1.8s.8 1.8 1.8 1.8h17.5c1 0 1.8-.8 1.8-1.8s-.8-1.8-1.8-1.8zm-10-2.2c.7.7 1.8.7 2.5 0l8.8-8.8c.7-.7.6-1.8-.1-2.5-.7-.6-1.7-.6-2.4 0l-5.8 5.8v-15c0-1-.8-1.8-1.8-1.8s-1.8.8-1.8 1.8v15l-5.8-5.8c-.7-.7-1.8-.6-2.5.1-.6.7-.6 1.7 0 2.4l8.9 8.8z"/>
|
||||
#else
|
||||
<path id="downloads" d="M253.285,18.118L242.09,29.126a3.008,3.008,0,0,1-4.242,0L226.59,18.118c-1.166-1.166-.772-2.121.879-2.121h6.5l0.062-12a2.027,2.027,0,0,1,2.032-2H244a2,2,0,0,1,2,2V16h6.406C254.057,16,254.451,16.952,253.285,18.118Z"/>
|
||||
#endif
|
||||
<path id="history" d="M208.007,30.007a14,14,0,1,1,14-14A14,14,0,0,1,208.007,30.007Zm0-24.007a10.008,10.008,0,1,0,10,10.008A10,10,0,0,0,208.007,6ZM206.1,15.9V10.412a1.829,1.829,0,0,1,1.829-1.829,1.951,1.951,0,0,1,1.965,1.829v5.032a22.977,22.977,0,0,1,3.52,5.939s-4.106-1.8-6.059-3.773A1.811,1.811,0,0,1,206.1,15.9Z"/>
|
||||
<path id="bookmark-filled" d="M188.4,11.546l-2.241-.371-5.3-.872-1.354-2.728v0l-1.09-2.192-1.088-2.2c-0.743-1.5-1.96-1.5-2.7,0l-1.089,2.2-1.088,2.192v0L171.1,10.3l-5.295.872-2.242.371c-1.677.275-2.093,1.49-.928,2.7l5.452,5.634-0.834,5.464L166.879,27.8c-0.253,1.643.766,2.348,2.264,1.576L171.2,28.3l2.051-1.071a0.007,0.007,0,0,0,.005,0l2.726-1.427,2.725,1.427a0.016,0.016,0,0,0,.007,0l2.048,1.071,2.06,1.082c1.5,0.772,2.514.068,2.266-1.576l-0.376-2.461-0.828-5.464,5.444-5.628C190.5,13.037,190.08,11.821,188.4,11.546Z"/>
|
||||
<path id="Bookmark-hollow" d="M144,8.365l1.725,3.526,0.79,1.616,1.773,0.3,4.069,0.681-3.007,3.153-1.182,1.24,0.254,1.7,0.63,4.207-3.426-1.821-1.639-.871-1.639.871-3.423,1.819,0.632-4.2,0.255-1.7-1.184-1.241-3-3.15,4.111-.683,1.79-.3,0.787-1.636L144,8.365M143.984,2a1.671,1.671,0,0,0-1.351,1.139l-3.472,7.213-7.582,1.259c-1.675.279-2.091,1.509-.926,2.735l5.445,5.709-1.207,8.031c-0.183,1.207.3,1.914,1.151,1.914a2.448,2.448,0,0,0,1.111-.317l6.832-3.631,6.832,3.631a2.447,2.447,0,0,0,1.11.317c0.85,0,1.333-.707,1.152-1.914l-1.2-8.031,5.438-5.7c1.165-1.229.749-2.461-.926-2.74l-7.527-1.259-3.527-7.213A1.668,1.668,0,0,0,143.984,2h0Z"/>
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -71,7 +71,11 @@ toolbar:not([brighttext]) #bookmarks-menu-button[cui-areatype="toolbar"][starred
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="toolbar"] {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
list-style-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
|
||||
%else
|
||||
list-style-image: url("chrome://browser/skin/download.svg");
|
||||
%endif
|
||||
}
|
||||
|
||||
#add-ons-button[cui-areatype="toolbar"] {
|
||||
|
@ -1593,19 +1593,22 @@ html|*.addon-webext-perm-list {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"] {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-webext-permissions"],
|
||||
.popup-notification-description[popupid="addon-installed"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.addon-webext-perm-notification-content,
|
||||
.addon-installed-notification-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#addon-webext-perm-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#addon-installed-notification-header {
|
||||
/* Align the text more closely with the icon by clearing some top line height. */
|
||||
margin-top: -1px;
|
||||
|
@ -22,7 +22,11 @@
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-button {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
|
||||
%else
|
||||
--downloads-indicator-image: url("chrome://browser/skin/download.svg");
|
||||
%endif
|
||||
}
|
||||
|
||||
#downloads-indicator-icon {
|
||||
|
@ -16,6 +16,11 @@ loader.lazyRequireGetter(this, "ToolboxHostManager", "devtools/client/framework/
|
||||
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
|
||||
loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
|
||||
|
||||
// Dependencies required for addon sdk compatibility layer.
|
||||
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
|
||||
loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm");
|
||||
|
||||
const {defaultTools: DefaultTools, defaultThemes: DefaultThemes} =
|
||||
require("devtools/client/definitions");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
@ -533,6 +538,42 @@ DevTools.prototype = {
|
||||
return TargetFactory.forTab(tab);
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility layer for addon-sdk. Remove when Firefox 57 hits release.
|
||||
* Initialize the debugger server if needed and and create a connection.
|
||||
*
|
||||
* @return {DebuggerTransport} a client-side DebuggerTransport for communicating with
|
||||
* the created connection.
|
||||
*/
|
||||
connectDebuggerServer: function () {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
return DebuggerServer.connectPipe();
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility layer for addon-sdk. Remove when Firefox 57 hits release.
|
||||
*
|
||||
* Create a connection to the debugger server and return a debugger client for this
|
||||
* new connection.
|
||||
*/
|
||||
createDebuggerClient: function () {
|
||||
let transport = this.connectDebuggerServer();
|
||||
return new DebuggerClient(transport);
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility layer for addon-sdk. Remove when Firefox 57 hits release.
|
||||
*
|
||||
* Create a BrowserToolbox process linked to the provided addon id.
|
||||
*/
|
||||
initBrowserToolboxProcessForAddon: function (addonID) {
|
||||
BrowserToolboxProcess.init({ addonID });
|
||||
},
|
||||
|
||||
/**
|
||||
* Either the SDK Loader has been destroyed by the add-on contribution
|
||||
* workflow, or firefox is shutting down.
|
||||
|
@ -181,6 +181,10 @@ Inspector.prototype = {
|
||||
return this._target.client.traits.getCssPath;
|
||||
},
|
||||
|
||||
get canGetXPath() {
|
||||
return this._target.client.traits.getXPath;
|
||||
},
|
||||
|
||||
get canGetUsedFontFaces() {
|
||||
return this._target.client.traits.getUsedFontFaces;
|
||||
},
|
||||
@ -1245,6 +1249,15 @@ Inspector.prototype = {
|
||||
hidden: !this.canGetCssPath,
|
||||
click: () => this.copyCssPath(),
|
||||
}));
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "node-menu-copyxpath",
|
||||
label: INSPECTOR_L10N.getStr("inspectorCopyXPath.label"),
|
||||
accesskey:
|
||||
INSPECTOR_L10N.getStr("inspectorCopyXPath.accesskey"),
|
||||
disabled: !isSelectionElement,
|
||||
hidden: !this.canGetXPath,
|
||||
click: () => this.copyXPath(),
|
||||
}));
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "node-menu-copyimagedatauri",
|
||||
label: INSPECTOR_L10N.getStr("inspectorImageDataUri.label"),
|
||||
@ -1802,6 +1815,20 @@ Inspector.prototype = {
|
||||
}).catch(e => console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the XPath of the selected Node to the clipboard.
|
||||
*/
|
||||
copyXPath: function () {
|
||||
if (!this.selection.isNode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.telemetry.toolOpened("copyxpath");
|
||||
this.selection.nodeFront.getXPath().then(path => {
|
||||
clipboardHelper.copyString(path);
|
||||
}).catch(e => console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initiate gcli screenshot command on selected node.
|
||||
*/
|
||||
|
@ -27,6 +27,7 @@ const ALL_MENU_ITEMS = [
|
||||
"node-menu-copyouter",
|
||||
"node-menu-copyuniqueselector",
|
||||
"node-menu-copycsspath",
|
||||
"node-menu-copyxpath",
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-delete",
|
||||
"node-menu-pseudo-hover",
|
||||
|
@ -8,6 +8,8 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
|
||||
const SELECTOR_UNIQUE = "devtools.copy.unique.css.selector.opened";
|
||||
const SELECTOR_FULL = "devtools.copy.full.css.selector.opened";
|
||||
const XPATH = "devtools.copy.xpath.opened";
|
||||
|
||||
const COPY_ITEMS_TEST_DATA = [
|
||||
{
|
||||
desc: "copy inner html",
|
||||
@ -33,6 +35,12 @@ const COPY_ITEMS_TEST_DATA = [
|
||||
selector: "[data-id=\"copy\"]",
|
||||
text: "html body div p",
|
||||
},
|
||||
{
|
||||
desc: "copy XPath",
|
||||
id: "node-menu-copyxpath",
|
||||
selector: "[data-id=\"copy\"]",
|
||||
text: "/html/body/div/p[1]",
|
||||
},
|
||||
{
|
||||
desc: "copy image data uri",
|
||||
id: "node-menu-copyimagedatauri",
|
||||
@ -73,13 +81,16 @@ function checkTelemetryResults(Telemetry) {
|
||||
}
|
||||
}
|
||||
|
||||
is(results.size, 2, "The correct number of scalars were logged");
|
||||
is(results.size, 3, "The correct number of scalars were logged");
|
||||
|
||||
let pings = checkPings(SELECTOR_UNIQUE, results);
|
||||
is(pings, 1, `${SELECTOR_UNIQUE} has just 1 ping`);
|
||||
|
||||
pings = checkPings(SELECTOR_FULL, results);
|
||||
is(pings, 1, `${SELECTOR_FULL} has just 1 ping`);
|
||||
|
||||
pings = checkPings(XPATH, results);
|
||||
is(pings, 1, `${XPATH} has just 1 ping`);
|
||||
}
|
||||
|
||||
function checkPings(scalarId, results) {
|
||||
|
@ -173,6 +173,12 @@ inspectorCopyCSSSelector.accesskey=S
|
||||
inspectorCopyCSSPath.label=CSS Path
|
||||
inspectorCopyCSSPath.accesskey=P
|
||||
|
||||
# LOCALIZATION NOTE (inspectorCopyXPath.label): This is the label
|
||||
# shown in the inspector contextual-menu for the item that lets users copy
|
||||
# the XPath of the current node
|
||||
inspectorCopyXPath.label=XPath
|
||||
inspectorCopyXPath.accesskey=X
|
||||
|
||||
# LOCALIZATION NOTE (inspectorPasteOuterHTML.label): This is the label shown
|
||||
# in the inspector contextual-menu for the item that lets users paste outer
|
||||
# HTML in the current node
|
||||
|
@ -146,6 +146,9 @@ Telemetry.prototype = {
|
||||
copyfullcssselector: {
|
||||
scalar: "devtools.copy.full.css.selector.opened",
|
||||
},
|
||||
copyxpath: {
|
||||
scalar: "devtools.copy.xpath.opened",
|
||||
},
|
||||
developertoolbar: {
|
||||
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_COUNT",
|
||||
timerHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_TIME_ACTIVE_SECONDS"
|
||||
|
@ -152,7 +152,7 @@ NewConsoleOutputWrapper.prototype = {
|
||||
// be removed once it's not needed anymore.
|
||||
// Can only wait for response if the action contains a valid message.
|
||||
if (waitForResponse && action.message) {
|
||||
let messageId = action.message.get("id");
|
||||
let messageId = action.message.id;
|
||||
return new Promise(resolve => {
|
||||
let jsterm = this.jsterm;
|
||||
jsterm.hud.on("new-messages", function onThisMessage(e, messages) {
|
||||
|
@ -88,10 +88,10 @@ function messages(state = new MessageState(), action, filtersState, prefsState)
|
||||
return state.withMutations(function (record) {
|
||||
// Add the new message with a reference to the parent group.
|
||||
let parentGroups = getParentGroups(currentGroup, groupsById);
|
||||
const addedMessage = newMessage.withMutations(function (message) {
|
||||
message.set("groupId", currentGroup);
|
||||
message.set("indent", parentGroups.length);
|
||||
});
|
||||
newMessage.groupId = currentGroup;
|
||||
newMessage.indent = parentGroups.length;
|
||||
|
||||
const addedMessage = Object.freeze(newMessage);
|
||||
record.set(
|
||||
"messagesById",
|
||||
messagesById.set(newMessage.id, addedMessage)
|
||||
|
@ -161,16 +161,16 @@ describe("PageError component:", () => {
|
||||
|
||||
it("can show an error note", () => {
|
||||
const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined");
|
||||
const message = origMessage.set("notes", [
|
||||
{
|
||||
const message = Object.assign({}, origMessage, {
|
||||
"notes": [{
|
||||
"messageBody": "test note",
|
||||
"frame": {
|
||||
"source": "http://example.com/test.js",
|
||||
"line": 2,
|
||||
"column": 6
|
||||
}
|
||||
}
|
||||
]);
|
||||
}]
|
||||
});
|
||||
|
||||
let wrapper = render(PageError({ message, serviceContainer }));
|
||||
|
||||
@ -189,8 +189,8 @@ describe("PageError component:", () => {
|
||||
|
||||
it("can show multiple error notes", () => {
|
||||
const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined");
|
||||
const message = origMessage.set("notes", [
|
||||
{
|
||||
const message = Object.assign({}, origMessage, {
|
||||
"notes": [{
|
||||
"messageBody": "test note 1",
|
||||
"frame": {
|
||||
"source": "http://example.com/test1.js",
|
||||
@ -213,8 +213,8 @@ describe("PageError component:", () => {
|
||||
"line": 9,
|
||||
"column": 4
|
||||
}
|
||||
}
|
||||
]);
|
||||
}]
|
||||
});
|
||||
|
||||
let wrapper = render(PageError({ message, serviceContainer }));
|
||||
|
||||
|
@ -25,7 +25,7 @@ stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({
|
||||
"foobar",
|
||||
"test"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foobar\",\"test\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foobar\",\"test\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -52,7 +52,7 @@ stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({
|
||||
"type": "undefined"
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -77,7 +77,7 @@ stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMe
|
||||
"parameters": [
|
||||
"danger, will robinson!"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"warn\",\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"source\":\"console-api\",\"type\":\"warn\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -104,7 +104,7 @@ stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({
|
||||
"type": "NaN"
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -131,7 +131,7 @@ stubPreparedMessages.set("console.log(null)", new ConsoleMessage({
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -156,7 +156,7 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"鼬"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -181,7 +181,7 @@ stubPreparedMessages.set("console.clear()", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"Console was cleared."
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"clear\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"source\":\"console-api\",\"type\":\"clear\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -204,7 +204,7 @@ stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({
|
||||
"level": "debug",
|
||||
"messageText": "bar: 1",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -250,7 +250,7 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"assert\",\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":27,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":1}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"source\":\"console-api\",\"type\":\"assert\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"columnNumber": 27,
|
||||
@ -283,7 +283,7 @@ stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", ne
|
||||
"parameters": [
|
||||
"hello \nfrom \rthe \"string world!"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -308,7 +308,7 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMe
|
||||
"parameters": [
|
||||
"úṇĩçödê țĕșť"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -345,7 +345,7 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":815,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":815,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -388,7 +388,7 @@ stubPreparedMessages.set("console.log('myarray', ['red', 'green', 'blue'])", new
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myarray\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj32\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"red\",\"green\",\"blue\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myarray\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj32\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"red\",\"green\",\"blue\"]}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -423,7 +423,7 @@ stubPreparedMessages.set("console.log('myregex', /a.b.c/)", new ConsoleMessage({
|
||||
"displayString": "/a.b.c/"
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myregex\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj33\",\"class\":\"RegExp\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"displayString\":\"/a.b.c/\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myregex\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj33\",\"class\":\"RegExp\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"displayString\":\"/a.b.c/\"}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -465,7 +465,7 @@ stubPreparedMessages.set("console.table(['red', 'green', 'blue']);", new Console
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj34\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"red\",\"green\",\"blue\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj34\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"red\",\"green\",\"blue\"]}}],\"source\":\"console-api\",\"type\":\"table\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -524,7 +524,7 @@ stubPreparedMessages.set("console.log('myobject', {red: 'redValue', green: 'gree
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myobject\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj35\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":3,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"red\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"redValue\"},\"green\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"greenValue\"},\"blue\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"blueValue\"}},\"ownPropertiesLength\":3,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":27},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myobject\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj35\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":3,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"red\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"redValue\"},\"green\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"greenValue\"},\"blue\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"blueValue\"}},\"ownPropertiesLength\":3,\"safeGetterValues\":{}}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -572,7 +572,7 @@ stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"mymap\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj36\",\"class\":\"Map\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"kind\":\"MapLike\",\"size\":2,\"entries\":[[\"key1\",\"value1\"],[\"key2\",\"value2\"]]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"mymap\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj36\",\"class\":\"Map\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"kind\":\"MapLike\",\"size\":2,\"entries\":[[\"key1\",\"value1\"],[\"key2\",\"value2\"]]}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -595,7 +595,7 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": [],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"trace\",\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"functionName\":\"testStacktraceFiltering\",\"language\":2,\"lineNumber\":3},{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"functionName\":\"foo\",\"language\":2,\"lineNumber\":6},{\"columnNumber\":1,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":9}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":3},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":3},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"source\":\"console-api\",\"type\":\"trace\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"columnNumber": 3,
|
||||
@ -640,7 +640,7 @@ stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"nullMessage\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"nullMessage\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -663,7 +663,7 @@ stubPreparedMessages.set("timerAlreadyExists", new ConsoleMessage({
|
||||
"level": "warn",
|
||||
"messageText": "Timer “bar” already exists.",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"time\",\"level\":\"warn\",\"messageText\":\"Timer “bar” already exists.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Timer “bar” already exists.\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"time\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -686,7 +686,7 @@ stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": "bar: 1.36ms",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"timeEnd\",\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":4,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":4,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"timeEnd\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -709,7 +709,7 @@ stubPreparedMessages.set("timerDoesntExist", new ConsoleMessage({
|
||||
"level": "warn",
|
||||
"messageText": "Timer “bar” doesn’t exist.",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"timeEnd\",\"level\":\"warn\",\"messageText\":\"Timer “bar” doesn’t exist.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Timer “bar” doesn’t exist.\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"timeEnd\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -734,7 +734,7 @@ stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"bar"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -775,7 +775,7 @@ stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({
|
||||
}
|
||||
}
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"source\":\"console-api\",\"type\":\"table\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -800,7 +800,7 @@ stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"bar"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -823,7 +823,7 @@ stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -848,7 +848,7 @@ stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"foo"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\"],\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -871,7 +871,7 @@ stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -896,7 +896,7 @@ stubPreparedMessages.set("console.group()", new ConsoleMessage({
|
||||
"parameters": [
|
||||
"<no group label>"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"<no group label>\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"<no group label>\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -919,7 +919,7 @@ stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -945,7 +945,7 @@ stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({
|
||||
"foo",
|
||||
"bar"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -974,7 +974,7 @@ stubPreparedMessages.set("console.group(%cfoo%cbar)", new ConsoleMessage({
|
||||
"foo",
|
||||
"bar"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"source\":\"console-api\",\"type\":\"startGroup\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -1000,7 +1000,7 @@ stubPreparedMessages.set("console.groupEnd(%cfoo%cbar)", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -1026,7 +1026,7 @@ stubPreparedMessages.set("console.groupCollapsed(%cfoo%cbaz)", new ConsoleMessag
|
||||
"foo",
|
||||
"baz"
|
||||
],
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"baz\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"baz\"],\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -1052,7 +1052,7 @@ stubPreparedMessages.set("console.groupEnd(%cfoo%cbaz)", new ConsoleMessage({
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"timeStamp\":null,\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"source\":\"console-api\",\"type\":\"endGroup\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
|
@ -22,7 +22,7 @@ stubPreparedMessages.set("Unknown property ‘such-unknown-property’. Declara
|
||||
"level": "warn",
|
||||
"messageText": "Unknown property ‘such-unknown-property’. Declaration dropped.",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"css\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"warn\",\"messageText\":\"Unknown property ‘such-unknown-property’. Declaration dropped.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":23},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":23},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Unknown property ‘such-unknown-property’. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
|
||||
@ -44,7 +44,7 @@ stubPreparedMessages.set("Error in parsing value for ‘padding-top’. Declara
|
||||
"level": "warn",
|
||||
"messageText": "Error in parsing value for ‘padding-top’. Declaration dropped.",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"css\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"warn\",\"messageText\":\"Error in parsing value for ‘padding-top’. Declaration dropped.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":15},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":15},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Error in parsing value for ‘padding-top’. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
|
||||
|
@ -32,7 +32,7 @@ stubPreparedMessages.set("new Date(0)", new ConsoleMessage({
|
||||
"timestamp": 0
|
||||
}
|
||||
},
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"result\",\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": null,
|
||||
"groupId": null,
|
||||
@ -52,7 +52,7 @@ stubPreparedMessages.set("asdf()", new ConsoleMessage({
|
||||
"parameters": {
|
||||
"type": "undefined"
|
||||
},
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"result\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "debugger eval code",
|
||||
@ -77,7 +77,7 @@ stubPreparedMessages.set("1 + @", new ConsoleMessage({
|
||||
"parameters": {
|
||||
"type": "undefined"
|
||||
},
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"result\",\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "debugger eval code",
|
||||
@ -107,7 +107,7 @@ stubPreparedMessages.set("longString message Error", new ConsoleMessage({
|
||||
"parameters": {
|
||||
"type": "undefined"
|
||||
},
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"result\",\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString37\"},\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString37\"},\"parameters\":{\"type\":\"undefined\"},\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": null,
|
||||
"frame": null,
|
||||
"groupId": null,
|
||||
|
@ -22,7 +22,7 @@ stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessa
|
||||
"level": "error",
|
||||
"messageText": "ReferenceError: asdf is not defined",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"lineNumber\":3,\"columnNumber\":5,\"functionName\":\"bar\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"lineNumber\":6,\"columnNumber\":5,\"functionName\":\"foo\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"lineNumber\":9,\"columnNumber\":3,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 52 > eval\",\"lineNumber\":6,\"columnNumber\":9,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"lineNumber\":53,\"columnNumber\":20,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":5},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
@ -76,7 +76,7 @@ stubPreparedMessages.set("SyntaxError: redeclaration of let a", new ConsoleMessa
|
||||
"level": "error",
|
||||
"messageText": "SyntaxError: redeclaration of let a",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"error\",\"messageText\":\"SyntaxError: redeclaration of let a\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"resource://testing-common/content-task.js line 52 > eval\",\"lineNumber\":6,\"columnNumber\":9,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"lineNumber\":53,\"columnNumber\":20,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":9},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":[{\"messageBody\":\"Previously declared at line 2, column 6\",\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":6}}],\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":9},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: redeclaration of let a\",\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js line 52 > eval",
|
||||
@ -125,7 +125,7 @@ stubPreparedMessages.set("TypeError longString message", new ConsoleMessage({
|
||||
"actor": "server1.conn0.child1/longString30"
|
||||
},
|
||||
"parameters": null,
|
||||
"repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"timeStamp\":null,\"type\":\"log\",\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString30\"},\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"lineNumber\":1,\"columnNumber\":7,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js line 52 > eval\",\"lineNumber\":6,\"columnNumber\":9,\"functionName\":null},{\"filename\":\"resource://testing-common/content-task.js\",\"lineNumber\":53,\"columnNumber\":20,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":7},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null,\"indent\":0}",
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":1,\"column\":7},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString30\"},\"parameters\":null,\"source\":\"javascript\",\"type\":\"log\",\"userProvidedStyles\":null}",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
|
@ -12,21 +12,23 @@ describe("getRepeatId:", () => {
|
||||
const baseMessage = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
|
||||
// Repeat ID must be the same even if the timestamp is different.
|
||||
const message1 = baseMessage.set("timeStamp", 1);
|
||||
const message2 = baseMessage.set("timeStamp", 2);
|
||||
const message1 = Object.assign({}, baseMessage, {"timeStamp": 1});
|
||||
const message2 = Object.assign({}, baseMessage, {"timeStamp": 2});
|
||||
|
||||
expect(getRepeatId(message1)).toEqual(getRepeatId(message2));
|
||||
});
|
||||
|
||||
it("returns different repeatIds for different values", () => {
|
||||
const message1 = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
const message2 = message1.set("parameters", ["funny", "monkey"]);
|
||||
const message2 = Object.assign({}, message1, {
|
||||
"parameters": ["funny", "monkey"]
|
||||
});
|
||||
expect(getRepeatId(message1)).toNotEqual(getRepeatId(message2));
|
||||
});
|
||||
|
||||
it("returns different repeatIds for different severities", () => {
|
||||
const message1 = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
const message2 = message1.set("level", "error");
|
||||
const message2 = Object.assign({}, message1, {"level": "error"});
|
||||
expect(getRepeatId(message1)).toNotEqual(getRepeatId(message2));
|
||||
});
|
||||
|
||||
|
@ -5,55 +5,59 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const Immutable = require("devtools/client/shared/vendor/immutable");
|
||||
|
||||
const {
|
||||
MESSAGE_SOURCE,
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_LEVEL
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
|
||||
exports.ConsoleCommand = Immutable.Record({
|
||||
id: null,
|
||||
allowRepeating: false,
|
||||
messageText: null,
|
||||
source: MESSAGE_SOURCE.JAVASCRIPT,
|
||||
type: MESSAGE_TYPE.COMMAND,
|
||||
level: MESSAGE_LEVEL.LOG,
|
||||
groupId: null,
|
||||
indent: 0,
|
||||
});
|
||||
exports.ConsoleCommand = function (props) {
|
||||
return Object.assign({
|
||||
id: null,
|
||||
allowRepeating: false,
|
||||
messageText: null,
|
||||
source: MESSAGE_SOURCE.JAVASCRIPT,
|
||||
type: MESSAGE_TYPE.COMMAND,
|
||||
level: MESSAGE_LEVEL.LOG,
|
||||
groupId: null,
|
||||
indent: 0,
|
||||
}, props);
|
||||
};
|
||||
|
||||
exports.ConsoleMessage = Immutable.Record({
|
||||
id: null,
|
||||
allowRepeating: true,
|
||||
source: null,
|
||||
timeStamp: null,
|
||||
type: null,
|
||||
level: null,
|
||||
messageText: null,
|
||||
parameters: null,
|
||||
repeatId: null,
|
||||
stacktrace: null,
|
||||
frame: null,
|
||||
groupId: null,
|
||||
exceptionDocURL: null,
|
||||
userProvidedStyles: null,
|
||||
notes: null,
|
||||
indent: 0,
|
||||
});
|
||||
exports.ConsoleMessage = function (props) {
|
||||
return Object.assign({
|
||||
id: null,
|
||||
allowRepeating: true,
|
||||
source: null,
|
||||
timeStamp: null,
|
||||
type: null,
|
||||
level: null,
|
||||
messageText: null,
|
||||
parameters: null,
|
||||
repeatId: null,
|
||||
stacktrace: null,
|
||||
frame: null,
|
||||
groupId: null,
|
||||
exceptionDocURL: null,
|
||||
userProvidedStyles: null,
|
||||
notes: null,
|
||||
indent: 0,
|
||||
}, props);
|
||||
};
|
||||
|
||||
exports.NetworkEventMessage = Immutable.Record({
|
||||
id: null,
|
||||
actor: null,
|
||||
level: MESSAGE_LEVEL.LOG,
|
||||
isXHR: false,
|
||||
request: null,
|
||||
response: null,
|
||||
source: MESSAGE_SOURCE.NETWORK,
|
||||
type: MESSAGE_TYPE.LOG,
|
||||
groupId: null,
|
||||
timeStamp: null,
|
||||
totalTime: null,
|
||||
indent: 0,
|
||||
});
|
||||
exports.NetworkEventMessage = function (props) {
|
||||
return Object.assign({
|
||||
id: null,
|
||||
actor: null,
|
||||
level: MESSAGE_LEVEL.LOG,
|
||||
isXHR: false,
|
||||
request: null,
|
||||
response: null,
|
||||
source: MESSAGE_SOURCE.NETWORK,
|
||||
type: MESSAGE_TYPE.LOG,
|
||||
groupId: null,
|
||||
timeStamp: null,
|
||||
totalTime: null,
|
||||
indent: 0,
|
||||
}, props);
|
||||
};
|
||||
|
@ -25,9 +25,10 @@ function prepareMessage(packet, idGenerator) {
|
||||
}
|
||||
|
||||
if (packet.allowRepeating) {
|
||||
packet = packet.set("repeatId", getRepeatId(packet));
|
||||
packet.repeatId = getRepeatId(packet);
|
||||
}
|
||||
return packet.set("id", idGenerator.getNextId(packet));
|
||||
packet.id = idGenerator.getNextId(packet);
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,9 +237,17 @@ function transformPacket(packet) {
|
||||
|
||||
// Helpers
|
||||
function getRepeatId(message) {
|
||||
message = message.toJS();
|
||||
message.timeStamp = null;
|
||||
return JSON.stringify(message);
|
||||
return JSON.stringify({
|
||||
frame: message.frame,
|
||||
groupId: message.groupId,
|
||||
indent: message.indent,
|
||||
level: message.level,
|
||||
messageText: message.messageText,
|
||||
parameters: message.parameters,
|
||||
source: message.source,
|
||||
type: message.type,
|
||||
userProvidedStyles: message.userProvidedStyles,
|
||||
});
|
||||
}
|
||||
|
||||
function convertCachedPacket(packet) {
|
||||
|
@ -159,6 +159,7 @@ loader.lazyGetter(this, "eventListenerService", function () {
|
||||
loader.lazyRequireGetter(this, "CssLogic", "devtools/server/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "getCssPath", "devtools/shared/inspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "getXPath", "devtools/shared/inspector/css-logic", true);
|
||||
|
||||
/**
|
||||
* We only send nodeValue up to a certain size by default. This stuff
|
||||
@ -665,6 +666,18 @@ var NodeActor = exports.NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
|
||||
return getCssPath(this.rawNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the XPath for this node.
|
||||
*
|
||||
* @return {String} The XPath for finding this node on the page.
|
||||
*/
|
||||
getXPath: function () {
|
||||
if (Cu.isDeadWrapper(this.rawNode)) {
|
||||
return "";
|
||||
}
|
||||
return getXPath(this.rawNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll the selected node into view.
|
||||
*/
|
||||
|
@ -152,6 +152,8 @@ RootActor.prototype = {
|
||||
getUniqueSelector: true,
|
||||
// Whether the dom node actor implements the getCssPath method
|
||||
getCssPath: true,
|
||||
// Whether the dom node actor implements the getXPath method
|
||||
getXPath: true,
|
||||
// Whether the director scripts are supported
|
||||
directorScripts: true,
|
||||
// Whether the debugger server supports
|
||||
|
@ -403,3 +403,63 @@ function getCssPath(ele) {
|
||||
return paths.length ? paths.join(" ") : "";
|
||||
}
|
||||
exports.getCssPath = getCssPath;
|
||||
|
||||
/**
|
||||
* Get the xpath for a given element.
|
||||
* @param {DomNode} ele
|
||||
* @returns a string that can be used as an XPath to find the element uniquely.
|
||||
*/
|
||||
function getXPath(ele) {
|
||||
ele = getRootBindingParent(ele);
|
||||
const document = ele.ownerDocument;
|
||||
if (!document || !document.contains(ele)) {
|
||||
throw new Error("getXPath received element not inside document");
|
||||
}
|
||||
|
||||
// Create a short XPath for elements with IDs.
|
||||
if (ele.id) {
|
||||
return `//*[@id="${ele.id}"]`;
|
||||
}
|
||||
|
||||
// Otherwise walk the DOM up and create a part for each ancestor.
|
||||
const parts = [];
|
||||
|
||||
// Use nodeName (instead of localName) so namespace prefix is included (if any).
|
||||
while (ele && ele.nodeType === Node.ELEMENT_NODE) {
|
||||
let nbOfPreviousSiblings = 0;
|
||||
let hasNextSiblings = false;
|
||||
|
||||
// Count how many previous same-name siblings the element has.
|
||||
let sibling = ele.previousSibling;
|
||||
while (sibling) {
|
||||
// Ignore document type declaration.
|
||||
if (sibling.nodeType !== Node.DOCUMENT_TYPE_NODE &&
|
||||
sibling.nodeName == ele.nodeName) {
|
||||
nbOfPreviousSiblings++;
|
||||
}
|
||||
|
||||
sibling = sibling.previousSibling;
|
||||
}
|
||||
|
||||
// Check if the element has at least 1 next same-name sibling.
|
||||
sibling = ele.nextSibling;
|
||||
while (sibling) {
|
||||
if (sibling.nodeName == ele.nodeName) {
|
||||
hasNextSiblings = true;
|
||||
break;
|
||||
}
|
||||
sibling = sibling.nextSibling;
|
||||
}
|
||||
|
||||
const prefix = ele.prefix ? ele.prefix + ":" : "";
|
||||
const nth = nbOfPreviousSiblings || hasNextSiblings
|
||||
? `[${nbOfPreviousSiblings + 1}]` : "";
|
||||
|
||||
parts.push(prefix + ele.localName + nth);
|
||||
|
||||
ele = ele.parentNode;
|
||||
}
|
||||
|
||||
return parts.length ? "/" + parts.reverse().join("/") : "";
|
||||
}
|
||||
exports.getXPath = getXPath;
|
||||
|
@ -43,6 +43,12 @@ const nodeSpec = generateActorSpec({
|
||||
value: RetVal("string")
|
||||
}
|
||||
},
|
||||
getXPath: {
|
||||
request: {},
|
||||
response: {
|
||||
value: RetVal("string")
|
||||
}
|
||||
},
|
||||
scrollIntoView: {
|
||||
request: {},
|
||||
response: {}
|
||||
|
@ -3,5 +3,6 @@ tags = devtools
|
||||
skip-if = os == 'android'
|
||||
|
||||
[test_css-logic-getCssPath.html]
|
||||
[test_css-logic-getXPath.html]
|
||||
[test_eventemitter_basic.html]
|
||||
skip-if = os == 'linux' && debug # Bug 1205739
|
||||
|
111
devtools/shared/tests/mochitest/test_css-logic-getXPath.html
Normal file
111
devtools/shared/tests/mochitest/test_css-logic-getXPath.html
Normal file
@ -0,0 +1,111 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=987877
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 987877</title>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu } = Components;
|
||||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const CssLogic = require("devtools/shared/inspector/css-logic");
|
||||
|
||||
const _tests = [];
|
||||
function addTest(test) {
|
||||
_tests.push(test);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (_tests.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
_tests.shift()();
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runNextTest();
|
||||
};
|
||||
|
||||
addTest(function getXPathForUnattachedElement() {
|
||||
let unattached = document.createElement("div");
|
||||
unattached.id = "unattached";
|
||||
try {
|
||||
CssLogic.getXPath(unattached);
|
||||
ok(false, "Unattached node did not throw");
|
||||
} catch (e) {
|
||||
ok(e, "Unattached node throws an exception");
|
||||
}
|
||||
|
||||
let unattachedChild = document.createElement("div");
|
||||
unattached.appendChild(unattachedChild);
|
||||
try {
|
||||
CssLogic.getXPath(unattachedChild);
|
||||
ok(false, "Unattached child node did not throw");
|
||||
} catch (e) {
|
||||
ok(e, "Unattached child node throws an exception");
|
||||
}
|
||||
|
||||
let unattachedBody = document.createElement("body");
|
||||
try {
|
||||
CssLogic.getXPath(unattachedBody);
|
||||
ok(false, "Unattached body node did not throw");
|
||||
} catch (e) {
|
||||
ok(e, "Unattached body node throws an exception");
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addTest(function getXPath() {
|
||||
let data = [{
|
||||
// Target elements that have an ID get a short XPath.
|
||||
selector: "#i-have-an-id",
|
||||
path: "//*[@id=\"i-have-an-id\"]"
|
||||
}, {
|
||||
selector: "html",
|
||||
path: "/html"
|
||||
}, {
|
||||
selector: "body",
|
||||
path: "/html/body"
|
||||
}, {
|
||||
selector: "body > div:nth-child(2) > div > div:nth-child(4)",
|
||||
path: "/html/body/div[2]/div/div[4]"
|
||||
}, {
|
||||
// XPath should support namespace.
|
||||
selector: "namespace\\:body",
|
||||
path: "/html/body/namespace:test/namespace:body"
|
||||
}];
|
||||
|
||||
for (let {selector, path} of data) {
|
||||
let node = document.querySelector(selector);
|
||||
is(CssLogic.getXPath(node), path, `Full css path is correct for ${selector}`);
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="i-have-an-id">find me</div>
|
||||
<div>
|
||||
<div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div>me too!</div>
|
||||
</div>
|
||||
</div>
|
||||
<namespace:test>
|
||||
<namespace:header></namespace:header>
|
||||
<namespace:body>and me</namespace:body>
|
||||
</namespace:test>
|
||||
</body>
|
||||
</html>
|
@ -196,3 +196,30 @@ this.DevToolsShim = {
|
||||
this.themes = [];
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Compatibility layer for addon-sdk. Remove when Firefox 57 hits release.
|
||||
*
|
||||
* The methods below are used by classes and tests from addon-sdk/
|
||||
* If DevTools are not installed when calling one of them, the call will throw.
|
||||
*/
|
||||
|
||||
let addonSdkMethods = [
|
||||
"closeToolbox",
|
||||
"connectDebuggerServer",
|
||||
"createDebuggerClient",
|
||||
"getTargetForTab",
|
||||
"getToolbox",
|
||||
"initBrowserToolboxProcessForAddon",
|
||||
"showToolbox",
|
||||
];
|
||||
|
||||
for (let method of addonSdkMethods) {
|
||||
this.DevToolsShim[method] = function () {
|
||||
if (!this.isInstalled()) {
|
||||
throw new Error(`Method ${method} unavailable if DevTools are not installed`);
|
||||
}
|
||||
|
||||
return this.gDevTools[method].apply(this.gDevTools, arguments);
|
||||
};
|
||||
}
|
||||
|
@ -4030,9 +4030,16 @@ Element::GetReferrerPolicyAsEnum()
|
||||
{
|
||||
if (IsHTMLElement()) {
|
||||
const nsAttrValue* referrerValue = GetParsedAttr(nsGkAtoms::referrerpolicy);
|
||||
if (referrerValue && referrerValue->Type() == nsAttrValue::eEnum) {
|
||||
return net::ReferrerPolicy(referrerValue->GetEnumValue());
|
||||
}
|
||||
return ReferrerPolicyFromAttr(referrerValue);
|
||||
}
|
||||
return net::RP_Unset;
|
||||
}
|
||||
|
||||
net::ReferrerPolicy
|
||||
Element::ReferrerPolicyFromAttr(const nsAttrValue* aValue)
|
||||
{
|
||||
if (aValue && aValue->Type() == nsAttrValue::eEnum) {
|
||||
return net::ReferrerPolicy(aValue->GetEnumValue());
|
||||
}
|
||||
return net::RP_Unset;
|
||||
}
|
||||
|
@ -1337,6 +1337,7 @@ public:
|
||||
float FontSizeInflation();
|
||||
|
||||
net::ReferrerPolicy GetReferrerPolicyAsEnum();
|
||||
net::ReferrerPolicy ReferrerPolicyFromAttr(const nsAttrValue* aValue);
|
||||
|
||||
/*
|
||||
* Helpers for .dataset. This is implemented on Element, though only some
|
||||
|
@ -118,7 +118,6 @@ private:
|
||||
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, mForm(nullptr)
|
||||
, mForceReload(false)
|
||||
, mInDocResponsiveContent(false)
|
||||
, mCurrentDensity(1.0)
|
||||
{
|
||||
@ -378,10 +377,6 @@ HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aValue) {
|
||||
BeforeMaybeChangeAttr(aNameSpaceID, aName, *aValue, aNotify);
|
||||
}
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && mForm &&
|
||||
(aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
|
||||
// remove the image from the hashtable as needed
|
||||
@ -402,8 +397,11 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue, bool aNotify)
|
||||
{
|
||||
nsAttrValueOrString attrVal(aValue);
|
||||
|
||||
if (aValue) {
|
||||
AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
|
||||
AfterMaybeChangeAttr(aNameSpaceID, aName, attrVal, aOldValue, true,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && mForm &&
|
||||
@ -420,8 +418,6 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
// parser or some such place; we'll get bound after all the attributes have
|
||||
// been set, so we'll do the image load from BindToTree.
|
||||
|
||||
nsAttrValueOrString attrVal(aValue);
|
||||
|
||||
if (aName == nsGkAtoms::src &&
|
||||
aNameSpaceID == kNameSpaceID_None &&
|
||||
!aValue) {
|
||||
@ -466,18 +462,19 @@ HTMLImageElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
BeforeMaybeChangeAttr(aNamespaceID, aName, aValue, aNotify);
|
||||
AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
|
||||
AfterMaybeChangeAttr(aNamespaceID, aName, aValue, nullptr, false, aNotify);
|
||||
|
||||
return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify)
|
||||
HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
bool aValueMaybeChanged, bool aNotify)
|
||||
{
|
||||
bool forceReload = false;
|
||||
// We need to force our image to reload. This must be done here, not in
|
||||
// AfterSetAttr or BeforeSetAttr, because we want to do it even if the attr is
|
||||
// being set to its existing value, which is normally optimized away as a
|
||||
@ -488,9 +485,6 @@ HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
// spec.
|
||||
//
|
||||
// Both cases handle unsetting src in AfterSetAttr
|
||||
//
|
||||
// Much of this should probably happen in AfterMaybeChangeAttr.
|
||||
// See Bug 1370705
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::src) {
|
||||
|
||||
@ -515,10 +509,14 @@ HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
mNewRequestsWillNeedAnimationReset = true;
|
||||
|
||||
// Force image loading here, so that we'll try to load the image from
|
||||
// network if it's set to be not cacheable... If we change things so that
|
||||
// the state gets in Element's attr-setting happen around this
|
||||
// LoadImage call, we could start passing false instead of aNotify
|
||||
// here.
|
||||
// network if it's set to be not cacheable.
|
||||
// Potentially, false could be passed here rather than aNotify since
|
||||
// UpdateState will be called by SetAttrAndNotify, but there are two
|
||||
// obstacles to this: 1) LoadImage will end up calling
|
||||
// UpdateState(aNotify), and we do not want it to call UpdateState(false)
|
||||
// when aNotify is true, and 2) When this function is called by
|
||||
// OnAttrSetButNotChanged, SetAttrAndNotify will not subsequently call
|
||||
// UpdateState.
|
||||
LoadImage(aValue.String(), true, aNotify, eImageLoadType_Normal);
|
||||
|
||||
mNewRequestsWillNeedAnimationReset = false;
|
||||
@ -526,40 +524,31 @@ HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
} else if (aNamespaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::crossorigin &&
|
||||
aNotify) {
|
||||
nsAttrValue attrValue;
|
||||
ParseCORSValue(aValue.String(), attrValue);
|
||||
if (GetCORSMode() != AttrValueToCORSMode(&attrValue)) {
|
||||
if (aValueMaybeChanged && GetCORSMode() != AttrValueToCORSMode(aOldValue)) {
|
||||
// Force a new load of the image with the new cross origin policy.
|
||||
mForceReload = true;
|
||||
forceReload = true;
|
||||
}
|
||||
} else if (aName == nsGkAtoms::referrerpolicy &&
|
||||
aNamespaceID == kNameSpaceID_None &&
|
||||
aNotify) {
|
||||
ReferrerPolicy referrerPolicy = AttributeReferrerPolicyFromString(aValue.String());
|
||||
ReferrerPolicy referrerPolicy = GetImageReferrerPolicy();
|
||||
if (!InResponsiveMode() &&
|
||||
referrerPolicy != RP_Unset &&
|
||||
referrerPolicy != GetImageReferrerPolicy()) {
|
||||
aValueMaybeChanged &&
|
||||
referrerPolicy != ReferrerPolicyFromAttr(aOldValue)) {
|
||||
// XXX: Bug 1076583 - We still use the older synchronous algorithm
|
||||
// Because referrerPolicy is not treated as relevant mutations, setting
|
||||
// the attribute will neither trigger a reload nor update the referrer
|
||||
// policy of the loading channel (whether it has previously completed or
|
||||
// not). Force a new load of the image with the new referrerpolicy.
|
||||
mForceReload = true;
|
||||
forceReload = true;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
bool aNotify)
|
||||
{
|
||||
// Because we load image synchronously in non-responsive-mode, we need to do
|
||||
// reload after the attribute has been set if the reload is triggerred by
|
||||
// cross origin changing.
|
||||
if (mForceReload) {
|
||||
mForceReload = false;
|
||||
if (forceReload) {
|
||||
// Mark channel as urgent-start before load image if the image load is
|
||||
// initaiated by a user interaction.
|
||||
mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
|
||||
@ -575,8 +564,6 @@ HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
ForceReload(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -361,34 +361,25 @@ private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
GenericSpecifiedValues* aGenericData);
|
||||
/**
|
||||
* This function is called by BeforeSetAttr and OnAttrSetButNotChanged.
|
||||
* This function is called by AfterSetAttr and OnAttrSetButNotChanged.
|
||||
* It will not be called if the value is being unset.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
void BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify);
|
||||
/**
|
||||
* This function is called by AfterSetAttr and OnAttrSetButNotChanged.
|
||||
* It will not be called if the value is being unset.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aOldValue the value previously set. Will be null if no value was
|
||||
* previously set. This value should only be used when
|
||||
* aValueMaybeChanged is true; when aValueMaybeChanged is false,
|
||||
* aOldValue should be considered unreliable.
|
||||
* @param aValueMaybeChanged will be false when this function is called from
|
||||
* OnAttrSetButNotChanged to indicate that the value was not changed.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
bool aNotify);
|
||||
/**
|
||||
* Used by BeforeMaybeChangeAttr and AfterMaybeChangeAttr to keep track of
|
||||
* whether a reload needs to be forced after an attribute change that is
|
||||
* currently in progress.
|
||||
*/
|
||||
bool mForceReload;
|
||||
const nsAttrValueOrString& aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
bool aValueMaybeChanged, bool aNotify);
|
||||
|
||||
bool mInDocResponsiveContent;
|
||||
RefPtr<ImageLoadTask> mPendingImageLoadTask;
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include "AndroidMediaReader.h"
|
||||
#include "AndroidMediaPluginHost.h"
|
||||
#endif
|
||||
#ifdef MOZ_ANDROID_HLS_SUPPORT
|
||||
#include "HLSDecoder.h"
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Decoder.h"
|
||||
#include "MP4Demuxer.h"
|
||||
@ -45,18 +48,6 @@
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
static bool
|
||||
IsHttpLiveStreamingType(const MediaContainerType& aType)
|
||||
{
|
||||
return // For m3u8.
|
||||
// https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
|
||||
aType.Type() == MEDIAMIMETYPE("application/vnd.apple.mpegurl")
|
||||
// Some sites serve these as the informal m3u type.
|
||||
|| aType.Type() == MEDIAMIMETYPE("application/x-mpegurl")
|
||||
|| aType.Type() == MEDIAMIMETYPE("audio/x-mpegurl");
|
||||
}
|
||||
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
static bool
|
||||
IsAndroidMediaType(const MediaContainerType& aType)
|
||||
@ -72,6 +63,18 @@ IsAndroidMediaType(const MediaContainerType& aType)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsHttpLiveStreamingType(const MediaContainerType& aType)
|
||||
{
|
||||
return // For m3u8.
|
||||
// https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
|
||||
aType.Type() == MEDIAMIMETYPE("application/vnd.apple.mpegurl")
|
||||
// Some sites serve these as the informal m3u type.
|
||||
|| aType.Type() == MEDIAMIMETYPE("application/x-mpegurl")
|
||||
|| aType.Type() == MEDIAMIMETYPE("audio/x-mpegurl");
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsMP4SupportedType(const MediaContainerType& aType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics)
|
||||
@ -165,7 +168,13 @@ CanHandleMediaType(const MediaContainerType& aType,
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (IsHttpLiveStreamingType(aType)) {
|
||||
#ifdef MOZ_ANDROID_HLS_SUPPORT
|
||||
if (HLSDecoder::IsSupportedType(aType)) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (DecoderTraits::IsHttpLiveStreamingType(aType)) {
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_REQUESTED, true);
|
||||
}
|
||||
|
||||
@ -263,6 +272,12 @@ InstantiateDecoder(const MediaContainerType& aType,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<MediaDecoder> decoder;
|
||||
|
||||
#ifdef MOZ_ANDROID_HLS_SUPPORT
|
||||
if (HLSDecoder::IsSupportedType(aType)) {
|
||||
decoder = new HLSDecoder(aInit);
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_FMP4
|
||||
if (MP4Decoder::IsSupportedType(aType, aDiagnostics)) {
|
||||
decoder = new MP4Decoder(aInit);
|
||||
@ -302,7 +317,7 @@ InstantiateDecoder(const MediaContainerType& aType,
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
if (IsHttpLiveStreamingType(aType)) {
|
||||
if (DecoderTraits::IsHttpLiveStreamingType(aType)) {
|
||||
// We don't have an HLS decoder.
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_HLS_DECODER_SUCCESS, false);
|
||||
}
|
||||
|
@ -61,6 +61,9 @@ public:
|
||||
// otherwise defers to MP4Decoder::IsSupportedType().
|
||||
static bool IsMP4SupportedType(const MediaContainerType& aType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics);
|
||||
|
||||
// Returns true if aType is MIME type of hls.
|
||||
static bool IsHttpLiveStreamingType(const MediaContainerType& aType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
@ -106,6 +107,7 @@ MP3Demuxer::NotifyDataRemoved()
|
||||
|
||||
MP3TrackDemuxer::MP3TrackDemuxer(MediaResource* aSource)
|
||||
: mSource(aSource)
|
||||
, mFrameLock(false)
|
||||
, mOffset(0)
|
||||
, mFirstFrameOffset(0)
|
||||
, mNumParsedFrames(0)
|
||||
@ -420,9 +422,12 @@ MP3TrackDemuxer::Duration(int64_t aNumFrames) const
|
||||
MediaByteRange
|
||||
MP3TrackDemuxer::FindFirstFrame()
|
||||
{
|
||||
// Get engough successive frames to avoid invalid frame from cut stream.
|
||||
// However, some website use very short mp3 file so using the same value as Chrome.
|
||||
// We attempt to find multiple successive frames to avoid locking onto a false
|
||||
// positive if we're fed a stream that has been cut mid-frame.
|
||||
// For compatibility reasons we have to use the same frame count as Chrome, since
|
||||
// some web sites actually use a file that short to test our playback capabilities.
|
||||
static const int MIN_SUCCESSIVE_FRAMES = 3;
|
||||
mFrameLock = false;
|
||||
|
||||
MediaByteRange candidateFrame = FindNextFrame();
|
||||
int numSuccFrames = candidateFrame.Length() > 0;
|
||||
@ -462,7 +467,8 @@ MP3TrackDemuxer::FindFirstFrame()
|
||||
|
||||
if (numSuccFrames >= MIN_SUCCESSIVE_FRAMES) {
|
||||
MP3LOG("FindFirst() accepting candidate frame: "
|
||||
"successiveFrames=%d", numSuccFrames);
|
||||
"successiveFrames=%d", numSuccFrames);
|
||||
mFrameLock = true;
|
||||
} else {
|
||||
MP3LOG("FindFirst() no suitable first frame found");
|
||||
}
|
||||
@ -491,7 +497,7 @@ MediaByteRange
|
||||
MP3TrackDemuxer::FindNextFrame()
|
||||
{
|
||||
static const int BUFFER_SIZE = 64;
|
||||
static const int MAX_SKIPPED_BYTES = 1024 * BUFFER_SIZE;
|
||||
static const uint32_t MAX_SKIPPABLE_BYTES = 1024 * BUFFER_SIZE;
|
||||
|
||||
MP3LOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
@ -504,13 +510,40 @@ MP3TrackDemuxer::FindNextFrame()
|
||||
|
||||
bool foundFrame = false;
|
||||
int64_t frameHeaderOffset = 0;
|
||||
int64_t startOffset = mOffset;
|
||||
const bool searchingForID3 = !mParser.ID3Header().Size();
|
||||
|
||||
// Check whether we've found a valid MPEG frame.
|
||||
while (!foundFrame) {
|
||||
if ((!mParser.FirstFrame().Length()
|
||||
&& mOffset - mParser.ID3Header().Size() > MAX_SKIPPED_BYTES)
|
||||
// How many bytes we can go without finding a valid MPEG frame
|
||||
// (effectively rounded up to the next full buffer size multiple, as we
|
||||
// only check this before reading the next set of data into the buffer).
|
||||
|
||||
// This default value of 0 will be used during testing whether we're being
|
||||
// fed a valid stream, which shouldn't have any gaps between frames.
|
||||
uint32_t maxSkippableBytes = 0;
|
||||
|
||||
if (!mParser.FirstFrame().Length()) {
|
||||
// We're looking for the first valid frame. A well-formed file should
|
||||
// have its first frame header right at the start (skipping an ID3 tag
|
||||
// if necessary), but in order to support files that might have been
|
||||
// improperly cut, we search the first few kB for a frame header.
|
||||
maxSkippableBytes = MAX_SKIPPABLE_BYTES;
|
||||
// Since we're counting the skipped bytes from the offset we started
|
||||
// this parsing session with, we need to discount the ID3 tag size only
|
||||
// if we were looking for one during the current frame parsing session.
|
||||
if (searchingForID3) {
|
||||
maxSkippableBytes += mParser.ID3Header().TotalTagSize();
|
||||
}
|
||||
} else if (mFrameLock) {
|
||||
// We've found a valid MPEG stream, so don't impose any limits
|
||||
// to allow skipping corrupted data until we hit EOS.
|
||||
maxSkippableBytes = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
if ((mOffset - startOffset > maxSkippableBytes)
|
||||
|| (read = Read(buffer, mOffset, BUFFER_SIZE)) == 0) {
|
||||
MP3LOG("FindNext() EOS or exceeded MAX_SKIPPED_BYTES without a frame");
|
||||
MP3LOG("FindNext() EOS or exceeded maxSkippeableBytes without a frame");
|
||||
// This is not a valid MPEG audio stream or we've reached EOS, give up.
|
||||
break;
|
||||
}
|
||||
@ -1320,11 +1353,7 @@ ID3Parser::Parse(ByteReader* aReader)
|
||||
|
||||
while (aReader->CanRead8() && !mHeader.ParseNext(aReader->ReadU8())) { }
|
||||
|
||||
if (mHeader.IsValid()) {
|
||||
// Header found, return total tag size.
|
||||
return ID3Header::SIZE + Header().Size() + Header().FooterSize();
|
||||
}
|
||||
return 0;
|
||||
return mHeader.TotalTagSize();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1389,6 +1418,16 @@ ID3Parser::ID3Header::FooterSize() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ID3Parser::ID3Header::TotalTagSize() const
|
||||
{
|
||||
if (IsValid()) {
|
||||
// Header found, return total tag size.
|
||||
return ID3Header::SIZE + Size() + FooterSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ID3Header::ParseNext(uint8_t c)
|
||||
{
|
||||
|
@ -72,6 +72,10 @@ public:
|
||||
// Returns the size of an ID3v2.4 footer if present and zero otherwise.
|
||||
uint8_t FooterSize() const;
|
||||
|
||||
// The total size of the ID3 tag including header/footer, or zero if
|
||||
// none has been found.
|
||||
uint32_t TotalTagSize() const;
|
||||
|
||||
// Returns whether the parsed data is a valid ID3 header up to the given
|
||||
// byte position.
|
||||
bool IsValid(int aPos) const;
|
||||
@ -450,6 +454,9 @@ private:
|
||||
// MPEG frame parser used to detect frames and extract side info.
|
||||
FrameParser mParser;
|
||||
|
||||
// Whether we've locked onto a valid sequence of frames or not.
|
||||
bool mFrameLock;
|
||||
|
||||
// Current byte offset in the source stream.
|
||||
int64_t mOffset;
|
||||
|
||||
|
@ -183,6 +183,9 @@ private:
|
||||
DECL_MEDIA_PREF("media.ogg.flac.enabled", FlacInOgg, bool, false);
|
||||
DECL_MEDIA_PREF("media.flac.enabled", FlacEnabled, bool, true);
|
||||
|
||||
// Hls
|
||||
DECL_MEDIA_PREF("media.hls.enabled", HLSEnabled, bool, false);
|
||||
|
||||
#if !defined(RELEASE_OR_BETA)
|
||||
DECL_MEDIA_PREF("media.rust.test_mode", RustTestMode, bool, false);
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaResource.h"
|
||||
#include "MediaResourceCallback.h"
|
||||
|
||||
@ -32,6 +33,10 @@
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
|
||||
#ifdef MOZ_ANDROID_HLS_SUPPORT
|
||||
#include "HLSResource.h"
|
||||
#endif
|
||||
|
||||
using mozilla::media::TimeUnit;
|
||||
|
||||
#undef LOG
|
||||
@ -1547,6 +1552,13 @@ MediaResource::Create(MediaResourceCallback* aCallback,
|
||||
|
||||
RefPtr<MediaResource> resource;
|
||||
|
||||
#ifdef MOZ_ANDROID_HLS_SUPPORT
|
||||
if (DecoderTraits::IsHttpLiveStreamingType(containerType.value())) {
|
||||
resource = new HLSResource(aCallback, aChannel, uri, *containerType);
|
||||
return resource.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Let's try to create a FileMediaResource in case the channel is a nsIFile
|
||||
nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
|
||||
if (fc) {
|
||||
|
54
dom/media/hls/HLSDecoder.cpp
Normal file
54
dom/media/hls/HLSDecoder.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "HLSDecoder.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "HLSDemuxer.h"
|
||||
#include "HLSUtils.h"
|
||||
#include "MediaContainerType.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachine*
|
||||
HLSDecoder::CreateStateMachine()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mReader =
|
||||
new MediaFormatReader(this,
|
||||
new HLSDemuxer(GetResource()),
|
||||
GetVideoFrameContainer());
|
||||
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
MediaDecoder*
|
||||
HLSDecoder::Clone(MediaDecoderInit& aInit)
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new HLSDecoder(aInit);
|
||||
}
|
||||
|
||||
bool
|
||||
HLSDecoder::IsEnabled()
|
||||
{
|
||||
return MediaPrefs::HLSEnabled() && (jni::GetAPIVersion() >= 16);
|
||||
}
|
||||
|
||||
bool
|
||||
HLSDecoder::IsSupportedType(const MediaContainerType& aContainerType)
|
||||
{
|
||||
return IsEnabled() &&
|
||||
DecoderTraits::IsHttpLiveStreamingType(aContainerType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
39
dom/media/hls/HLSDecoder.h
Normal file
39
dom/media/hls/HLSDecoder.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef HLSDecoder_h_
|
||||
#define HLSDecoder_h_
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
class MediaFormatReader;
|
||||
|
||||
class HLSDecoder final : public MediaDecoder
|
||||
{
|
||||
public:
|
||||
// MediaDecoder interface.
|
||||
explicit HLSDecoder(MediaDecoderInit& aInit) : MediaDecoder(aInit) { }
|
||||
|
||||
MediaDecoder* Clone(MediaDecoderInit& aInit) override;
|
||||
|
||||
MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
// Returns true if the HLS backend is pref'ed on.
|
||||
static bool IsEnabled();
|
||||
|
||||
// Returns true if aContainerType is an HLS type that we think we can render
|
||||
// with the a platform decoder backend.
|
||||
// If provided, codecs are checked for support.
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
RefPtr<MediaFormatReader> mReader;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* HLSDecoder_h_ */
|
655
dom/media/hls/HLSDemuxer.cpp
Normal file
655
dom/media/hls/HLSDemuxer.cpp
Normal file
@ -0,0 +1,655 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "HLSDemuxer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HLSResource.h"
|
||||
#include "HLSUtils.h"
|
||||
#include "MediaCodec.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
using namespace mozilla::java;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static Atomic<uint32_t> sStreamSourceID(0u);
|
||||
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
using media::TimeUnit;
|
||||
using media::TimeIntervals;
|
||||
using media::TimeInterval;
|
||||
|
||||
static
|
||||
VideoInfo::Rotation getVideoInfoRotation(int aRotation)
|
||||
{
|
||||
switch (aRotation) {
|
||||
case 0:
|
||||
return VideoInfo::Rotation::kDegree_0;
|
||||
case 90:
|
||||
return VideoInfo::Rotation::kDegree_90;
|
||||
case 180:
|
||||
return VideoInfo::Rotation::kDegree_180;
|
||||
case 270:
|
||||
return VideoInfo::Rotation::kDegree_270;
|
||||
default:
|
||||
return VideoInfo::Rotation::kDegree_0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
mozilla::StereoMode getStereoMode(int aMode)
|
||||
{
|
||||
switch (aMode) {
|
||||
case 0:
|
||||
return mozilla::StereoMode::MONO;
|
||||
case 1:
|
||||
return mozilla::StereoMode::TOP_BOTTOM;
|
||||
case 2:
|
||||
return mozilla::StereoMode::LEFT_RIGHT;
|
||||
default:
|
||||
return mozilla::StereoMode::MONO;
|
||||
}
|
||||
}
|
||||
|
||||
// HlsDemuxerCallbacksSupport is a native implemented callback class for
|
||||
// HlsDemuxerCallbacks in GeckoHlsDemuxerWrapper.java.
|
||||
// The callback functions will be invoked by JAVA-side thread.
|
||||
// Should dispatch the task to the demuxer's task queue.
|
||||
// We ensure the callback will never be invoked after
|
||||
// HlsDemuxerCallbacksSupport::DisposeNative has been called in ~HLSDemuxer.
|
||||
class HLSDemuxer::HlsDemuxerCallbacksSupport
|
||||
: public GeckoHlsDemuxerWrapper::HlsDemuxerCallbacks::Natives<HlsDemuxerCallbacksSupport>
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HlsDemuxerCallbacksSupport)
|
||||
public:
|
||||
typedef GeckoHlsDemuxerWrapper::HlsDemuxerCallbacks::Natives<HlsDemuxerCallbacksSupport> NativeCallbacks;
|
||||
using NativeCallbacks::DisposeNative;
|
||||
using NativeCallbacks::AttachNative;
|
||||
|
||||
HlsDemuxerCallbacksSupport(HLSDemuxer* aDemuxer)
|
||||
: mMutex("HlsDemuxerCallbacksSupport")
|
||||
, mDemuxer(aDemuxer)
|
||||
{
|
||||
MOZ_ASSERT(mDemuxer);
|
||||
}
|
||||
|
||||
void OnInitialized(bool aHasAudio, bool aHasVideo)
|
||||
{
|
||||
HLS_DEBUG("HlsDemuxerCallbacksSupport",
|
||||
"OnInitialized");
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mDemuxer) { return; }
|
||||
RefPtr<HlsDemuxerCallbacksSupport> self = this;
|
||||
mDemuxer->GetTaskQueue()->Dispatch(NS_NewRunnableFunction(
|
||||
[=] () {
|
||||
MutexAutoLock lock(self->mMutex);
|
||||
if (self->mDemuxer) {
|
||||
self->mDemuxer->OnInitialized(aHasAudio, aHasVideo);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO: Handle the unexpected error signal from the java implementation
|
||||
// in bug 1368904.
|
||||
void OnError(int aErrorCode)
|
||||
{
|
||||
HLS_DEBUG("HlsDemuxerCallbacksSupport",
|
||||
"Got error(%d) from java side",
|
||||
aErrorCode);
|
||||
}
|
||||
void Detach()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mDemuxer = nullptr;
|
||||
}
|
||||
|
||||
Mutex mMutex;
|
||||
private:
|
||||
~HlsDemuxerCallbacksSupport() { }
|
||||
HLSDemuxer* mDemuxer;
|
||||
|
||||
};
|
||||
|
||||
HLSDemuxer::HLSDemuxer(MediaResource* aResource)
|
||||
: mResource(aResource)
|
||||
, mTaskQueue(new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
|
||||
/* aSupportsTailDispatch = */ false))
|
||||
, mMutex("HLSDemuxer")
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aResource);
|
||||
HlsDemuxerCallbacksSupport::Init();
|
||||
mJavaCallbacks = GeckoHlsDemuxerWrapper::HlsDemuxerCallbacks::New();
|
||||
MOZ_ASSERT(mJavaCallbacks);
|
||||
|
||||
mCallbackSupport = new HlsDemuxerCallbacksSupport(this);
|
||||
HlsDemuxerCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||
mCallbackSupport);
|
||||
|
||||
auto resourceWrapper = static_cast<HLSResource*>(aResource)->GetResourceWrapper();
|
||||
mHlsDemuxerWrapper = GeckoHlsDemuxerWrapper::Create(resourceWrapper->GetPlayer(), mJavaCallbacks);
|
||||
MOZ_ASSERT(mHlsDemuxerWrapper);
|
||||
}
|
||||
|
||||
void
|
||||
HLSDemuxer::OnInitialized(bool aHasAudio, bool aHasVideo)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (aHasAudio) {
|
||||
UpdateAudioInfo(0);
|
||||
}
|
||||
if (aHasVideo) {
|
||||
UpdateVideoInfo(0);
|
||||
}
|
||||
|
||||
mInitPromise.ResolveIfExists(NS_OK, __func__);
|
||||
}
|
||||
|
||||
RefPtr<HLSDemuxer::InitPromise>
|
||||
HLSDemuxer::Init()
|
||||
{
|
||||
RefPtr<HLSDemuxer> self = this;
|
||||
return InvokeAsync(GetTaskQueue(), __func__,
|
||||
[self](){
|
||||
RefPtr<InitPromise> p = self->mInitPromise.Ensure(__func__);
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
void HLSDemuxer::NotifyDataArrived()
|
||||
{
|
||||
HLS_DEBUG("HLSDemuxer", "NotifyDataArrived");
|
||||
}
|
||||
|
||||
bool
|
||||
HLSDemuxer::HasTrackType(TrackType aType) const
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
HLS_DEBUG("HLSDemuxer", "HasTrackType(%d)", aType);
|
||||
switch (aType) {
|
||||
case TrackType::kAudioTrack:
|
||||
return mInfo.HasAudio();
|
||||
case TrackType::kVideoTrack:
|
||||
return mInfo.HasVideo();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HLSDemuxer::GetNumberTracks(TrackType aType) const
|
||||
{
|
||||
switch (aType) {
|
||||
case TrackType::kAudioTrack:
|
||||
return mHlsDemuxerWrapper->GetNumberOfTracks(TrackType::kAudioTrack);
|
||||
case TrackType::kVideoTrack:
|
||||
return mHlsDemuxerWrapper->GetNumberOfTracks(TrackType::kVideoTrack);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
HLSDemuxer::GetTrackDemuxer(TrackType aType, uint32_t aTrackNumber)
|
||||
{
|
||||
RefPtr<HLSTrackDemuxer> e = new HLSTrackDemuxer(this, aType);
|
||||
mDemuxers.AppendElement(e);
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
HLSDemuxer::IsSeekable() const
|
||||
{
|
||||
return !mHlsDemuxerWrapper->IsLiveStream();
|
||||
}
|
||||
|
||||
UniquePtr<EncryptionInfo>
|
||||
HLSDemuxer::GetCrypto()
|
||||
{
|
||||
// TODO: Currently, our HLS implementation doesn't support encrypted content.
|
||||
// Return null at this stage.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TrackInfo*
|
||||
HLSDemuxer::GetTrackInfo(TrackType aTrack)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
switch (aTrack) {
|
||||
case TrackType::kAudioTrack: {
|
||||
return &mInfo.mAudio;
|
||||
}
|
||||
case TrackType::kVideoTrack: {
|
||||
return &mInfo.mVideo;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
HLSDemuxer::GetNextKeyFrameTime()
|
||||
{
|
||||
MOZ_ASSERT(mHlsDemuxerWrapper);
|
||||
return TimeUnit::FromMicroseconds(mHlsDemuxerWrapper->GetNextKeyFrameTime());
|
||||
}
|
||||
|
||||
void
|
||||
HLSDemuxer::UpdateAudioInfo(int index)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mHlsDemuxerWrapper);
|
||||
HLS_DEBUG("HLSDemuxer", "UpdateAudioInfo (%d)", index);
|
||||
MutexAutoLock lock(mMutex);
|
||||
jni::Object::LocalRef infoObj = mHlsDemuxerWrapper->GetAudioInfo(index);
|
||||
if (infoObj) {
|
||||
java::GeckoAudioInfo::LocalRef audioInfo(Move(infoObj));
|
||||
mInfo.mAudio.mRate = audioInfo->Rate();
|
||||
mInfo.mAudio.mChannels = audioInfo->Channels();
|
||||
mInfo.mAudio.mProfile = audioInfo->Profile();
|
||||
mInfo.mAudio.mBitDepth = audioInfo->BitDepth();
|
||||
mInfo.mAudio.mMimeType = NS_ConvertUTF16toUTF8(audioInfo->MimeType()->ToString());
|
||||
mInfo.mAudio.mDuration = TimeUnit::FromMicroseconds(audioInfo->Duration());
|
||||
auto&& csd = audioInfo->CodecSpecificData()->GetElements();
|
||||
mInfo.mAudio.mCodecSpecificConfig->Clear();
|
||||
mInfo.mAudio.mCodecSpecificConfig->AppendElements(reinterpret_cast<uint8_t*>(&csd[0]),
|
||||
csd.Length());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HLSDemuxer::UpdateVideoInfo(int index)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mHlsDemuxerWrapper);
|
||||
MutexAutoLock lock(mMutex);
|
||||
jni::Object::LocalRef infoObj = mHlsDemuxerWrapper->GetVideoInfo(index);
|
||||
if (infoObj) {
|
||||
java::GeckoVideoInfo::LocalRef videoInfo(Move(infoObj));
|
||||
mInfo.mVideo.mStereoMode = getStereoMode(videoInfo->StereoMode());
|
||||
mInfo.mVideo.mRotation = getVideoInfoRotation(videoInfo->Rotation());
|
||||
mInfo.mVideo.mImage.width = videoInfo->DisplayWidth();
|
||||
mInfo.mVideo.mImage.height = videoInfo->DisplayHeight();
|
||||
mInfo.mVideo.mDisplay.width = videoInfo->PictureWidth();
|
||||
mInfo.mVideo.mDisplay.height = videoInfo->PictureHeight();
|
||||
mInfo.mVideo.mMimeType = NS_ConvertUTF16toUTF8(videoInfo->MimeType()->ToString());
|
||||
mInfo.mVideo.mDuration = TimeUnit::FromMicroseconds(videoInfo->Duration());
|
||||
HLS_DEBUG("HLSDemuxer", "UpdateVideoInfo (%d) / I(%dx%d) / D(%dx%d)",
|
||||
index, mInfo.mVideo.mImage.width, mInfo.mVideo.mImage.height,
|
||||
mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HLSDemuxer::OnTaskQueue() const
|
||||
{
|
||||
return mTaskQueue->IsCurrentThreadIn();
|
||||
}
|
||||
|
||||
HLSDemuxer::~HLSDemuxer()
|
||||
{
|
||||
HLS_DEBUG("HLSDemuxer", "~HLSDemuxer()");
|
||||
mCallbackSupport->Detach();
|
||||
if (mJavaCallbacks) {
|
||||
HlsDemuxerCallbacksSupport::DisposeNative(mJavaCallbacks);
|
||||
mJavaCallbacks = nullptr;
|
||||
}
|
||||
if (mHlsDemuxerWrapper) {
|
||||
mHlsDemuxerWrapper->Destroy();
|
||||
mHlsDemuxerWrapper = nullptr;
|
||||
}
|
||||
mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
HLSTrackDemuxer::HLSTrackDemuxer(HLSDemuxer* aParent, TrackInfo::TrackType aType)
|
||||
: mParent(aParent)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
UniquePtr<TrackInfo>
|
||||
HLSTrackDemuxer::GetInfo() const
|
||||
{
|
||||
return mParent->GetTrackInfo(mType)->Clone();
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SeekPromise>
|
||||
HLSTrackDemuxer::Seek(const TimeUnit& aTime)
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
return InvokeAsync<TimeUnit&&>(mParent->GetTaskQueue(),
|
||||
this,
|
||||
__func__,
|
||||
&HLSTrackDemuxer::DoSeek,
|
||||
aTime);
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SeekPromise>
|
||||
HLSTrackDemuxer::DoSeek(const TimeUnit& aTime)
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
MOZ_ASSERT(mParent->OnTaskQueue());
|
||||
mQueuedSample = nullptr;
|
||||
int64_t seekTimeUs = aTime.ToMicroseconds();
|
||||
bool result = mParent->mHlsDemuxerWrapper->Seek(seekTimeUs);
|
||||
if (!result) {
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA,
|
||||
__func__);
|
||||
}
|
||||
TimeUnit seekTime = TimeUnit::FromMicroseconds(seekTimeUs);
|
||||
return SeekPromise::CreateAndResolve(seekTime, __func__);
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SamplesPromise>
|
||||
HLSTrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
|
||||
&HLSTrackDemuxer::DoGetSamples, aNumSamples);
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SamplesPromise>
|
||||
HLSTrackDemuxer::DoGetSamples(int32_t aNumSamples)
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
MOZ_ASSERT(mParent->OnTaskQueue());
|
||||
if (!aNumSamples) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
|
||||
__func__);
|
||||
}
|
||||
RefPtr<SamplesHolder> samples = new SamplesHolder;
|
||||
if (mQueuedSample) {
|
||||
if (mQueuedSample->mEOS) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
|
||||
__func__);
|
||||
}
|
||||
MOZ_ASSERT(mQueuedSample->mKeyframe,
|
||||
"mQueuedSample must be a keyframe");
|
||||
samples->mSamples.AppendElement(mQueuedSample);
|
||||
mQueuedSample = nullptr;
|
||||
aNumSamples--;
|
||||
}
|
||||
if (aNumSamples == 0) {
|
||||
// Return the queued sample.
|
||||
return SamplesPromise::CreateAndResolve(samples, __func__);
|
||||
}
|
||||
mozilla::jni::ObjectArray::LocalRef demuxedSamples =
|
||||
(mType == TrackInfo::kAudioTrack)
|
||||
? mParent->mHlsDemuxerWrapper->GetSamples(TrackInfo::kAudioTrack, aNumSamples)
|
||||
: mParent->mHlsDemuxerWrapper->GetSamples(TrackInfo::kVideoTrack, aNumSamples);
|
||||
nsTArray<jni::Object::LocalRef> sampleObjectArray(demuxedSamples->GetElements());
|
||||
|
||||
if (sampleObjectArray.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
|
||||
for (auto&& demuxedSample : sampleObjectArray) {
|
||||
java::GeckoHlsSample::LocalRef sample(Move(demuxedSample));
|
||||
if (sample->IsEOS()) {
|
||||
HLS_DEBUG("HLSTrackDemuxer", "Met BUFFER_FLAG_END_OF_STREAM.");
|
||||
if (samples->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
|
||||
__func__);
|
||||
}
|
||||
mQueuedSample = new MediaRawData();
|
||||
mQueuedSample->mEOS = true;
|
||||
break;
|
||||
}
|
||||
RefPtr<MediaRawData> mrd = ConvertToMediaRawData(sample);
|
||||
if (!mrd) {
|
||||
return SamplesPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
|
||||
}
|
||||
samples->mSamples.AppendElement(mrd);
|
||||
}
|
||||
if (mType == TrackInfo::kVideoTrack &&
|
||||
(mNextKeyframeTime.isNothing() ||
|
||||
samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value())) {
|
||||
// Only need to find NextKeyFrame for Video
|
||||
UpdateNextKeyFrameTime();
|
||||
}
|
||||
|
||||
return SamplesPromise::CreateAndResolve(samples, __func__);
|
||||
}
|
||||
|
||||
|
||||
CryptoSample
|
||||
HLSTrackDemuxer::ExtractCryptoSample(size_t aSampleSize,
|
||||
java::sdk::CryptoInfo::LocalRef aCryptoInfo)
|
||||
{
|
||||
if (!aCryptoInfo) {
|
||||
return CryptoSample{};
|
||||
}
|
||||
// Extract Crypto information
|
||||
CryptoSample crypto;
|
||||
char const* msg = "";
|
||||
do {
|
||||
HLS_DEBUG("HLSTrackDemuxer", "Sample has Crypto Info");
|
||||
crypto.mValid = true;
|
||||
int32_t mode = 0;
|
||||
if (NS_FAILED(aCryptoInfo->Mode(&mode))) {
|
||||
msg = "Error when extracting encryption mode.";
|
||||
break;
|
||||
}
|
||||
crypto.mMode = mode;
|
||||
mozilla::jni::ByteArray::LocalRef ivData;
|
||||
if (NS_FAILED(aCryptoInfo->Iv(&ivData))) {
|
||||
msg = "Error when extracting encryption IV.";
|
||||
break;
|
||||
}
|
||||
// Data in mIV is uint8_t and jbyte is signed char
|
||||
auto&& ivArr= ivData->GetElements();
|
||||
crypto.mIV.AppendElements(reinterpret_cast<uint8_t*>(&ivArr[0]),
|
||||
ivArr.Length());
|
||||
crypto.mIVSize = ivArr.Length();
|
||||
mozilla::jni::ByteArray::LocalRef keyData;
|
||||
if (NS_FAILED(aCryptoInfo->Key(&keyData))) {
|
||||
msg = "Error when extracting encryption key.";
|
||||
break;
|
||||
}
|
||||
auto&& keyArr = keyData->GetElements();
|
||||
// Data in mKeyId is uint8_t and jbyte is signed char
|
||||
crypto.mKeyId.AppendElements(reinterpret_cast<uint8_t*>(&keyArr[0]),
|
||||
keyArr.Length());
|
||||
|
||||
mozilla::jni::IntArray::LocalRef clearData;
|
||||
if (NS_FAILED(aCryptoInfo->NumBytesOfClearData(&clearData))) {
|
||||
msg = "Error when extracting clear data.";
|
||||
break;
|
||||
}
|
||||
// Data in mPlainSizes is uint16_t, NumBytesOfClearData is int32_t
|
||||
// , so need a for loop to copy
|
||||
for (const auto& b : clearData->GetElements()) {
|
||||
crypto.mPlainSizes.AppendElement(b);
|
||||
}
|
||||
|
||||
mozilla::jni::IntArray::LocalRef encryptedData;
|
||||
if (NS_FAILED(aCryptoInfo->NumBytesOfEncryptedData(&encryptedData))) {
|
||||
msg = "Error when extracting encrypted data.";
|
||||
break;
|
||||
}
|
||||
auto&& encryptedArr = encryptedData->GetElements();
|
||||
// Data in mEncryptedSizes is uint32_t, NumBytesOfEncryptedData is int32_t
|
||||
crypto.mEncryptedSizes.AppendElements(reinterpret_cast<uint32_t*>(&encryptedArr[0]),
|
||||
encryptedArr.Length());
|
||||
int subSamplesNum = 0;
|
||||
if (NS_FAILED(aCryptoInfo->NumSubSamples(&subSamplesNum))) {
|
||||
msg = "Error when extracting subsamples.";
|
||||
break;
|
||||
}
|
||||
crypto.mPlainSizes[0] -= (aSampleSize - subSamplesNum);
|
||||
|
||||
return crypto;
|
||||
} while (false);
|
||||
|
||||
HLS_DEBUG("HLSTrackDemuxer",
|
||||
"%s", msg);
|
||||
return CryptoSample{};
|
||||
}
|
||||
|
||||
RefPtr<MediaRawData>
|
||||
HLSTrackDemuxer::ConvertToMediaRawData(java::GeckoHlsSample::LocalRef aSample)
|
||||
{
|
||||
java::sdk::BufferInfo::LocalRef info = aSample->Info();
|
||||
// Currently extract PTS, Size and Data without Crypto information.
|
||||
// Transform java Sample into MediaRawData
|
||||
RefPtr<MediaRawData> mrd = new MediaRawData();
|
||||
int64_t presentationTimeUs = 0;
|
||||
bool ok = NS_SUCCEEDED(info->PresentationTimeUs(&presentationTimeUs));
|
||||
mrd->mTime = TimeUnit::FromMicroseconds(presentationTimeUs);
|
||||
mrd->mTimecode = TimeUnit::FromMicroseconds(presentationTimeUs);
|
||||
mrd->mKeyframe = aSample->IsKeyFrame();
|
||||
mrd->mDuration = (mType == TrackInfo::kVideoTrack)
|
||||
? TimeUnit::FromMicroseconds(aSample->Duration())
|
||||
: TimeUnit::Zero();
|
||||
|
||||
int32_t size = 0;
|
||||
ok &= NS_SUCCEEDED(info->Size(&size));
|
||||
if (!ok) {
|
||||
HLS_DEBUG("HLSTrackDemuxer", "Error occurred during extraction from Sample java object.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Update streamSouceID & videoInfo for MFR.
|
||||
if (mType == TrackInfo::kVideoTrack) {
|
||||
auto sampleFormatIndex = aSample->FormatIndex();
|
||||
if (mLastFormatIndex != sampleFormatIndex) {
|
||||
mLastFormatIndex = sampleFormatIndex;
|
||||
mParent->UpdateVideoInfo(mLastFormatIndex);
|
||||
MutexAutoLock lock(mParent->mMutex);
|
||||
mrd->mTrackInfo = new TrackInfoSharedPtr(mParent->mInfo.mVideo, ++sStreamSourceID);
|
||||
}
|
||||
}
|
||||
|
||||
// Write payload into MediaRawData
|
||||
UniquePtr<MediaRawDataWriter> writer(mrd->CreateWriter());
|
||||
if (!writer->SetSize(size)) {
|
||||
HLS_DEBUG("HLSTrackDemuxer", "Exit failed to allocate media buffer");
|
||||
return nullptr;
|
||||
}
|
||||
jni::ByteBuffer::LocalRef dest =
|
||||
jni::ByteBuffer::New(writer->Data(), writer->Size());
|
||||
aSample->WriteToByteBuffer(dest);
|
||||
|
||||
writer->mCrypto = ExtractCryptoSample(writer->Size(),
|
||||
aSample->CryptoInfo());
|
||||
return mrd;
|
||||
}
|
||||
|
||||
void
|
||||
HLSTrackDemuxer::Reset()
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
mQueuedSample = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HLSTrackDemuxer::UpdateNextKeyFrameTime()
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
TimeUnit nextKeyFrameTime = mParent->GetNextKeyFrameTime();
|
||||
if (nextKeyFrameTime != mNextKeyframeTime.refOr(TimeUnit::FromInfinity())) {
|
||||
HLS_DEBUG("HLSTrackDemuxer", "Update mNextKeyframeTime to %" PRId64 , nextKeyFrameTime.ToMicroseconds());
|
||||
mNextKeyframeTime = Some(nextKeyFrameTime);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HLSTrackDemuxer::GetNextRandomAccessPoint(TimeUnit* aTime)
|
||||
{
|
||||
if (mNextKeyframeTime.isNothing()) {
|
||||
// There's no next key frame.
|
||||
*aTime = TimeUnit::FromInfinity();
|
||||
} else {
|
||||
*aTime = mNextKeyframeTime.value();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SkipAccessPointPromise>
|
||||
HLSTrackDemuxer::SkipToNextRandomAccessPoint(
|
||||
const TimeUnit& aTimeThreshold)
|
||||
{
|
||||
return InvokeAsync(
|
||||
mParent->GetTaskQueue(), this, __func__,
|
||||
&HLSTrackDemuxer::DoSkipToNextRandomAccessPoint,
|
||||
aTimeThreshold);
|
||||
}
|
||||
|
||||
RefPtr<HLSTrackDemuxer::SkipAccessPointPromise>
|
||||
HLSTrackDemuxer::DoSkipToNextRandomAccessPoint(
|
||||
const TimeUnit& aTimeThreshold)
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
MOZ_ASSERT(mParent->OnTaskQueue());
|
||||
mQueuedSample = nullptr;
|
||||
uint32_t parsed = 0;
|
||||
bool found = false;
|
||||
MediaResult result = NS_ERROR_DOM_MEDIA_END_OF_STREAM;
|
||||
do {
|
||||
mozilla::jni::ObjectArray::LocalRef demuxedSamples =
|
||||
mParent->mHlsDemuxerWrapper->GetSamples(mType, 1);
|
||||
nsTArray<jni::Object::LocalRef> sampleObjectArray(demuxedSamples->GetElements());
|
||||
if (sampleObjectArray.IsEmpty()) {
|
||||
result = NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA;
|
||||
break;
|
||||
}
|
||||
parsed++;
|
||||
java::GeckoHlsSample::LocalRef sample(Move(sampleObjectArray[0]));
|
||||
if (sample->IsEOS()) {
|
||||
result = NS_ERROR_DOM_MEDIA_END_OF_STREAM;
|
||||
break;
|
||||
}
|
||||
if (sample->IsKeyFrame()) {
|
||||
java::sdk::BufferInfo::LocalRef info = sample->Info();
|
||||
int64_t presentationTimeUs = 0;
|
||||
bool ok = NS_SUCCEEDED(info->PresentationTimeUs(&presentationTimeUs));
|
||||
if (ok && TimeUnit::FromMicroseconds(presentationTimeUs) >= aTimeThreshold) {
|
||||
found = true;
|
||||
mQueuedSample = ConvertToMediaRawData(sample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(true);
|
||||
|
||||
if (!found) {
|
||||
return SkipAccessPointPromise::CreateAndReject(
|
||||
SkipFailureHolder(result, parsed),
|
||||
__func__);
|
||||
}
|
||||
return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
|
||||
}
|
||||
|
||||
TimeIntervals
|
||||
HLSTrackDemuxer::GetBuffered()
|
||||
{
|
||||
MOZ_ASSERT(mParent, "Called after BreackCycle()");
|
||||
int64_t bufferedTime = mParent->mHlsDemuxerWrapper->GetBuffered(); //us
|
||||
return TimeIntervals(TimeInterval(TimeUnit(),
|
||||
TimeUnit::FromMicroseconds(bufferedTime)));
|
||||
}
|
||||
|
||||
void
|
||||
HLSTrackDemuxer::BreakCycles()
|
||||
{
|
||||
RefPtr<HLSTrackDemuxer> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self]() {
|
||||
self->mParent = nullptr;
|
||||
} );
|
||||
mParent->GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
HLSTrackDemuxer::~HLSTrackDemuxer()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
130
dom/media/hls/HLSDemuxer.h
Normal file
130
dom/media/hls/HLSDemuxer.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(HLSDemuxer_h_)
|
||||
#define HLSDemuxer_h_
|
||||
|
||||
#include "AutoTaskQueue.h"
|
||||
#include "GeneratedJNINatives.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#include "MediaCodec.h"
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "VideoUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AbstractThread;
|
||||
class MediaResult;
|
||||
class HLSTrackDemuxer;
|
||||
|
||||
class HLSDemuxer final : public MediaDataDemuxer
|
||||
{
|
||||
class HlsDemuxerCallbacksSupport;
|
||||
public:
|
||||
explicit HLSDemuxer(MediaResource* aResource);
|
||||
|
||||
RefPtr<InitPromise> Init() override;
|
||||
|
||||
bool HasTrackType(TrackInfo::TrackType aType) const override;
|
||||
|
||||
uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
|
||||
|
||||
already_AddRefed<MediaTrackDemuxer>
|
||||
GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
|
||||
bool IsSeekable() const override;
|
||||
|
||||
UniquePtr<EncryptionInfo> GetCrypto() override;
|
||||
|
||||
bool ShouldComputeStartTime() const override { return true; }
|
||||
|
||||
void NotifyDataArrived() override;
|
||||
|
||||
AutoTaskQueue* GetTaskQueue() const { return mTaskQueue; }
|
||||
void OnInitialized(bool aHasAudio, bool aHasVideo);
|
||||
|
||||
private:
|
||||
media::TimeUnit GetNextKeyFrameTime();
|
||||
void UpdateVideoInfo(int index);
|
||||
void UpdateAudioInfo(int index);
|
||||
bool OnTaskQueue() const;
|
||||
TrackInfo* GetTrackInfo(TrackInfo::TrackType);
|
||||
~HLSDemuxer();
|
||||
RefPtr<MediaResource> mResource;
|
||||
friend class HLSTrackDemuxer;
|
||||
|
||||
const RefPtr<AutoTaskQueue> mTaskQueue;
|
||||
nsTArray<RefPtr<HLSTrackDemuxer>> mDemuxers;
|
||||
|
||||
MozPromiseHolder<InitPromise> mInitPromise;
|
||||
RefPtr<HlsDemuxerCallbacksSupport> mCallbackSupport;
|
||||
|
||||
// Mutex to protect members below across multiple threads.
|
||||
mutable Mutex mMutex;
|
||||
MediaInfo mInfo;
|
||||
|
||||
java::GeckoHlsDemuxerWrapper::HlsDemuxerCallbacks::GlobalRef mJavaCallbacks;
|
||||
java::GeckoHlsDemuxerWrapper::GlobalRef mHlsDemuxerWrapper;
|
||||
};
|
||||
|
||||
class HLSTrackDemuxer : public MediaTrackDemuxer
|
||||
{
|
||||
public:
|
||||
HLSTrackDemuxer(HLSDemuxer* aParent,
|
||||
TrackInfo::TrackType aType);
|
||||
~HLSTrackDemuxer();
|
||||
UniquePtr<TrackInfo> GetInfo() const override;
|
||||
|
||||
RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
|
||||
|
||||
RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
|
||||
|
||||
void Reset() override;
|
||||
|
||||
nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;
|
||||
|
||||
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreshold) override;
|
||||
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
void BreakCycles() override;
|
||||
|
||||
bool GetSamplesMayBlock() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// Update the timestamp of the next keyframe if there's one.
|
||||
void UpdateNextKeyFrameTime();
|
||||
|
||||
// Runs on HLSDemuxer's task queue.
|
||||
RefPtr<SeekPromise> DoSeek(const media::TimeUnit& aTime);
|
||||
RefPtr<SamplesPromise> DoGetSamples(int32_t aNumSamples);
|
||||
RefPtr<SkipAccessPointPromise> DoSkipToNextRandomAccessPoint(
|
||||
const media::TimeUnit& aTimeThreshold);
|
||||
|
||||
CryptoSample ExtractCryptoSample(size_t aSampleSize,
|
||||
java::sdk::CryptoInfo::LocalRef aCryptoInfo);
|
||||
RefPtr<MediaRawData> ConvertToMediaRawData(java::GeckoHlsSample::LocalRef aSample);
|
||||
|
||||
RefPtr<HLSDemuxer> mParent;
|
||||
TrackInfo::TrackType mType;
|
||||
Maybe<media::TimeUnit> mNextKeyframeTime;
|
||||
int32_t mLastFormatIndex = -1;
|
||||
// Queued samples extracted by the demuxer, but not yet returned.
|
||||
RefPtr<MediaRawData> mQueuedSample;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
72
dom/media/hls/HLSResource.cpp
Normal file
72
dom/media/hls/HLSResource.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "HLSResource.h"
|
||||
#include "HLSUtils.h"
|
||||
|
||||
using namespace mozilla::java;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
HlsResourceCallbacksSupport::HlsResourceCallbacksSupport(HLSResource* aResource)
|
||||
{
|
||||
MOZ_ASSERT(aResource);
|
||||
mResource = aResource;
|
||||
}
|
||||
|
||||
void
|
||||
HlsResourceCallbacksSupport::OnDataArrived()
|
||||
{
|
||||
MOZ_ASSERT(mResource);
|
||||
mResource->onDataAvailable();
|
||||
}
|
||||
|
||||
void
|
||||
HlsResourceCallbacksSupport::OnError(int aErrorCode)
|
||||
{
|
||||
MOZ_ASSERT(mResource);
|
||||
}
|
||||
|
||||
HLSResource::HLSResource(MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel,
|
||||
nsIURI* aURI,
|
||||
const MediaContainerType& aContainerType)
|
||||
: BaseMediaResource(aCallback, aChannel, aURI, aContainerType)
|
||||
{
|
||||
nsCString spec;
|
||||
nsresult rv = aURI->GetSpec(spec);
|
||||
(void)rv;
|
||||
HlsResourceCallbacksSupport::Init();
|
||||
mJavaCallbacks = GeckoHlsResourceWrapper::HlsResourceCallbacks::New();
|
||||
HlsResourceCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||
mozilla::MakeUnique<HlsResourceCallbacksSupport>(this));
|
||||
mHlsResourceWrapper = java::GeckoHlsResourceWrapper::Create(NS_ConvertUTF8toUTF16(spec),
|
||||
mJavaCallbacks);
|
||||
MOZ_ASSERT(mHlsResourceWrapper);
|
||||
}
|
||||
|
||||
void
|
||||
HLSResource::onDataAvailable()
|
||||
{
|
||||
MOZ_ASSERT(mCallback);
|
||||
HLS_DEBUG("HLSResource", "onDataAvailable");
|
||||
mCallback->NotifyDataArrived();
|
||||
}
|
||||
|
||||
HLSResource::~HLSResource()
|
||||
{
|
||||
if (mJavaCallbacks) {
|
||||
HlsResourceCallbacksSupport::DisposeNative(mJavaCallbacks);
|
||||
mJavaCallbacks = nullptr;
|
||||
}
|
||||
if (mHlsResourceWrapper) {
|
||||
mHlsResourceWrapper->Destroy();
|
||||
mHlsResourceWrapper = nullptr;
|
||||
}
|
||||
HLS_DEBUG("HLSResource", "Destroy");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
128
dom/media/hls/HLSResource.h
Normal file
128
dom/media/hls/HLSResource.h
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef HLSResource_h_
|
||||
#define HLSResource_h_
|
||||
|
||||
#include "GeneratedJNINatives.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#include "HLSUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#define UNIMPLEMENTED() HLS_DEBUG("HLSResource", "UNIMPLEMENTED FUNCTION")
|
||||
|
||||
using namespace mozilla::java;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class HLSResource;
|
||||
|
||||
class HlsResourceCallbacksSupport
|
||||
: public GeckoHlsResourceWrapper::HlsResourceCallbacks::Natives<HlsResourceCallbacksSupport>
|
||||
{
|
||||
public:
|
||||
typedef GeckoHlsResourceWrapper::HlsResourceCallbacks::Natives<HlsResourceCallbacksSupport> NativeCallbacks;
|
||||
using NativeCallbacks::DisposeNative;
|
||||
using NativeCallbacks::AttachNative;
|
||||
|
||||
HlsResourceCallbacksSupport(HLSResource* aResource);
|
||||
void OnDataArrived();
|
||||
void OnError(int aErrorCode);
|
||||
|
||||
private:
|
||||
HLSResource* mResource;
|
||||
};
|
||||
|
||||
class HLSResource final : public BaseMediaResource
|
||||
{
|
||||
public:
|
||||
HLSResource(MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel,
|
||||
nsIURI* aURI,
|
||||
const MediaContainerType& aContainerType);
|
||||
~HLSResource();
|
||||
nsresult Close() override { return NS_OK; }
|
||||
void Suspend(bool aCloseImmediately) override { UNIMPLEMENTED(); }
|
||||
void Resume() override { UNIMPLEMENTED(); }
|
||||
bool CanClone() override { UNIMPLEMENTED(); return false; }
|
||||
already_AddRefed<MediaResource> CloneData(MediaResourceCallback*) override { UNIMPLEMENTED(); return nullptr; }
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override { UNIMPLEMENTED(); }
|
||||
void SetPlaybackRate(uint32_t aBytesPerSecond) override { UNIMPLEMENTED(); }
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
|
||||
bool ShouldCacheReads() override { UNIMPLEMENTED(); return false; }
|
||||
int64_t Tell() override { UNIMPLEMENTED(); return -1; }
|
||||
void Pin() override { UNIMPLEMENTED(); }
|
||||
void Unpin() override { UNIMPLEMENTED(); }
|
||||
double GetDownloadRate(bool* aIsReliable) override { UNIMPLEMENTED(); *aIsReliable = false; return 0; }
|
||||
int64_t GetLength() override { UNIMPLEMENTED(); return -1; }
|
||||
int64_t GetNextCachedData(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
|
||||
int64_t GetCachedDataEnd(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
|
||||
bool IsDataCachedToEndOfResource(int64_t aOffset) override { UNIMPLEMENTED(); return false; }
|
||||
bool IsSuspendedByCache() override { UNIMPLEMENTED(); return false; }
|
||||
bool IsSuspended() override { UNIMPLEMENTED(); return false; }
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
|
||||
nsresult Open(nsIStreamListener** aStreamListener) override { UNIMPLEMENTED(); return NS_OK; }
|
||||
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (!secMan || !mChannel)
|
||||
return nullptr;
|
||||
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsTransportSeekable() override { return true; }
|
||||
|
||||
const MediaContainerType& GetContentType() const override { return mContainerType; }
|
||||
|
||||
bool IsLiveStream() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsExpectingMoreData() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
java::GeckoHlsResourceWrapper::GlobalRef GetResourceWrapper() {
|
||||
return mHlsResourceWrapper;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class HlsResourceCallbacksSupport;
|
||||
|
||||
void onDataAvailable();
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
size_t size = MediaResource::SizeOfExcludingThis(aMallocSizeOf);
|
||||
size += mContainerType.SizeOfExcludingThis(aMallocSizeOf);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
java::GeckoHlsResourceWrapper::GlobalRef mHlsResourceWrapper;
|
||||
java::GeckoHlsResourceWrapper::HlsResourceCallbacks::GlobalRef mJavaCallbacks;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* HLSResource_h_ */
|
7
dom/media/hls/HLSUtils.cpp
Normal file
7
dom/media/hls/HLSUtils.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "HLSUtils.h"
|
||||
|
||||
mozilla::LogModule* GetHLSLog()
|
||||
{
|
||||
static mozilla::LazyLogModule sLogModule("HLS");
|
||||
return sLogModule;
|
||||
}
|
17
dom/media/hls/HLSUtils.h
Normal file
17
dom/media/hls/HLSUtils.h
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef HLSUtils_h_
|
||||
#define HLSUtils_h_
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
// Logger
|
||||
mozilla::LogModule* GetHLSLog();
|
||||
|
||||
#define HLS_DEBUG(TAG, format, ...) MOZ_LOG(GetHLSLog(), mozilla::LogLevel::Debug, (TAG "(%p)::%s: " format, this, __func__, ##__VA_ARGS__))
|
||||
#define HLS_DEBUG_NON_MEMBER(TAG, format, ...) MOZ_LOG(GetHLSLog(), mozilla::LogLevel::Debug, (TAG " %s: " format, __func__, ##__VA_ARGS__))
|
||||
|
||||
#endif // HLSUtils_h_
|
26
dom/media/hls/moz.build
Normal file
26
dom/media/hls/moz.build
Normal file
@ -0,0 +1,26 @@
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
|
||||
EXPORTS += [
|
||||
'HLSDecoder.h',
|
||||
'HLSDemuxer.h',
|
||||
'HLSResource.h',
|
||||
'HLSUtils.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'HLSDecoder.cpp',
|
||||
'HLSDemuxer.cpp',
|
||||
'HLSResource.cpp',
|
||||
'HLSUtils.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
@ -53,6 +53,9 @@ DIRS += [
|
||||
if CONFIG['MOZ_ANDROID_OMX']:
|
||||
DIRS += ['android']
|
||||
|
||||
if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
|
||||
DIRS += ['hls']
|
||||
|
||||
if CONFIG['MOZ_FMP4']:
|
||||
DIRS += ['fmp4']
|
||||
|
||||
@ -313,6 +316,9 @@ if CONFIG['ANDROID_VERSION'] > '15':
|
||||
if CONFIG['MOZ_GONK_MEDIACODEC']:
|
||||
DEFINES['MOZ_GONK_MEDIACODEC'] = True
|
||||
|
||||
if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
|
||||
DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC warnings being treated as errors:
|
||||
|
@ -420,17 +420,7 @@ public:
|
||||
return;
|
||||
}
|
||||
if (ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo()) {
|
||||
// In general the element is always styled by the time we're applying XBL
|
||||
// bindings, because we need to style the element to know what the binding
|
||||
// URI is. However, programmatic consumers of the XBL service (like the
|
||||
// XML pretty printer) _can_ apply bindings without having styled the bound
|
||||
// element. We could assert against this and require the callers manually
|
||||
// resolve the style first, but it's easy enough to just handle here.
|
||||
if (MOZ_UNLIKELY(!mElement->HasServoData())) {
|
||||
servoSet->StyleNewSubtree(mElement);
|
||||
} else {
|
||||
servoSet->StyleNewChildren(mElement);
|
||||
}
|
||||
servoSet->StyleNewlyBoundElement(mElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ template <typename T>
|
||||
inline ProxyUniquePtr<T>
|
||||
ToProxyUniquePtr(const RefPtr<T>& aRefPtr)
|
||||
{
|
||||
MOZ_ASSERT(IsProxy(aRawPtr));
|
||||
MOZ_ASSERT(IsProxy(aRefPtr));
|
||||
MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) ||
|
||||
(XRE_IsContentProcess() && IsCurrentThreadMTA()));
|
||||
|
||||
|
@ -424,10 +424,6 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile)
|
||||
// Cache this module for later
|
||||
mModules.Put(spec, entry);
|
||||
|
||||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information
|
||||
xpc::SetLocationForGlobal(entryObj, spec);
|
||||
|
||||
// The hash owns the ModuleEntry now, forget about it
|
||||
return entry.forget();
|
||||
}
|
||||
@ -465,6 +461,7 @@ mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||
|
||||
void
|
||||
mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
|
||||
nsACString& aLocation,
|
||||
JSAddonId* aAddonID,
|
||||
MutableHandleObject aGlobal)
|
||||
{
|
||||
@ -507,6 +504,10 @@ mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information
|
||||
xpc::SetLocationForGlobal(global, aLocation);
|
||||
|
||||
aGlobal.set(global);
|
||||
}
|
||||
|
||||
@ -516,9 +517,12 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||
nsIURI* aURI,
|
||||
bool* aRealFile)
|
||||
{
|
||||
nsAutoCString nativePath;
|
||||
NS_ENSURE_SUCCESS(aURI->GetSpec(nativePath), nullptr);
|
||||
|
||||
RootedObject globalObj(aCx);
|
||||
|
||||
CreateLoaderGlobal(aCx, MapURIToAddonID(aURI), &globalObj);
|
||||
CreateLoaderGlobal(aCx, nativePath, MapURIToAddonID(aURI), &globalObj);
|
||||
|
||||
// |thisObj| is the object we set properties on for a particular .jsm.
|
||||
// XXX Right now, thisObj is always globalObj, but if we start
|
||||
@ -558,10 +562,6 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString nativePath;
|
||||
rv = aURI->GetSpec(nativePath);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
// Expose the URI from which the script was imported through a special
|
||||
// variable that we insert into the JSM.
|
||||
RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
|
||||
@ -991,10 +991,6 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information
|
||||
xpc::SetLocationForGlobal(newEntry->obj, aLocation);
|
||||
|
||||
mod = newEntry;
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,7 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
|
||||
void UnloadModules();
|
||||
|
||||
void CreateLoaderGlobal(JSContext* aCx,
|
||||
nsACString& aLocation,
|
||||
JSAddonId* aAddonID,
|
||||
JS::MutableHandleObject aGlobal);
|
||||
|
||||
|
@ -1555,7 +1555,7 @@ needs-focus == 568441.html 568441-ref.html
|
||||
== 571347-1b.html 571347-1-ref.html
|
||||
== 571347-2a.html 571347-2-ref.html
|
||||
== 571347-2b.html 571347-2-ref.html
|
||||
fails-if(styloVsGecko||stylo) == 571347-2c.html 571347-2-ref.html
|
||||
== 571347-2c.html 571347-2-ref.html
|
||||
== 571347-2d.html 571347-2-ref.html
|
||||
== 571347-3.html 571347-3-ref.html
|
||||
== 572598-1.html 572598-ref.html
|
||||
@ -1667,7 +1667,7 @@ fuzzy-if(Android,8,500) fuzzy-if(skiaContent,2,1) fuzzy-if(webrender,3,19) == 63
|
||||
fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html
|
||||
== 641770-1.html 641770-1-ref.html
|
||||
== 641856-1.html 641856-1-ref.html
|
||||
fails-if(styloVsGecko||stylo) == 645491-1.html 645491-1-ref.html
|
||||
== 645491-1.html 645491-1-ref.html
|
||||
== 645647-1.html 645647-1-ref.html
|
||||
== 645647-2.html 645647-2-ref.html
|
||||
== 645768-1.html 645768-1-ref.html
|
||||
|
9
layout/reftests/css-import/1331291-1.html
Normal file
9
layout/reftests/css-import/1331291-1.html
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
@import url(subdir/sheet.css);
|
||||
</style>
|
||||
<script>
|
||||
document.styleSheets[0].cssRules[0].styleSheet
|
||||
.insertRule("* { background: url(1x1-green-in-subdir.png) red; }", 0);
|
||||
</script>
|
@ -8,6 +8,7 @@ random-if(styloVsGecko||stylo) == 445415-1a.xhtml 445415-1-ref.xhtml
|
||||
== 445415-1b.xhtml 445415-1-ref.xhtml
|
||||
== 445415-2a.xhtml 445415-2-ref.xhtml
|
||||
fails-if(styloVsGecko||stylo) == 445415-2b.xhtml 445415-2-ref.xhtml
|
||||
== 1331291-1.html green.html
|
||||
== 1368782-1.html green.html
|
||||
== 1368782-2.html green.html
|
||||
== 1368782-3.html green.html
|
||||
|
BIN
layout/reftests/css-import/subdir/1x1-green-in-subdir.png
Normal file
BIN
layout/reftests/css-import/subdir/1x1-green-in-subdir.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
0
layout/reftests/css-import/subdir/sheet.css
Normal file
0
layout/reftests/css-import/subdir/sheet.css
Normal file
@ -374,9 +374,14 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
|
||||
bool forAnimationOnly =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForAnimationOnly;
|
||||
#ifdef DEBUG
|
||||
bool forNewlyBoundElement =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForNewlyBoundElement;
|
||||
#endif
|
||||
bool postTraversalRequired = Servo_TraverseSubtree(
|
||||
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
|
||||
MOZ_ASSERT(!(isInitial || forReconstruct) || !postTraversalRequired);
|
||||
MOZ_ASSERT(!(isInitial || forReconstruct || forNewlyBoundElement) ||
|
||||
!postTraversalRequired);
|
||||
|
||||
// Don't need to trigger a second traversal if this restyle only needs
|
||||
// animation-only restyle.
|
||||
@ -955,6 +960,34 @@ ServoStyleSet::StyleNewChildren(Element* aParent)
|
||||
// or some of its other children might have pending restyles.
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleNewlyBoundElement(Element* aElement)
|
||||
{
|
||||
PreTraverse();
|
||||
|
||||
// In general the element is always styled by the time we're applying XBL
|
||||
// bindings, because we need to style the element to know what the binding
|
||||
// URI is. However, programmatic consumers of the XBL service (like the
|
||||
// XML pretty printer) _can_ apply bindings without having styled the bound
|
||||
// element. We could assert against this and require the callers manually
|
||||
// resolve the style first, but it's easy enough to just handle here.
|
||||
//
|
||||
// Also, when applying XBL bindings to elements within a display:none or
|
||||
// unstyled subtree (for example, when <object> elements are wrapped to be
|
||||
// exposed to JS), we need to tell the traversal that it is OK to
|
||||
// skip restyling, rather than panic when trying to unwrap the styles
|
||||
// it expects to have just computed.
|
||||
|
||||
TraversalRootBehavior rootBehavior =
|
||||
MOZ_UNLIKELY(!aElement->HasServoData())
|
||||
? TraversalRootBehavior::Normal
|
||||
: TraversalRootBehavior::UnstyledChildrenOnly;
|
||||
|
||||
PrepareAndTraverseSubtree(aElement,
|
||||
rootBehavior,
|
||||
TraversalRestyleBehavior::ForNewlyBoundElement);
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
|
||||
{
|
||||
|
@ -305,6 +305,14 @@ public:
|
||||
*/
|
||||
void StyleNewChildren(dom::Element* aParent);
|
||||
|
||||
/**
|
||||
* Eagerly styles the children of an element that has just had an XBL
|
||||
* binding applied to it. Some XBL consumers attach bindings to elements
|
||||
* that have not been styled yet, and in such cases, this will do the
|
||||
* equivalent of StyleNewSubtree instead.
|
||||
*/
|
||||
void StyleNewlyBoundElement(dom::Element* aElement);
|
||||
|
||||
/**
|
||||
* Like StyleNewSubtree, but in response to a request to reconstruct frames
|
||||
* for the given subtree, and so works on elements that already have
|
||||
|
@ -176,7 +176,12 @@ ServoStyleSheet::ParseSheet(css::Loader* aLoader,
|
||||
void
|
||||
ServoStyleSheet::LoadFailed()
|
||||
{
|
||||
Inner()->mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
|
||||
if (!Inner()->mSheet) {
|
||||
// Only create empty stylesheet if this is a top level stylesheet.
|
||||
// The raw sheet for stylesheet of @import rule is already set in
|
||||
// loader, and we should not touch it.
|
||||
Inner()->mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
|
||||
}
|
||||
Inner()->mURLData = URLExtraData::Dummy();
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user