mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Merge autoland to m-c, a=merge
MozReview-Commit-ID: 6ChkHqkFGsA
This commit is contained in:
commit
da94b3af3f
@ -54,11 +54,7 @@
|
|||||||
<li>&aboutPrivateBrowsing.info.downloads;</li>
|
<li>&aboutPrivateBrowsing.info.downloads;</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>&aboutPrivateBrowsing.note.before;<strong>&aboutPrivateBrowsing.note.emphasize;</strong>&aboutPrivateBrowsing.note.after;</p>
|
||||||
&aboutPrivateBrowsing.note.before;
|
|
||||||
<strong>&aboutPrivateBrowsing.note.emphasize;</strong>
|
|
||||||
&aboutPrivateBrowsing.note.after;
|
|
||||||
</p>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<h2 id="tpSubHeader" class="about-subheader">
|
<h2 id="tpSubHeader" class="about-subheader">
|
||||||
@ -75,9 +71,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section-main">
|
<section class="section-main">
|
||||||
<p class="about-info">&aboutPrivateBrowsing.learnMore2;
|
<p class="about-info">&aboutPrivateBrowsing.learnMore3.before;<a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore3.title;</a>&aboutPrivateBrowsing.learnMore3.after;</p>
|
||||||
<a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore2.title;</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,11 @@ ac_add_options --disable-install-strip
|
|||||||
ac_add_options --enable-verify-mar
|
ac_add_options --enable-verify-mar
|
||||||
ac_add_options --enable-profiling
|
ac_add_options --enable-profiling
|
||||||
ac_add_options --enable-instruments
|
ac_add_options --enable-instruments
|
||||||
ac_add_options --enable-dtrace
|
|
||||||
|
# Cross-universal builds fail when dtrace is enabled
|
||||||
|
if test `uname -s` != Linux; then
|
||||||
|
ac_add_options --enable-dtrace
|
||||||
|
fi
|
||||||
|
|
||||||
if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
|
if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
|
||||||
ac_add_options --with-macbundlename-prefix=Firefox
|
ac_add_options --with-macbundlename-prefix=Firefox
|
||||||
|
@ -23,8 +23,9 @@
|
|||||||
<!ENTITY aboutPrivateBrowsing.note.before "Private Browsing ">
|
<!ENTITY aboutPrivateBrowsing.note.before "Private Browsing ">
|
||||||
<!ENTITY aboutPrivateBrowsing.note.emphasize "doesn’t make you anonymous">
|
<!ENTITY aboutPrivateBrowsing.note.emphasize "doesn’t make you anonymous">
|
||||||
<!ENTITY aboutPrivateBrowsing.note.after " on the Internet. Your employer or Internet service provider can still know what page you visit.">
|
<!ENTITY aboutPrivateBrowsing.note.after " on the Internet. Your employer or Internet service provider can still know what page you visit.">
|
||||||
<!ENTITY aboutPrivateBrowsing.learnMore2 "Learn more about">
|
<!ENTITY aboutPrivateBrowsing.learnMore3.before "Learn more about ">
|
||||||
<!ENTITY aboutPrivateBrowsing.learnMore2.title "Private Browsing">
|
<!ENTITY aboutPrivateBrowsing.learnMore3.title "Private Browsing">
|
||||||
|
<!ENTITY aboutPrivateBrowsing.learnMore3.after ".">
|
||||||
|
|
||||||
<!ENTITY trackingProtection.title "Tracking Protection">
|
<!ENTITY trackingProtection.title "Tracking Protection">
|
||||||
<!ENTITY trackingProtection.description2 "Some websites use trackers that can monitor your activity across the Internet. With Tracking Protection Firefox will block many trackers that can collect information about your browsing behavior.">
|
<!ENTITY trackingProtection.description2 "Some websites use trackers that can monitor your activity across the Internet. With Tracking Protection Firefox will block many trackers that can collect information about your browsing behavior.">
|
||||||
|
@ -132,17 +132,13 @@ PluginContent.prototype = {
|
|||||||
switch (aTopic) {
|
switch (aTopic) {
|
||||||
case "decoder-doctor-notification":
|
case "decoder-doctor-notification":
|
||||||
let data = JSON.parse(aData);
|
let data = JSON.parse(aData);
|
||||||
if (this.haveShownNotification &&
|
let type = data.type.toLowerCase();
|
||||||
|
if (type == "cannot-play" &&
|
||||||
|
this.haveShownNotification &&
|
||||||
aSubject.top.document == this.content.document &&
|
aSubject.top.document == this.content.document &&
|
||||||
data.formats.toLowerCase().includes("application/x-mpegurl", 0)) {
|
data.formats.toLowerCase().includes("application/x-mpegurl", 0)) {
|
||||||
let principal = this.content.document.nodePrincipal;
|
|
||||||
let location = this.content.document.location.href;
|
|
||||||
this.global.content.pluginRequiresReload = true;
|
this.global.content.pluginRequiresReload = true;
|
||||||
this.global.sendAsyncMessage("PluginContent:ShowClickToPlayNotification",
|
this.updateNotificationUI(this.content.document);
|
||||||
{ plugins: [...this.pluginData.values()],
|
|
||||||
showNow: true,
|
|
||||||
location: location,
|
|
||||||
}, null, principal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -235,6 +231,12 @@ PluginContent.prototype = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _getPluginInfoForTag is called when iterating the plugins for a document,
|
||||||
|
* and what we get from nsIDOMWindowUtils is an nsIPluginTag, and not an
|
||||||
|
* nsIObjectLoadingContent. This only should happen if the plugin is
|
||||||
|
* click-to-play (see bug 1186948).
|
||||||
|
*/
|
||||||
_getPluginInfoForTag: function(pluginTag, tagMimetype) {
|
_getPluginInfoForTag: function(pluginTag, tagMimetype) {
|
||||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||||
|
|
||||||
@ -269,7 +271,11 @@ PluginContent.prototype = {
|
|||||||
pluginName: pluginName,
|
pluginName: pluginName,
|
||||||
pluginTag: pluginTag,
|
pluginTag: pluginTag,
|
||||||
permissionString: permissionString,
|
permissionString: permissionString,
|
||||||
fallbackType: null,
|
// Since we should only have entered _getPluginInfoForTag when
|
||||||
|
// examining a click-to-play plugin, we can safely hard-code
|
||||||
|
// this fallback type, since we don't actually have an
|
||||||
|
// nsIObjectLoadingContent to check.
|
||||||
|
fallbackType: Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
|
||||||
blocklistState: blocklistState,
|
blocklistState: blocklistState,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -83,6 +83,7 @@ AC_CHECK_PROGS(RANLIB, "${TOOLCHAIN_PREFIX}ranlib", :)
|
|||||||
AC_CHECK_PROGS(AR, "${TOOLCHAIN_PREFIX}ar", :)
|
AC_CHECK_PROGS(AR, "${TOOLCHAIN_PREFIX}ar", :)
|
||||||
AC_CHECK_PROGS(AS, "${TOOLCHAIN_PREFIX}as", :)
|
AC_CHECK_PROGS(AS, "${TOOLCHAIN_PREFIX}as", :)
|
||||||
AC_CHECK_PROGS(LD, "${TOOLCHAIN_PREFIX}ld", :)
|
AC_CHECK_PROGS(LD, "${TOOLCHAIN_PREFIX}ld", :)
|
||||||
|
AC_CHECK_PROGS(LIPO, "${TOOLCHAIN_PREFIX}lipo", :)
|
||||||
AC_CHECK_PROGS(STRIP, "${TOOLCHAIN_PREFIX}strip", :)
|
AC_CHECK_PROGS(STRIP, "${TOOLCHAIN_PREFIX}strip", :)
|
||||||
AC_CHECK_PROGS(WINDRES, "${TOOLCHAIN_PREFIX}windres", :)
|
AC_CHECK_PROGS(WINDRES, "${TOOLCHAIN_PREFIX}windres", :)
|
||||||
AC_CHECK_PROGS(OTOOL, "${TOOLCHAIN_PREFIX}otool", :)
|
AC_CHECK_PROGS(OTOOL, "${TOOLCHAIN_PREFIX}otool", :)
|
||||||
|
@ -4,13 +4,16 @@
|
|||||||
|
|
||||||
mk_add_options MOZ_UNIFY_BDATE=1
|
mk_add_options MOZ_UNIFY_BDATE=1
|
||||||
|
|
||||||
DARWIN_VERSION=`uname -r`
|
DARWIN_VERSION=10
|
||||||
ac_add_app_options i386 --target=i386-apple-darwin$DARWIN_VERSION
|
ac_add_app_options i386 --target=i386-apple-darwin$DARWIN_VERSION
|
||||||
ac_add_app_options x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION
|
ac_add_app_options x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION
|
||||||
ac_add_app_options i386 --with-unify-dist=../x86_64/dist
|
ac_add_app_options i386 --with-unify-dist=../x86_64/dist
|
||||||
ac_add_app_options x86_64 --with-unify-dist=../i386/dist
|
ac_add_app_options x86_64 --with-unify-dist=../i386/dist
|
||||||
|
|
||||||
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.7.sdk
|
if ! test `uname -s` = Linux; then
|
||||||
|
# Cross-universal builds already do the equivalent of this by setting -isysroot directly
|
||||||
|
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.7.sdk
|
||||||
|
fi
|
||||||
|
|
||||||
. $topsrcdir/build/macosx/mozconfig.common
|
. $topsrcdir/build/macosx/mozconfig.common
|
||||||
|
|
||||||
@ -35,12 +38,12 @@ if test "$MOZ_BUILD_APP" = "i386" -o "$MOZ_BUILD_APP" = "x86_64"; then
|
|||||||
CXX="$CXX -arch $TARGET_CPU"
|
CXX="$CXX -arch $TARGET_CPU"
|
||||||
|
|
||||||
# These must be set for cross builds, and don't hurt straight builds.
|
# These must be set for cross builds, and don't hurt straight builds.
|
||||||
RANLIB=ranlib
|
RANLIB="${TOOLCHAIN_PREFIX}ranlib"
|
||||||
AR=ar
|
AR="${TOOLCHAIN_PREFIX}ar"
|
||||||
AS=$CC
|
AS=$CC
|
||||||
LD=ld
|
LD=ld
|
||||||
STRIP="strip"
|
STRIP="strip"
|
||||||
OTOOL="otool"
|
OTOOL="${TOOLCHAIN_PREFIX}otool"
|
||||||
|
|
||||||
# Each per-CPU build should be entirely oblivious to the fact that a
|
# Each per-CPU build should be entirely oblivious to the fact that a
|
||||||
# universal binary will be produced. The exception is packager.mk, which
|
# universal binary will be produced. The exception is packager.mk, which
|
||||||
|
@ -726,13 +726,14 @@ gDevTools.getToolDefinitionArray()
|
|||||||
// and the new ones.
|
// and the new ones.
|
||||||
gDevTools.on("tool-registered", function (ev, toolId) {
|
gDevTools.on("tool-registered", function (ev, toolId) {
|
||||||
let toolDefinition = gDevTools._tools.get(toolId);
|
let toolDefinition = gDevTools._tools.get(toolId);
|
||||||
gDevToolsBrowser._addToolToWindows(toolDefinition);
|
// If the tool has been registered globally, add to all the
|
||||||
|
// available windows.
|
||||||
|
if (toolDefinition) {
|
||||||
|
gDevToolsBrowser._addToolToWindows(toolDefinition);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
gDevTools.on("tool-unregistered", function (ev, toolId) {
|
gDevTools.on("tool-unregistered", function (ev, toolId) {
|
||||||
if (typeof toolId != "string") {
|
|
||||||
toolId = toolId.id;
|
|
||||||
}
|
|
||||||
gDevToolsBrowser._removeToolFromWindows(toolId);
|
gDevToolsBrowser._removeToolFromWindows(toolId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,12 +140,16 @@ DevTools.prototype = {
|
|||||||
tool = this._tools.get(tool);
|
tool = this._tools.get(tool);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
let {Deprecated} = Cu.import("resource://gre/modules/Deprecated.jsm", {});
|
||||||
|
Deprecated.warning("Deprecation WARNING: gDevTools.unregisterTool(tool) is deprecated. " +
|
||||||
|
"You should unregister a tool using its toolId: " +
|
||||||
|
"gDevTools.unregisterTool(toolId).");
|
||||||
toolId = tool.id;
|
toolId = tool.id;
|
||||||
}
|
}
|
||||||
this._tools.delete(toolId);
|
this._tools.delete(toolId);
|
||||||
|
|
||||||
if (!isQuitApplication) {
|
if (!isQuitApplication) {
|
||||||
this.emit("tool-unregistered", tool);
|
this.emit("tool-unregistered", toolId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ skip-if = e10s # Bug 1069044 - destroyInspector may hang during shutdown
|
|||||||
[browser_toolbox_toggle.js]
|
[browser_toolbox_toggle.js]
|
||||||
[browser_toolbox_tool_ready.js]
|
[browser_toolbox_tool_ready.js]
|
||||||
[browser_toolbox_tool_remote_reopen.js]
|
[browser_toolbox_tool_remote_reopen.js]
|
||||||
|
[browser_toolbox_tools_per_toolbox_registration.js]
|
||||||
[browser_toolbox_transport_events.js]
|
[browser_toolbox_transport_events.js]
|
||||||
[browser_toolbox_view_source_01.js]
|
[browser_toolbox_view_source_01.js]
|
||||||
[browser_toolbox_view_source_02.js]
|
[browser_toolbox_view_source_02.js]
|
||||||
|
@ -71,9 +71,8 @@ function testUnregister()
|
|||||||
gDevTools.unregisterTool("test-tool");
|
gDevTools.unregisterTool("test-tool");
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolUnregistered(event, toolDefinition)
|
function toolUnregistered(event, toolId)
|
||||||
{
|
{
|
||||||
let toolId = toolDefinition.id;
|
|
||||||
is(toolId, "test-tool", "tool-unregistered event handler sent tool id");
|
is(toolId, "test-tool", "tool-unregistered event handler sent tool id");
|
||||||
|
|
||||||
ok(!gDevTools.getToolDefinitionMap().has(toolId), "tool removed from map");
|
ok(!gDevTools.getToolDefinitionMap().has(toolId), "tool removed from map");
|
||||||
|
@ -21,6 +21,7 @@ add_task(function* () {
|
|||||||
let target = TargetFactory.forTab(tab);
|
let target = TargetFactory.forTab(tab);
|
||||||
toolbox = yield gDevTools.showToolbox(target);
|
toolbox = yield gDevTools.showToolbox(target);
|
||||||
doc = toolbox.doc;
|
doc = toolbox.doc;
|
||||||
|
yield registerNewPerToolboxTool();
|
||||||
yield testSelectTool();
|
yield testSelectTool();
|
||||||
yield testOptionsShortcut();
|
yield testOptionsShortcut();
|
||||||
yield testOptions();
|
yield testOptions();
|
||||||
@ -46,6 +47,31 @@ function registerNewTool() {
|
|||||||
"The tool is registered");
|
"The tool is registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerNewPerToolboxTool() {
|
||||||
|
let toolDefinition = {
|
||||||
|
id: "test-pertoolbox-tool",
|
||||||
|
isTargetSupported: () => true,
|
||||||
|
visibilityswitch: "devtools.test-pertoolbox-tool.enabled",
|
||||||
|
url: "about:blank",
|
||||||
|
label: "perToolboxSomeLabel"
|
||||||
|
};
|
||||||
|
|
||||||
|
ok(gDevTools, "gDevTools exists");
|
||||||
|
ok(!gDevTools.getToolDefinitionMap().has("test-pertoolbox-tool"),
|
||||||
|
"The per-toolbox tool is not registered globally");
|
||||||
|
|
||||||
|
ok(toolbox, "toolbox exists");
|
||||||
|
ok(!toolbox.hasAdditionalTool("test-pertoolbox-tool"),
|
||||||
|
"The per-toolbox tool is not yet registered to the toolbox");
|
||||||
|
|
||||||
|
toolbox.addAdditionalTool(toolDefinition);
|
||||||
|
|
||||||
|
ok(!gDevTools.getToolDefinitionMap().has("test-pertoolbox-tool"),
|
||||||
|
"The per-toolbox tool is not registered globally");
|
||||||
|
ok(toolbox.hasAdditionalTool("test-pertoolbox-tool"),
|
||||||
|
"The per-toolbox tool has been registered to the toolbox");
|
||||||
|
}
|
||||||
|
|
||||||
function* testSelectTool() {
|
function* testSelectTool() {
|
||||||
info("Checking to make sure that the options panel can be selected.");
|
info("Checking to make sure that the options panel can be selected.");
|
||||||
|
|
||||||
@ -168,9 +194,13 @@ function* testToggleTools() {
|
|||||||
"#additional-tools-box input[type=checkbox]:not([data-unsupported])");
|
"#additional-tools-box input[type=checkbox]:not([data-unsupported])");
|
||||||
let enabledTools = [...toolNodes].filter(node => node.checked);
|
let enabledTools = [...toolNodes].filter(node => node.checked);
|
||||||
|
|
||||||
let toggleableTools = gDevTools.getDefaultTools().filter(tool => {
|
let toggleableTools = gDevTools.getDefaultTools()
|
||||||
return tool.visibilityswitch;
|
.filter(tool => {
|
||||||
}).concat(gDevTools.getAdditionalTools());
|
return tool.visibilityswitch;
|
||||||
|
})
|
||||||
|
.concat(gDevTools.getAdditionalTools())
|
||||||
|
.concat(toolbox.getAdditionalTools());
|
||||||
|
|
||||||
|
|
||||||
for (let node of toolNodes) {
|
for (let node of toolNodes) {
|
||||||
let id = node.getAttribute("id");
|
let id = node.getAttribute("id");
|
||||||
@ -235,7 +265,7 @@ function* toggleTool(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkUnregistered(toolId, deferred, event, data) {
|
function checkUnregistered(toolId, deferred, event, data) {
|
||||||
if (data.id == toolId) {
|
if (data == toolId) {
|
||||||
ok(true, "Correct tool removed");
|
ok(true, "Correct tool removed");
|
||||||
// checking tab on the toolbox
|
// checking tab on the toolbox
|
||||||
ok(!doc.getElementById("toolbox-tab-" + toolId),
|
ok(!doc.getElementById("toolbox-tab-" + toolId),
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const TEST_URL = `data:text/html,<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
test for registering and unregistering tools to a specific toolbox
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
const TOOL_ID = "test-toolbox-tool";
|
||||||
|
var toolbox;
|
||||||
|
var target;
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
addTab(TEST_URL).then(tab => {
|
||||||
|
target = TargetFactory.forTab(tab);
|
||||||
|
|
||||||
|
gDevTools.showToolbox(target)
|
||||||
|
.then(toolboxRegister)
|
||||||
|
.then(testToolRegistered);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolveToolInstanceBuild;
|
||||||
|
var waitForToolInstanceBuild = new Promise((resolve) => {
|
||||||
|
resolveToolInstanceBuild = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
var resolveToolInstanceDestroyed;
|
||||||
|
var waitForToolInstanceDestroyed = new Promise((resolve) => {
|
||||||
|
resolveToolInstanceDestroyed = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
function toolboxRegister(aToolbox) {
|
||||||
|
toolbox = aToolbox;
|
||||||
|
|
||||||
|
var resolveToolInstanceBuild;
|
||||||
|
|
||||||
|
waitForToolInstanceBuild = new Promise((resolve) => {
|
||||||
|
resolveToolInstanceBuild = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
info("add per-toolbox tool in the opened toolbox.");
|
||||||
|
|
||||||
|
toolbox.addAdditionalTool({
|
||||||
|
id: TOOL_ID,
|
||||||
|
label: "per-toolbox Test Tool",
|
||||||
|
inMenu: true,
|
||||||
|
isTargetSupported: () => true,
|
||||||
|
build: function () {
|
||||||
|
info("per-toolbox tool has been built.");
|
||||||
|
resolveToolInstanceBuild();
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy: () => {
|
||||||
|
info("per-toolbox tool has been destroyed.");
|
||||||
|
resolveToolInstanceDestroyed();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
key: "t"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testToolRegistered() {
|
||||||
|
ok(!gDevTools.getToolDefinitionMap().has(TOOL_ID), "per-toolbox tool is not registered globally");
|
||||||
|
ok(toolbox.hasAdditionalTool(TOOL_ID),
|
||||||
|
"per-toolbox tool registered to the specific toolbox");
|
||||||
|
|
||||||
|
// Test that the tool appeared in the UI.
|
||||||
|
let doc = toolbox.doc;
|
||||||
|
let tab = doc.getElementById("toolbox-tab-" + TOOL_ID);
|
||||||
|
ok(tab, "new tool's tab exists in toolbox UI");
|
||||||
|
|
||||||
|
let panel = doc.getElementById("toolbox-panel-" + TOOL_ID);
|
||||||
|
ok(panel, "new tool's panel exists in toolbox UI");
|
||||||
|
|
||||||
|
for (let win of getAllBrowserWindows()) {
|
||||||
|
let key = win.document.getElementById("key_" + TOOL_ID);
|
||||||
|
if (win.document == doc) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ok(!key, "key for new tool should not exists in the other browser windows");
|
||||||
|
let menuitem = win.document.getElementById("menuitem_" + TOOL_ID);
|
||||||
|
ok(!menuitem, "menu item should not exists in the other browser window");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the tool is built once selected and then test its unregistering.
|
||||||
|
info("select per-toolbox tool in the opened toolbox.");
|
||||||
|
gDevTools.showToolbox(target, TOOL_ID)
|
||||||
|
.then(waitForToolInstanceBuild)
|
||||||
|
.then(testUnregister);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllBrowserWindows() {
|
||||||
|
let wins = [];
|
||||||
|
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
while (enumerator.hasMoreElements()) {
|
||||||
|
wins.push(enumerator.getNext());
|
||||||
|
}
|
||||||
|
return wins;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUnregister() {
|
||||||
|
info("remove per-toolbox tool in the opened toolbox.");
|
||||||
|
toolbox.removeAdditionalTool(TOOL_ID);
|
||||||
|
|
||||||
|
Promise.all([
|
||||||
|
waitForToolInstanceDestroyed
|
||||||
|
]).then(toolboxToolUnregistered);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toolboxToolUnregistered() {
|
||||||
|
ok(!toolbox.hasAdditionalTool(TOOL_ID),
|
||||||
|
"per-toolbox tool unregistered from the specific toolbox");
|
||||||
|
|
||||||
|
// test that it disappeared from the UI
|
||||||
|
let doc = toolbox.doc;
|
||||||
|
let tab = doc.getElementById("toolbox-tab-" + TOOL_ID);
|
||||||
|
ok(!tab, "tool's tab was removed from the toolbox UI");
|
||||||
|
|
||||||
|
let panel = doc.getElementById("toolbox-panel-" + TOOL_ID);
|
||||||
|
ok(!panel, "tool's panel was removed from toolbox UI");
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
toolbox.destroy();
|
||||||
|
toolbox = null;
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
finish();
|
||||||
|
}
|
@ -186,15 +186,15 @@ OptionsPanel.prototype = {
|
|||||||
"tools-not-supported-label");
|
"tools-not-supported-label");
|
||||||
let atleastOneToolNotSupported = false;
|
let atleastOneToolNotSupported = false;
|
||||||
|
|
||||||
|
const toolbox = this.toolbox;
|
||||||
|
|
||||||
|
// Signal tool registering/unregistering globally (for the tools registered
|
||||||
|
// globally) and per toolbox (for the tools registered to a single toolbox).
|
||||||
let onCheckboxClick = function (id) {
|
let onCheckboxClick = function (id) {
|
||||||
let toolDefinition = gDevTools._tools.get(id);
|
let toolDefinition = gDevTools._tools.get(id) || toolbox.getToolDefinition(id);
|
||||||
// Set the kill switch pref boolean to true
|
// Set the kill switch pref boolean to true
|
||||||
Services.prefs.setBoolPref(toolDefinition.visibilityswitch, this.checked);
|
Services.prefs.setBoolPref(toolDefinition.visibilityswitch, this.checked);
|
||||||
if (this.checked) {
|
gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", id);
|
||||||
gDevTools.emit("tool-registered", id);
|
|
||||||
} else {
|
|
||||||
gDevTools.emit("tool-unregistered", toolDefinition);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let createToolCheckbox = tool => {
|
let createToolCheckbox = tool => {
|
||||||
@ -243,6 +243,13 @@ OptionsPanel.prototype = {
|
|||||||
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populating the additional toolbox-specific tools list that came
|
||||||
|
// from WebExtension add-ons.
|
||||||
|
for (let tool of this.toolbox.getAdditionalTools()) {
|
||||||
|
atleastOneAddon = true;
|
||||||
|
additionalToolsBox.appendChild(createToolCheckbox(tool));
|
||||||
|
}
|
||||||
|
|
||||||
if (!atleastOneAddon) {
|
if (!atleastOneAddon) {
|
||||||
additionalToolsBox.style.display = "none";
|
additionalToolsBox.style.display = "none";
|
||||||
}
|
}
|
||||||
|
@ -895,6 +895,7 @@ Toolbox.prototype = {
|
|||||||
* Add tabs to the toolbox UI for registered tools
|
* Add tabs to the toolbox UI for registered tools
|
||||||
*/
|
*/
|
||||||
_buildTabs: function () {
|
_buildTabs: function () {
|
||||||
|
// Build tabs for global registered tools.
|
||||||
for (let definition of gDevTools.getToolDefinitionArray()) {
|
for (let definition of gDevTools.getToolDefinitionArray()) {
|
||||||
this._buildTabForTool(definition);
|
this._buildTabForTool(definition);
|
||||||
}
|
}
|
||||||
@ -1252,6 +1253,81 @@ Toolbox.prototype = {
|
|||||||
this._addKeysToWindow();
|
this._addKeysToWindow();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily created map of the additional tools registered to this toolbox.
|
||||||
|
*
|
||||||
|
* @returns {Map<string, object>}
|
||||||
|
* a map of the tools definitions registered to this
|
||||||
|
* particular toolbox (the key is the toolId string, the value
|
||||||
|
* is the tool definition plain javascript object).
|
||||||
|
*/
|
||||||
|
get additionalToolDefinitions() {
|
||||||
|
if (!this._additionalToolDefinitions) {
|
||||||
|
this._additionalToolDefinitions = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._additionalToolDefinitions;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the array of the additional tools registered to this toolbox.
|
||||||
|
*
|
||||||
|
* @return {Array<object>}
|
||||||
|
* the array of additional tool definitions registered on this toolbox.
|
||||||
|
*/
|
||||||
|
getAdditionalTools() {
|
||||||
|
return Array.from(this.additionalToolDefinitions.values());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the existence of a additional tools registered to this toolbox by tool id.
|
||||||
|
*
|
||||||
|
* @param {string} toolId
|
||||||
|
* the id of the tool to test for existence.
|
||||||
|
*
|
||||||
|
* @return {boolean}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
hasAdditionalTool(toolId) {
|
||||||
|
return this.additionalToolDefinitions.has(toolId);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register and load an additional tool on this particular toolbox.
|
||||||
|
*
|
||||||
|
* @param {object} definition
|
||||||
|
* the additional tool definition to register and add to this toolbox.
|
||||||
|
*/
|
||||||
|
addAdditionalTool(definition) {
|
||||||
|
if (!definition.id) {
|
||||||
|
throw new Error("Tool definition id is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isToolRegistered(definition.id)) {
|
||||||
|
throw new Error("Tool definition already registered: " +
|
||||||
|
definition.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.additionalToolDefinitions.set(definition.id, definition);
|
||||||
|
this._buildTabForTool(definition);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister and unload an additional tool from this particular toolbox.
|
||||||
|
*
|
||||||
|
* @param {string} toolId
|
||||||
|
* the id of the additional tool to unregister and remove.
|
||||||
|
*/
|
||||||
|
removeAdditionalTool(toolId) {
|
||||||
|
if (!this.hasAdditionalTool(toolId)) {
|
||||||
|
throw new Error("Tool definition not registered to this toolbox: " +
|
||||||
|
toolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unloadTool(toolId);
|
||||||
|
this.additionalToolDefinitions.delete(toolId);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure the tool with the given id is loaded.
|
* Ensure the tool with the given id is loaded.
|
||||||
*
|
*
|
||||||
@ -1280,7 +1356,9 @@ Toolbox.prototype = {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
let definition = gDevTools.getToolDefinition(id);
|
// Retrieve the tool definition (from the global or the per-toolbox tool maps)
|
||||||
|
let definition = this.getToolDefinition(id);
|
||||||
|
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
deferred.reject(new Error("no such tool id " + id));
|
deferred.reject(new Error("no such tool id " + id));
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
@ -1907,41 +1985,47 @@ Toolbox.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return if the tool is available as a tab (i.e. if it's checked
|
* Test the availability of a tool (both globally registered tools and
|
||||||
* in the options panel). This is different from Toolbox.getPanel -
|
* additional tools registered to this toolbox) by tool id.
|
||||||
* a tool could be registered but not yet opened in which case
|
*
|
||||||
* isToolRegistered would return true but getPanel would return false.
|
* @param {string} toolId
|
||||||
|
* Id of the tool definition to search in the per-toolbox or globally
|
||||||
|
* registered tools.
|
||||||
|
*
|
||||||
|
* @returns {bool}
|
||||||
|
* Returns true if the tool is registered globally or on this toolbox.
|
||||||
*/
|
*/
|
||||||
isToolRegistered: function (toolId) {
|
isToolRegistered: function (toolId) {
|
||||||
return gDevTools.getToolDefinitionMap().has(toolId);
|
return !!this.getToolDefinition(toolId);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the tool-registered event.
|
* Return the tool definition registered globally or additional tools registered
|
||||||
* @param {string} event
|
* to this toolbox.
|
||||||
* Name of the event ("tool-registered")
|
*
|
||||||
* @param {string} toolId
|
* @param {string} toolId
|
||||||
* Id of the tool that was registered
|
* Id of the tool definition to retrieve for the per-toolbox and globally
|
||||||
|
* registered tools.
|
||||||
|
*
|
||||||
|
* @returns {object}
|
||||||
|
* The plain javascript object that represents the requested tool definition.
|
||||||
*/
|
*/
|
||||||
_toolRegistered: function (event, toolId) {
|
getToolDefinition: function (toolId) {
|
||||||
let tool = gDevTools.getToolDefinition(toolId);
|
return gDevTools.getToolDefinition(toolId) ||
|
||||||
this._buildTabForTool(tool);
|
this.additionalToolDefinitions.get(toolId);
|
||||||
// Emit the event so tools can listen to it from the toolbox level
|
|
||||||
// instead of gDevTools
|
|
||||||
this.emit("tool-registered", toolId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the tool-unregistered event.
|
* Internal helper that removes a loaded tool from the toolbox,
|
||||||
* @param {string} event
|
* it removes a loaded tool panel and tab from the toolbox without removing
|
||||||
* Name of the event ("tool-unregistered")
|
* its definition, so that it can still be listed in options and re-added later.
|
||||||
* @param {string|object} toolId
|
*
|
||||||
* Definition or id of the tool that was unregistered. Passing the
|
* @param {string} toolId
|
||||||
* tool id should be avoided as it is a temporary measure.
|
* Id of the tool to be removed.
|
||||||
*/
|
*/
|
||||||
_toolUnregistered: function (event, toolId) {
|
unloadTool: function (toolId) {
|
||||||
if (typeof toolId != "string") {
|
if (typeof toolId != "string") {
|
||||||
toolId = toolId.id;
|
throw new Error("Unexpected non-string toolId received.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._toolPanels.has(toolId)) {
|
if (this._toolPanels.has(toolId)) {
|
||||||
@ -1980,6 +2064,38 @@ Toolbox.prototype = {
|
|||||||
key.parentNode.removeChild(key);
|
key.parentNode.removeChild(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the tool-registered event.
|
||||||
|
* @param {string} event
|
||||||
|
* Name of the event ("tool-registered")
|
||||||
|
* @param {string} toolId
|
||||||
|
* Id of the tool that was registered
|
||||||
|
*/
|
||||||
|
_toolRegistered: function (event, toolId) {
|
||||||
|
let tool = this.getToolDefinition(toolId);
|
||||||
|
if (!tool) {
|
||||||
|
// Ignore if the tool is not found, when a per-toolbox tool
|
||||||
|
// has been toggle in the toolbox options view, every toolbox will receive
|
||||||
|
// the toolbox-register and toolbox-unregister events.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._buildTabForTool(tool);
|
||||||
|
// Emit the event so tools can listen to it from the toolbox level
|
||||||
|
// instead of gDevTools.
|
||||||
|
this.emit("tool-registered", toolId);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the tool-unregistered event.
|
||||||
|
* @param {string} event
|
||||||
|
* Name of the event ("tool-unregistered")
|
||||||
|
* @param {string} toolId
|
||||||
|
* id of the tool that was unregistered
|
||||||
|
*/
|
||||||
|
_toolUnregistered: function (event, toolId) {
|
||||||
|
this.unloadTool(toolId);
|
||||||
// Emit the event so tools can listen to it from the toolbox level
|
// Emit the event so tools can listen to it from the toolbox level
|
||||||
// instead of gDevTools
|
// instead of gDevTools
|
||||||
this.emit("tool-unregistered", toolId);
|
this.emit("tool-unregistered", toolId);
|
||||||
|
@ -4,45 +4,47 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Test for as-authored styles.
|
// Test for as-authored color styles.
|
||||||
|
|
||||||
function* createTestContent(style) {
|
/**
|
||||||
let html = `<style type="text/css">
|
* Array of test color objects:
|
||||||
${style}
|
* {String} name: name of the used & expected color format.
|
||||||
</style>
|
* {String} id: id of the element that will be created to test this color.
|
||||||
<div id="testid" class="testclass">Styled Node</div>`;
|
* {String} color: initial value of the color property applied to the test element.
|
||||||
let tab = yield addTab("data:text/html;charset=utf-8," +
|
* {String} result: expected value of the color property after edition.
|
||||||
encodeURIComponent(html));
|
*/
|
||||||
|
const colors = [
|
||||||
let {inspector, view} = yield openRuleView();
|
{name: "hex", id: "test1", color: "#f0c", result: "#0f0"},
|
||||||
yield selectNode("#testid", inspector);
|
{name: "rgb", id: "test2", color: "rgb(0,128,250)", result: "rgb(0, 255, 0)"},
|
||||||
return {view, tab};
|
// Test case preservation.
|
||||||
}
|
{name: "hex", id: "test3", color: "#F0C", result: "#0F0"},
|
||||||
|
];
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let colors = [
|
|
||||||
{name: "hex", text: "#f0c", result: "#0f0"},
|
|
||||||
{name: "rgb", text: "rgb(0,128,250)", result: "rgb(0, 255, 0)"},
|
|
||||||
// Test case preservation.
|
|
||||||
{name: "hex", text: "#F0C", result: "#0F0"},
|
|
||||||
];
|
|
||||||
|
|
||||||
Services.prefs.setCharPref("devtools.defaultColorUnit", "authored");
|
Services.prefs.setCharPref("devtools.defaultColorUnit", "authored");
|
||||||
|
|
||||||
for (let color of colors) {
|
let html = "";
|
||||||
let {view, tab} = yield createTestContent("#testid {" +
|
for (let {color, id} of colors) {
|
||||||
" color: " + color.text + ";" +
|
html += `<div id="${id}" style="color: ${color}">Styled Node</div>`;
|
||||||
"} ");
|
}
|
||||||
|
|
||||||
|
let tab = yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(html));
|
||||||
|
|
||||||
|
let {inspector, view} = yield openRuleView();
|
||||||
|
|
||||||
|
for (let color of colors) {
|
||||||
let cPicker = view.tooltips.colorPicker;
|
let cPicker = view.tooltips.colorPicker;
|
||||||
let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
|
let selector = "#" + color.id;
|
||||||
|
yield selectNode(selector, inspector);
|
||||||
|
|
||||||
|
let swatch = getRuleViewProperty(view, "element", "color").valueSpan
|
||||||
.querySelector(".ruleview-colorswatch");
|
.querySelector(".ruleview-colorswatch");
|
||||||
let onColorPickerReady = cPicker.once("ready");
|
let onColorPickerReady = cPicker.once("ready");
|
||||||
swatch.click();
|
swatch.click();
|
||||||
yield onColorPickerReady;
|
yield onColorPickerReady;
|
||||||
|
|
||||||
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
||||||
selector: "#testid",
|
selector,
|
||||||
name: "color",
|
name: "color",
|
||||||
value: "rgb(0, 255, 0)"
|
value: "rgb(0, 255, 0)"
|
||||||
});
|
});
|
||||||
@ -55,11 +57,11 @@ add_task(function* () {
|
|||||||
yield onHidden;
|
yield onHidden;
|
||||||
yield onRuleViewChanged;
|
yield onRuleViewChanged;
|
||||||
|
|
||||||
is(getRuleViewPropertyValue(view, "#testid", "color"), color.result,
|
is(getRuleViewPropertyValue(view, "element", "color"), color.result,
|
||||||
"changing the color preserved the unit for " + color.name);
|
"changing the color preserved the unit for " + color.name);
|
||||||
|
|
||||||
let target = TargetFactory.forTab(tab);
|
|
||||||
yield gDevTools.closeToolbox(target);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let target = TargetFactory.forTab(tab);
|
||||||
|
yield gDevTools.closeToolbox(target);
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
});
|
});
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
/* globals window, dumpn, gNetwork, $, EVENTS, NetMonitorView */
|
/* globals window, dumpn, gNetwork, $, EVENTS, NetMonitorView */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {Task} = require("devtools/shared/task");
|
const { Task } = require("devtools/shared/task");
|
||||||
const {writeHeaderText, getKeyWithEvent} = require("./request-utils");
|
const {
|
||||||
|
writeHeaderText,
|
||||||
loader.lazyRequireGetter(this, "NetworkHelper",
|
getKeyWithEvent,
|
||||||
"devtools/shared/webconsole/network-helper");
|
getUrlQuery,
|
||||||
|
parseQueryString,
|
||||||
|
} = require("./request-utils");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions handling the custom request view.
|
* Functions handling the custom request view.
|
||||||
@ -112,8 +114,7 @@ CustomRequestView.prototype = {
|
|||||||
* The URL to extract query string from.
|
* The URL to extract query string from.
|
||||||
*/
|
*/
|
||||||
updateCustomQuery: function (url) {
|
updateCustomQuery: function (url) {
|
||||||
let paramsArray = NetworkHelper.parseQueryString(
|
const paramsArray = parseQueryString(getUrlQuery(url));
|
||||||
NetworkHelper.nsIURL(url).query);
|
|
||||||
|
|
||||||
if (!paramsArray) {
|
if (!paramsArray) {
|
||||||
$("#custom-query").hidden = true;
|
$("#custom-query").hidden = true;
|
||||||
@ -135,7 +136,7 @@ CustomRequestView.prototype = {
|
|||||||
let queryString = writeQueryString(params);
|
let queryString = writeQueryString(params);
|
||||||
|
|
||||||
let url = $("#custom-url-value").value;
|
let url = $("#custom-url-value").value;
|
||||||
let oldQuery = NetworkHelper.nsIURL(url).query;
|
let oldQuery = getUrlQuery(url);
|
||||||
let path = url.replace(oldQuery, queryString);
|
let path = url.replace(oldQuery, queryString);
|
||||||
|
|
||||||
$("#custom-url-value").value = path;
|
$("#custom-url-value").value = path;
|
||||||
|
@ -8,9 +8,11 @@ const { LocalizationHelper } = require("devtools/shared/l10n");
|
|||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const appInfo = Services.appinfo;
|
const appInfo = Services.appinfo;
|
||||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||||
const { getFormDataSections } = require("devtools/client/netmonitor/request-utils");
|
const {
|
||||||
|
getFormDataSections,
|
||||||
loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
|
getUrlQuery,
|
||||||
|
parseQueryString,
|
||||||
|
} = require("devtools/client/netmonitor/request-utils");
|
||||||
|
|
||||||
loader.lazyGetter(this, "L10N", () => {
|
loader.lazyGetter(this, "L10N", () => {
|
||||||
return new LocalizationHelper("devtools/client/locales/har.properties");
|
return new LocalizationHelper("devtools/client/locales/har.properties");
|
||||||
@ -170,8 +172,7 @@ HarBuilder.prototype = {
|
|||||||
request.headers = this.appendHeadersPostData(request.headers, file);
|
request.headers = this.appendHeadersPostData(request.headers, file);
|
||||||
request.cookies = this.buildCookies(file.requestCookies);
|
request.cookies = this.buildCookies(file.requestCookies);
|
||||||
|
|
||||||
request.queryString = NetworkHelper.parseQueryString(
|
request.queryString = parseQueryString(getUrlQuery(file.url)) || [];
|
||||||
NetworkHelper.nsIURL(file.url).query) || [];
|
|
||||||
|
|
||||||
request.postData = this.buildPostData(file);
|
request.postData = this.buildPostData(file);
|
||||||
|
|
||||||
@ -280,7 +281,7 @@ HarBuilder.prototype = {
|
|||||||
this._options.getString
|
this._options.getString
|
||||||
).then(formDataSections => {
|
).then(formDataSections => {
|
||||||
formDataSections.forEach(section => {
|
formDataSections.forEach(section => {
|
||||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
let paramsArray = parseQueryString(section);
|
||||||
if (paramsArray) {
|
if (paramsArray) {
|
||||||
postData.params = [...postData.params, ...paramsArray];
|
postData.params = [...postData.params, ...paramsArray];
|
||||||
}
|
}
|
||||||
|
@ -56,14 +56,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Chart",
|
|||||||
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
||||||
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
||||||
|
|
||||||
Object.defineProperty(this, "NetworkHelper", {
|
|
||||||
get: function () {
|
|
||||||
return require("devtools/shared/webconsole/network-helper");
|
|
||||||
},
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object defining the network monitor controller components.
|
* Object defining the network monitor controller components.
|
||||||
*/
|
*/
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
/* exported $, $all */
|
/* exported $, $all */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function () {
|
|
||||||
return require("devtools/shared/webconsole/network-helper");
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
const {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
|
const {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
@ -20,9 +16,15 @@ const {ToolSidebar} = require("devtools/client/framework/sidebar");
|
|||||||
const {testing: isTesting} = require("devtools/shared/flags");
|
const {testing: isTesting} = require("devtools/shared/flags");
|
||||||
const {ViewHelpers, Heritage} = require("devtools/client/shared/widgets/view-helpers");
|
const {ViewHelpers, Heritage} = require("devtools/client/shared/widgets/view-helpers");
|
||||||
const {Filters} = require("./filter-predicates");
|
const {Filters} = require("./filter-predicates");
|
||||||
const {getFormDataSections,
|
const {
|
||||||
formDataURI,
|
formDataURI,
|
||||||
getUriHostPort} = require("./request-utils");
|
decodeUnicodeUrl,
|
||||||
|
getFormDataSections,
|
||||||
|
getUrlBaseName,
|
||||||
|
getUrlQuery,
|
||||||
|
getUrlHost,
|
||||||
|
parseQueryString,
|
||||||
|
} = require("./request-utils");
|
||||||
const {L10N} = require("./l10n");
|
const {L10N} = require("./l10n");
|
||||||
const {RequestsMenuView} = require("./requests-menu-view");
|
const {RequestsMenuView} = require("./requests-menu-view");
|
||||||
const {CustomRequestView} = require("./custom-request-view");
|
const {CustomRequestView} = require("./custom-request-view");
|
||||||
@ -552,7 +554,7 @@ NetworkDetailsView.prototype = {
|
|||||||
*/
|
*/
|
||||||
_setSummary: function (data) {
|
_setSummary: function (data) {
|
||||||
if (data.url) {
|
if (data.url) {
|
||||||
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(data.url));
|
let unicodeUrl = decodeUnicodeUrl(data.url);
|
||||||
$("#headers-summary-url-value").setAttribute("value", unicodeUrl);
|
$("#headers-summary-url-value").setAttribute("value", unicodeUrl);
|
||||||
$("#headers-summary-url-value").setAttribute("tooltiptext", unicodeUrl);
|
$("#headers-summary-url-value").setAttribute("tooltiptext", unicodeUrl);
|
||||||
$("#headers-summary-url").removeAttribute("hidden");
|
$("#headers-summary-url").removeAttribute("hidden");
|
||||||
@ -743,7 +745,7 @@ NetworkDetailsView.prototype = {
|
|||||||
* The request's url.
|
* The request's url.
|
||||||
*/
|
*/
|
||||||
_setRequestGetParams: function (url) {
|
_setRequestGetParams: function (url) {
|
||||||
let query = NetworkHelper.nsIURL(url).query;
|
let query = getUrlQuery(url);
|
||||||
if (query) {
|
if (query) {
|
||||||
this._addParams(this._paramsQueryString, query);
|
this._addParams(this._paramsQueryString, query);
|
||||||
}
|
}
|
||||||
@ -825,7 +827,7 @@ NetworkDetailsView.prototype = {
|
|||||||
* A query string of params (e.g. "?foo=bar&baz=42").
|
* A query string of params (e.g. "?foo=bar&baz=42").
|
||||||
*/
|
*/
|
||||||
_addParams: function (name, queryString) {
|
_addParams: function (name, queryString) {
|
||||||
let paramsArray = NetworkHelper.parseQueryString(queryString);
|
let paramsArray = parseQueryString(queryString);
|
||||||
if (!paramsArray) {
|
if (!paramsArray) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -918,7 +920,7 @@ NetworkDetailsView.prototype = {
|
|||||||
// Immediately display additional information about the image:
|
// Immediately display additional information about the image:
|
||||||
// file name, mime type and encoding.
|
// file name, mime type and encoding.
|
||||||
$("#response-content-image-name-value").setAttribute("value",
|
$("#response-content-image-name-value").setAttribute("value",
|
||||||
NetworkHelper.nsIURL(url).fileName);
|
getUrlBaseName(url));
|
||||||
$("#response-content-image-mime-value").setAttribute("value", mimeType);
|
$("#response-content-image-mime-value").setAttribute("value", mimeType);
|
||||||
|
|
||||||
// Wait for the image to load in order to display the width and height.
|
// Wait for the image to load in order to display the width and height.
|
||||||
@ -1126,7 +1128,7 @@ NetworkDetailsView.prototype = {
|
|||||||
setValue("#security-ciphersuite-value", securityInfo.cipherSuite);
|
setValue("#security-ciphersuite-value", securityInfo.cipherSuite);
|
||||||
|
|
||||||
// Host header
|
// Host header
|
||||||
let domain = getUriHostPort(url);
|
let domain = getUrlHost(url);
|
||||||
let hostHeader = L10N.getFormatStr("netmonitor.security.hostHeader",
|
let hostHeader = L10N.getFormatStr("netmonitor.security.hostHeader",
|
||||||
domain);
|
domain);
|
||||||
setValue("#security-info-host-header", hostHeader);
|
setValue("#security-info-host-header", hostHeader);
|
||||||
|
@ -13,7 +13,12 @@ const { gDevTools } = require("devtools/client/framework/devtools");
|
|||||||
const Menu = require("devtools/client/framework/menu");
|
const Menu = require("devtools/client/framework/menu");
|
||||||
const MenuItem = require("devtools/client/framework/menu-item");
|
const MenuItem = require("devtools/client/framework/menu-item");
|
||||||
const { L10N } = require("./l10n");
|
const { L10N } = require("./l10n");
|
||||||
const { formDataURI, getFormDataSections } = require("./request-utils");
|
const {
|
||||||
|
formDataURI,
|
||||||
|
getFormDataSections,
|
||||||
|
getUrlQuery,
|
||||||
|
parseQueryString,
|
||||||
|
} = require("./request-utils");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "HarExporter",
|
loader.lazyRequireGetter(this, "HarExporter",
|
||||||
"devtools/client/netmonitor/har/har-exporter", true);
|
"devtools/client/netmonitor/har/har-exporter", true);
|
||||||
@ -21,9 +26,6 @@ loader.lazyRequireGetter(this, "HarExporter",
|
|||||||
loader.lazyServiceGetter(this, "clipboardHelper",
|
loader.lazyServiceGetter(this, "clipboardHelper",
|
||||||
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "NetworkHelper",
|
|
||||||
"devtools/shared/webconsole/network-helper");
|
|
||||||
|
|
||||||
function RequestListContextMenu() {}
|
function RequestListContextMenu() {}
|
||||||
|
|
||||||
RequestListContextMenu.prototype = {
|
RequestListContextMenu.prototype = {
|
||||||
@ -56,8 +58,7 @@ RequestListContextMenu.prototype = {
|
|||||||
id: "request-menu-context-copy-url-params",
|
id: "request-menu-context-copy-url-params",
|
||||||
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
||||||
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
||||||
visible: !!(selectedItem &&
|
visible: !!(selectedItem && getUrlQuery(selectedItem.attachment.url)),
|
||||||
NetworkHelper.nsIURL(selectedItem.attachment.url).query),
|
|
||||||
click: () => this.copyUrlParams(),
|
click: () => this.copyUrlParams(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -203,7 +204,7 @@ RequestListContextMenu.prototype = {
|
|||||||
*/
|
*/
|
||||||
copyUrlParams() {
|
copyUrlParams() {
|
||||||
let { url } = this.selectedItem.attachment;
|
let { url } = this.selectedItem.attachment;
|
||||||
let params = NetworkHelper.nsIURL(url).query.split("&");
|
let params = getUrlQuery(url).split("&");
|
||||||
let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
|
let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
|
||||||
clipboardHelper.copyString(string);
|
clipboardHelper.copyString(string);
|
||||||
},
|
},
|
||||||
@ -224,7 +225,7 @@ RequestListContextMenu.prototype = {
|
|||||||
|
|
||||||
let params = [];
|
let params = [];
|
||||||
formDataSections.forEach(section => {
|
formDataSections.forEach(section => {
|
||||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
let paramsArray = parseQueryString(section);
|
||||||
if (paramsArray) {
|
if (paramsArray) {
|
||||||
params = [...params, ...paramsArray];
|
params = [...params, ...paramsArray];
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* eslint-disable mozilla/reject-some-requires */
|
/* eslint-disable mozilla/reject-some-requires */
|
||||||
const { Ci } = require("chrome");
|
const { Ci } = require("chrome");
|
||||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||||
const { Task } = require("devtools/shared/task");
|
const { Task } = require("devtools/shared/task");
|
||||||
const NetworkHelper = require("devtools/shared/webconsole/network-helper");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to get a wrapped function which can be bound to as
|
* Helper method to get a wrapped function which can be bound to as
|
||||||
* an event listener directly and is executed only when data-key is
|
* an event listener directly and is executed only when data-key is
|
||||||
* present in event.target.
|
* present in event.target.
|
||||||
*
|
*
|
||||||
* @param function callback
|
* @param {function} callback - function to execute execute when data-key
|
||||||
* Function to execute execute when data-key
|
* is present in event.target.
|
||||||
* is present in event.target.
|
* @param {bool} onlySpaceOrReturn - flag to indicate if callback should only
|
||||||
* @param bool onlySpaceOrReturn
|
* be called when the space or return button
|
||||||
* Flag to indicate if callback should only be called
|
* is pressed
|
||||||
when the space or return button is pressed
|
* @return {function} wrapped function with the target data-key as the first argument
|
||||||
* @return function
|
* and the event as the second argument.
|
||||||
* Wrapped function with the target data-key as the first argument
|
|
||||||
* and the event as the second argument.
|
|
||||||
*/
|
*/
|
||||||
exports.getKeyWithEvent = function (callback, onlySpaceOrReturn) {
|
function getKeyWithEvent(callback, onlySpaceOrReturn) {
|
||||||
return function (event) {
|
return function (event) {
|
||||||
let key = event.target.getAttribute("data-key");
|
let key = event.target.getAttribute("data-key");
|
||||||
let filterKeyboardEvent = !onlySpaceOrReturn ||
|
let filterKeyboardEvent = !onlySpaceOrReturn ||
|
||||||
@ -31,24 +29,19 @@ exports.getKeyWithEvent = function (callback, onlySpaceOrReturn) {
|
|||||||
callback.call(null, key);
|
callback.call(null, key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||||
* POST request.
|
* POST request.
|
||||||
*
|
*
|
||||||
* @param object headers
|
* @param {object} headers - the "requestHeaders".
|
||||||
* The "requestHeaders".
|
* @param {object} uploadHeaders - the "requestHeadersFromUploadStream".
|
||||||
* @param object uploadHeaders
|
* @param {object} postData - the "requestPostData".
|
||||||
* The "requestHeadersFromUploadStream".
|
* @param {function} getString - callback to retrieve a string from a LongStringGrip.
|
||||||
* @param object postData
|
* @return {array} a promise list that is resolved with the extracted form data.
|
||||||
* The "requestPostData".
|
|
||||||
* @param object getString
|
|
||||||
Callback to retrieve a string from a LongStringGrip.
|
|
||||||
* @return array
|
|
||||||
* A promise that is resolved with the extracted form data.
|
|
||||||
*/
|
*/
|
||||||
exports.getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
|
const getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
|
||||||
getString) {
|
getString) {
|
||||||
let formDataSections = [];
|
let formDataSections = [];
|
||||||
|
|
||||||
@ -83,73 +76,132 @@ exports.getFormDataSections = Task.async(function* (headers, uploadHeaders, post
|
|||||||
/**
|
/**
|
||||||
* Form a data: URI given a mime type, encoding, and some text.
|
* Form a data: URI given a mime type, encoding, and some text.
|
||||||
*
|
*
|
||||||
* @param {String} mimeType the mime type
|
* @param {string} mimeType - mime type
|
||||||
* @param {String} encoding the encoding to use; if not set, the
|
* @param {string} encoding - encoding to use; if not set, the
|
||||||
* text will be base64-encoded.
|
* text will be base64-encoded.
|
||||||
* @param {String} text the text of the URI.
|
* @param {string} text - text of the URI.
|
||||||
* @return {String} a data: URI
|
* @return {string} a data URI
|
||||||
*/
|
*/
|
||||||
exports.formDataURI = function (mimeType, encoding, text) {
|
function formDataURI(mimeType, encoding, text) {
|
||||||
if (!encoding) {
|
if (!encoding) {
|
||||||
encoding = "base64";
|
encoding = "base64";
|
||||||
text = btoa(text);
|
text = btoa(text);
|
||||||
}
|
}
|
||||||
return "data:" + mimeType + ";" + encoding + "," + text;
|
return "data:" + mimeType + ";" + encoding + "," + text;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write out a list of headers into a chunk of text
|
* Write out a list of headers into a chunk of text
|
||||||
*
|
*
|
||||||
* @param array headers
|
* @param {array} headers - array of headers info { name, value }
|
||||||
* Array of headers info {name, value}
|
* @return {string} list of headers in text format
|
||||||
* @return string text
|
|
||||||
* List of headers in text format
|
|
||||||
*/
|
*/
|
||||||
exports.writeHeaderText = function (headers) {
|
function writeHeaderText(headers) {
|
||||||
return headers.map(({name, value}) => name + ": " + value).join("\n");
|
return headers.map(({name, value}) => name + ": " + value).join("\n");
|
||||||
};
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string into unicode if string is valid.
|
||||||
|
* If there is a malformed URI sequence, it returns input string.
|
||||||
|
*
|
||||||
|
* @param {string} url - a string
|
||||||
|
* @return {string} unicode string
|
||||||
|
*/
|
||||||
|
function decodeUnicodeUrl(string) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(string);
|
||||||
|
} catch (err) {
|
||||||
|
// Ignore error and return input string directly.
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for getting an abbreviated string for a mime type.
|
* Helper for getting an abbreviated string for a mime type.
|
||||||
*
|
*
|
||||||
* @param string mimeType
|
* @param {string} mimeType - mime type
|
||||||
* @return string
|
* @return {string} abbreviated mime type
|
||||||
*/
|
*/
|
||||||
exports.getAbbreviatedMimeType = function (mimeType) {
|
function getAbbreviatedMimeType(mimeType) {
|
||||||
if (!mimeType) {
|
if (!mimeType) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return (mimeType.split(";")[0].split("/")[1] || "").split("+")[0];
|
return (mimeType.split(";")[0].split("/")[1] || "").split("+")[0];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers for getting details about an nsIURL.
|
* Helpers for getting the last portion of a url.
|
||||||
|
* For example helper returns "basename" from http://domain.com/path/basename
|
||||||
|
* If basename portion is empty, it returns the url pathname.
|
||||||
*
|
*
|
||||||
* @param nsIURL | string url
|
* @param {string} url - url string
|
||||||
* @return string
|
* @return {string} unicode basename of a url
|
||||||
*/
|
*/
|
||||||
exports.getUriNameWithQuery = function (url) {
|
function getUrlBaseName(url) {
|
||||||
if (!(url instanceof Ci.nsIURL)) {
|
const pathname = (new URL(url)).pathname;
|
||||||
url = NetworkHelper.nsIURL(url);
|
return decodeUnicodeUrl(
|
||||||
|
pathname.replace(/\S*\//, "") || pathname || "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for getting the query portion of a url.
|
||||||
|
*
|
||||||
|
* @param {string} url - url string
|
||||||
|
* @return {string} unicode query of a url
|
||||||
|
*/
|
||||||
|
function getUrlQuery(url) {
|
||||||
|
return decodeUnicodeUrl((new URL(url)).search.replace(/^\?/, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for getting unicode name and query portions of a url.
|
||||||
|
*
|
||||||
|
* @param {string} url - url string
|
||||||
|
* @return {string} unicode basename and query portions of a url
|
||||||
|
*/
|
||||||
|
function getUrlBaseNameWithQuery(url) {
|
||||||
|
return getUrlBaseName(url) + decodeUnicodeUrl((new URL(url)).search);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for getting unicode hostname portion of an URL.
|
||||||
|
*
|
||||||
|
* @param {string} url - url string
|
||||||
|
* @return {string} unicode hostname of a url
|
||||||
|
*/
|
||||||
|
function getUrlHostName(url) {
|
||||||
|
return decodeUnicodeUrl((new URL(url)).hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for getting unicode host portion of an URL.
|
||||||
|
*
|
||||||
|
* @param {string} url - url string
|
||||||
|
* @return {string} unicode host of a url
|
||||||
|
*/
|
||||||
|
function getUrlHost(url) {
|
||||||
|
return decodeUnicodeUrl((new URL(url)).host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a url's query string into its components
|
||||||
|
*
|
||||||
|
* @param {string} query - query string of a url portion
|
||||||
|
* @return {array} array of query params { name, value }
|
||||||
|
*/
|
||||||
|
function parseQueryString(query) {
|
||||||
|
if (!query) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = NetworkHelper.convertToUnicode(
|
return query.replace(/^[?&]/, "").split("&").map(e => {
|
||||||
unescape(url.fileName || url.filePath || "/"));
|
let param = e.split("=");
|
||||||
let query = NetworkHelper.convertToUnicode(unescape(url.query));
|
return {
|
||||||
|
name: param[0] ? decodeUnicodeUrl(param[0]) : "",
|
||||||
return name + (query ? "?" + query : "");
|
value: param[1] ? decodeUnicodeUrl(param[1]) : "",
|
||||||
};
|
};
|
||||||
|
});
|
||||||
exports.getUriHostPort = function (url) {
|
}
|
||||||
if (!(url instanceof Ci.nsIURL)) {
|
|
||||||
url = NetworkHelper.nsIURL(url);
|
|
||||||
}
|
|
||||||
return NetworkHelper.convertToUnicode(unescape(url.hostPort));
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.getUriHost = function (url) {
|
|
||||||
return exports.getUriHostPort(url).replace(/:\d+$/, "");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a nsIContentPolicy constant to a display string
|
* Convert a nsIContentPolicy constant to a display string
|
||||||
@ -180,6 +232,22 @@ const LOAD_CAUSE_STRINGS = {
|
|||||||
[Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest"
|
[Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest"
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.loadCauseString = function (causeType) {
|
function loadCauseString(causeType) {
|
||||||
return LOAD_CAUSE_STRINGS[causeType] || "unknown";
|
return LOAD_CAUSE_STRINGS[causeType] || "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getKeyWithEvent,
|
||||||
|
getFormDataSections,
|
||||||
|
formDataURI,
|
||||||
|
writeHeaderText,
|
||||||
|
decodeUnicodeUrl,
|
||||||
|
getAbbreviatedMimeType,
|
||||||
|
getUrlBaseName,
|
||||||
|
getUrlQuery,
|
||||||
|
getUrlBaseNameWithQuery,
|
||||||
|
getUrlHostName,
|
||||||
|
getUrlHost,
|
||||||
|
parseQueryString,
|
||||||
|
loadCauseString,
|
||||||
};
|
};
|
||||||
|
@ -24,18 +24,16 @@ const {Sorters} = require("./sort-predicates");
|
|||||||
const {L10N, WEBCONSOLE_L10N} = require("./l10n");
|
const {L10N, WEBCONSOLE_L10N} = require("./l10n");
|
||||||
const {formDataURI,
|
const {formDataURI,
|
||||||
writeHeaderText,
|
writeHeaderText,
|
||||||
|
decodeUnicodeUrl,
|
||||||
getKeyWithEvent,
|
getKeyWithEvent,
|
||||||
getAbbreviatedMimeType,
|
getAbbreviatedMimeType,
|
||||||
getUriNameWithQuery,
|
getUrlBaseNameWithQuery,
|
||||||
getUriHostPort,
|
getUrlHost,
|
||||||
getUriHost,
|
getUrlHostName,
|
||||||
loadCauseString} = require("./request-utils");
|
loadCauseString} = require("./request-utils");
|
||||||
const Actions = require("./actions/index");
|
const Actions = require("./actions/index");
|
||||||
const RequestListContextMenu = require("./request-list-context-menu");
|
const RequestListContextMenu = require("./request-list-context-menu");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "NetworkHelper",
|
|
||||||
"devtools/shared/webconsole/network-helper");
|
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
const EPSILON = 0.001;
|
const EPSILON = 0.001;
|
||||||
// ms
|
// ms
|
||||||
@ -925,17 +923,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "url": {
|
case "url": {
|
||||||
let uri;
|
let nameWithQuery = getUrlBaseNameWithQuery(value);
|
||||||
try {
|
let hostPort = getUrlHost(value);
|
||||||
uri = NetworkHelper.nsIURL(value);
|
let host = getUrlHostName(value);
|
||||||
} catch (e) {
|
let unicodeUrl = decodeUnicodeUrl(value);
|
||||||
// User input may not make a well-formed url yet.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let nameWithQuery = getUriNameWithQuery(uri);
|
|
||||||
let hostPort = getUriHostPort(uri);
|
|
||||||
let host = getUriHost(uri);
|
|
||||||
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(uri.spec));
|
|
||||||
|
|
||||||
let file = $(".requests-menu-file", target);
|
let file = $(".requests-menu-file", target);
|
||||||
file.setAttribute("value", nameWithQuery);
|
file.setAttribute("value", nameWithQuery);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { getAbbreviatedMimeType,
|
const { getAbbreviatedMimeType,
|
||||||
getUriNameWithQuery,
|
getUrlBaseNameWithQuery,
|
||||||
getUriHostPort,
|
getUrlHost,
|
||||||
loadCauseString } = require("./request-utils");
|
loadCauseString } = require("./request-utils");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,8 +36,8 @@ function method(first, second) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function file(first, second) {
|
function file(first, second) {
|
||||||
let firstUrl = getUriNameWithQuery(first.url).toLowerCase();
|
let firstUrl = getUrlBaseNameWithQuery(first.url).toLowerCase();
|
||||||
let secondUrl = getUriNameWithQuery(second.url).toLowerCase();
|
let secondUrl = getUrlBaseNameWithQuery(second.url).toLowerCase();
|
||||||
if (firstUrl == secondUrl) {
|
if (firstUrl == secondUrl) {
|
||||||
return first.startedMillis - second.startedMillis;
|
return first.startedMillis - second.startedMillis;
|
||||||
}
|
}
|
||||||
@ -45,8 +45,8 @@ function file(first, second) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function domain(first, second) {
|
function domain(first, second) {
|
||||||
let firstDomain = getUriHostPort(first.url).toLowerCase();
|
let firstDomain = getUrlHost(first.url).toLowerCase();
|
||||||
let secondDomain = getUriHostPort(second.url).toLowerCase();
|
let secondDomain = getUrlHost(second.url).toLowerCase();
|
||||||
if (firstDomain == secondDomain) {
|
if (firstDomain == secondDomain) {
|
||||||
return first.startedMillis - second.startedMillis;
|
return first.startedMillis - second.startedMillis;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,13 @@ Services.scriptloader.loadSubScript(
|
|||||||
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
||||||
this);
|
this);
|
||||||
|
|
||||||
var NetworkHelper = require("devtools/shared/webconsole/network-helper");
|
|
||||||
var { Toolbox } = require("devtools/client/framework/toolbox");
|
var { Toolbox } = require("devtools/client/framework/toolbox");
|
||||||
|
const {
|
||||||
|
decodeUnicodeUrl,
|
||||||
|
getUrlBaseName,
|
||||||
|
getUrlQuery,
|
||||||
|
getUrlHost,
|
||||||
|
} = require("devtools/client/netmonitor/request-utils");
|
||||||
|
|
||||||
const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
|
const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
|
||||||
const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
|
const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
|
||||||
@ -260,11 +265,10 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
|
|||||||
transferred, size, time, displayedStatus } = aData;
|
transferred, size, time, displayedStatus } = aData;
|
||||||
let { attachment, target } = aRequestItem;
|
let { attachment, target } = aRequestItem;
|
||||||
|
|
||||||
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
let unicodeUrl = decodeUnicodeUrl(aUrl);
|
||||||
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(aUrl));
|
let name = getUrlBaseName(aUrl);
|
||||||
let name = NetworkHelper.convertToUnicode(unescape(uri.fileName || uri.filePath || "/"));
|
let query = getUrlQuery(aUrl);
|
||||||
let query = NetworkHelper.convertToUnicode(unescape(uri.query));
|
let hostPort = getUrlHost(aUrl);
|
||||||
let hostPort = uri.hostPort;
|
|
||||||
let remoteAddress = attachment.remoteAddress;
|
let remoteAddress = attachment.remoteAddress;
|
||||||
|
|
||||||
if (fuzzyUrl) {
|
if (fuzzyUrl) {
|
||||||
|
@ -1740,6 +1740,7 @@ WebConsoleActor.prototype =
|
|||||||
delete result.ID;
|
delete result.ID;
|
||||||
delete result.innerID;
|
delete result.innerID;
|
||||||
delete result.consoleID;
|
delete result.consoleID;
|
||||||
|
delete result.originAttributes;
|
||||||
|
|
||||||
result.arguments = Array.map(aMessage.arguments || [], (aObj) => {
|
result.arguments = Array.map(aMessage.arguments || [], (aObj) => {
|
||||||
let dbgObj = this.makeDebuggeeValue(aObj, aUseObjectGlobal);
|
let dbgObj = this.makeDebuggeeValue(aObj, aUseObjectGlobal);
|
||||||
|
@ -127,6 +127,12 @@ ConsoleAPIStorageService.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let storage = _consoleStorage.get(aId);
|
let storage = _consoleStorage.get(aId);
|
||||||
|
|
||||||
|
// Clone originAttributes to prevent "TypeError: can't access dead object"
|
||||||
|
// exceptions when cached console messages are retrieved/filtered
|
||||||
|
// by the devtools webconsole actor.
|
||||||
|
aEvent.originAttributes = Cu.cloneInto(aEvent.originAttributes, {});
|
||||||
|
|
||||||
storage.push(aEvent);
|
storage.push(aEvent);
|
||||||
|
|
||||||
// truncate
|
// truncate
|
||||||
|
@ -407,7 +407,8 @@ EventTargetChainItem::HandleEventTargetChain(
|
|||||||
}
|
}
|
||||||
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
||||||
|
|
||||||
if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
|
if (!aVisitor.mEvent->mFlags.mInSystemGroup &&
|
||||||
|
aVisitor.mEvent->IsAllowedToDispatchInSystemGroup()) {
|
||||||
// Dispatch to the system event group. Make sure to clear the
|
// Dispatch to the system event group. Make sure to clear the
|
||||||
// STOP_DISPATCH flag since this resets for each event group.
|
// STOP_DISPATCH flag since this resets for each event group.
|
||||||
aVisitor.mEvent->mFlags.mPropagationStopped = false;
|
aVisitor.mEvent->mFlags.mPropagationStopped = false;
|
||||||
|
@ -118,10 +118,8 @@ support-files =
|
|||||||
support-files = pointerevent_setpointercapture_to_same_element_twice-manual.html
|
support-files = pointerevent_setpointercapture_to_same_element_twice-manual.html
|
||||||
[test_pointerevent_suppress_compat_events_on_click.html]
|
[test_pointerevent_suppress_compat_events_on_click.html]
|
||||||
support-files = pointerevent_suppress_compat_events_on_click.html
|
support-files = pointerevent_suppress_compat_events_on_click.html
|
||||||
disabled = should be investigated
|
|
||||||
[test_pointerevent_suppress_compat_events_on_drag_mouse.html]
|
[test_pointerevent_suppress_compat_events_on_drag_mouse.html]
|
||||||
support-files = pointerevent_suppress_compat_events_on_drag_mouse.html
|
support-files = pointerevent_suppress_compat_events_on_drag_mouse.html
|
||||||
disabled = should be investigated
|
|
||||||
[test_touch_action.html]
|
[test_touch_action.html]
|
||||||
support-files =
|
support-files =
|
||||||
../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js
|
../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js
|
||||||
@ -148,5 +146,7 @@ support-files =
|
|||||||
support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
|
support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
|
||||||
[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
|
[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
|
||||||
support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
|
support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
|
||||||
|
[test_bug1303704.html]
|
||||||
[test_empty_file.html]
|
[test_empty_file.html]
|
||||||
disabled = disabled # Bug 1150091 - Issue with support-files
|
disabled = disabled # Bug 1150091 - Issue with support-files
|
||||||
|
[test_bug1315862.html]
|
||||||
|
54
dom/events/test/pointerevents/test_bug1303704.html
Normal file
54
dom/events/test/pointerevents/test_bug1303704.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1303704
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1303704</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303704">Mozilla Bug 1303704</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<a id="link1" href="http://www.google.com">Link 1</a>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 1303704 **/
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
let link1 = window.document.getElementById("link1");
|
||||||
|
let mouseEvents = ["mousedown", "mouseup", "mousemove"];
|
||||||
|
|
||||||
|
link1.addEventListener("pointerdown", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
is(e.defaultPrevented, true, "defaultPrevented should be true");
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
mouseEvents.forEach((elm, index, arr) => {
|
||||||
|
link1.addEventListener(elm, () => {
|
||||||
|
ok(false, "Should not receive " + elm + " after preventDefault on pointerdown");
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
link1.addEventListener("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
SimpleTest.finish();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
synthesizeMouseAtCenter(link1, { type: "mousedown",
|
||||||
|
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE });
|
||||||
|
synthesizeMouseAtCenter(link1, { type: "mousemove",
|
||||||
|
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE });
|
||||||
|
synthesizeMouseAtCenter(link1, { type: "mouseup",
|
||||||
|
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE });
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
66
dom/events/test/pointerevents/test_bug1315862.html
Normal file
66
dom/events/test/pointerevents/test_bug1315862.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1315862
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1315862</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p id="content">
|
||||||
|
This is a test to check if pointer events are dispatched in the system group
|
||||||
|
</p>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 1315862 **/
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
let allPointerEvents = ["pointerdown", "pointerup", "pointercancel",
|
||||||
|
"pointermove", "pointerover", "pointerout",
|
||||||
|
"pointerenter", "pointerleave", "gotpointercapture",
|
||||||
|
"lostpointercapture"
|
||||||
|
];
|
||||||
|
let content = document.getElementById('content');
|
||||||
|
let iframe = document.createElement('iframe');
|
||||||
|
let receivePointerEvents = false;
|
||||||
|
iframe.width = 50;
|
||||||
|
iframe.height = 50;
|
||||||
|
content.appendChild(iframe);
|
||||||
|
iframe.contentDocument.body.innerHTML =
|
||||||
|
"<div style='width: 100%; height: 100%; border: 1px solid black;'></div>";
|
||||||
|
|
||||||
|
let target = iframe.contentDocument.body.firstChild;
|
||||||
|
allPointerEvents.forEach((event, idx, arr) => {
|
||||||
|
SpecialPowers.addSystemEventListener(target, event, () => {
|
||||||
|
ok(false, "Shouldn't dispatch " + event + " in the system group");
|
||||||
|
receivePointerEvents = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
target.addEventListener("pointerdown", (e) => {
|
||||||
|
target.setPointerCapture(e.pointerId);
|
||||||
|
}, false);
|
||||||
|
target.addEventListener("pointerup", () => {
|
||||||
|
is(receivePointerEvents, false, "Shouldn't dispatch pointer events in the system group");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}, false);
|
||||||
|
let source = SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE;
|
||||||
|
synthesizeMouse(target, 5, 5, { type: "mousemove", inputSource: source },
|
||||||
|
iframe.contentWindow);
|
||||||
|
synthesizeMouse(target, 5, 5, { type: "mousedown", inputSource: source },
|
||||||
|
iframe.contentWindow);
|
||||||
|
synthesizeMouse(target, 5, 5, { type: "mousemove", inputSource: source },
|
||||||
|
iframe.contentWindow);
|
||||||
|
synthesizeMouse(target, 5, 5, { type: "mouseup", inputSource: source },
|
||||||
|
iframe.contentWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1042,11 +1042,6 @@ RTCPeerConnection.prototype = {
|
|||||||
stream.getTracks().forEach(track => this.addTrack(track, stream));
|
stream.getTracks().forEach(track => this.addTrack(track, stream));
|
||||||
},
|
},
|
||||||
|
|
||||||
getStreamById: function(id) {
|
|
||||||
throw new this._win.DOMException("getStreamById not yet implemented",
|
|
||||||
"NotSupportedError");
|
|
||||||
},
|
|
||||||
|
|
||||||
addTrack: function(track, stream) {
|
addTrack: function(track, stream) {
|
||||||
if (stream.currentTime === undefined) {
|
if (stream.currentTime === undefined) {
|
||||||
throw new this._win.DOMException("invalid stream.", "InvalidParameterError");
|
throw new this._win.DOMException("invalid stream.", "InvalidParameterError");
|
||||||
|
@ -372,6 +372,13 @@ MediaDrmCDMProxy::IsOnOwnerThread()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const nsString&
|
||||||
|
MediaDrmCDMProxy::GetMediaDrmStubId() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mCDM);
|
||||||
|
return mCDM->GetMediaDrmStubId();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MediaDrmCDMProxy::OnCDMCreated(uint32_t aPromiseId)
|
MediaDrmCDMProxy::OnCDMCreated(uint32_t aPromiseId)
|
||||||
{
|
{
|
||||||
@ -464,4 +471,4 @@ MediaDrmCDMProxy::md_Shutdown()
|
|||||||
mCDM = nullptr;
|
mCDM = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include "mozilla/jni/Types.h"
|
#include "mozilla/jni/Types.h"
|
||||||
#include "GeneratedJNINatives.h"
|
#include "GeneratedJNINatives.h"
|
||||||
|
|
||||||
#include "mozilla/CDMProxy.h"
|
#include "mozilla/CDMProxy.h"
|
||||||
#include "mozilla/CDMCaps.h"
|
#include "mozilla/CDMCaps.h"
|
||||||
#include "mozilla/dom/MediaKeys.h"
|
#include "mozilla/dom/MediaKeys.h"
|
||||||
@ -118,6 +117,8 @@ public:
|
|||||||
bool IsOnOwnerThread() override;
|
bool IsOnOwnerThread() override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const nsString& GetMediaDrmStubId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~MediaDrmCDMProxy();
|
virtual ~MediaDrmCDMProxy();
|
||||||
|
|
||||||
@ -181,4 +182,4 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
#endif // MediaDrmCDMProxy_h_
|
#endif // MediaDrmCDMProxy_h_
|
||||||
|
@ -204,6 +204,9 @@ MediaDrmProxySupport::MediaDrmProxySupport(const nsAString& aKeySystem)
|
|||||||
MediaDrmProxy::Create(mKeySystem,
|
MediaDrmProxy::Create(mKeySystem,
|
||||||
mJavaCallbacks,
|
mJavaCallbacks,
|
||||||
MediaPrefs::PDMAndroidRemoteCodecEnabled());
|
MediaPrefs::PDMAndroidRemoteCodecEnabled());
|
||||||
|
|
||||||
|
MOZ_ASSERT(mBridgeProxy, "mBridgeProxy should not be null");
|
||||||
|
mMediaDrmStubId = mBridgeProxy->GetStubId()->ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDrmProxySupport::~MediaDrmProxySupport()
|
MediaDrmProxySupport::~MediaDrmProxySupport()
|
||||||
@ -281,4 +284,4 @@ MediaDrmProxySupport::Shutdown()
|
|||||||
mDestroyed = true;
|
mDestroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -54,14 +54,16 @@ public:
|
|||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
const nsString& GetMediaDrmStubId() const { return mMediaDrmStubId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const nsString mKeySystem;
|
const nsString mKeySystem;
|
||||||
java::MediaDrmProxy::GlobalRef mBridgeProxy;
|
java::MediaDrmProxy::GlobalRef mBridgeProxy;
|
||||||
java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::GlobalRef mJavaCallbacks;
|
java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::GlobalRef mJavaCallbacks;
|
||||||
DecryptorProxyCallback* mCallback;
|
DecryptorProxyCallback* mCallback;
|
||||||
bool mDestroyed;
|
bool mDestroyed;
|
||||||
|
nsString mMediaDrmStubId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
#endif // MediaDrmProxySupport_H
|
#endif // MediaDrmProxySupport_H
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <memory>
|
||||||
#include "../AudioPacketizer.h"
|
#include "../AudioPacketizer.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ int16_t Sequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
|
|||||||
return aStart + i;
|
return aStart + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsSequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
|
void IsSequence(std::unique_ptr<int16_t[]> aBuffer, uint32_t aSize, uint32_t aStart = 0)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < aSize; i++) {
|
for (uint32_t i = 0; i < aSize; i++) {
|
||||||
ASSERT_TRUE(aBuffer[i] == static_cast<int64_t>(aStart + i)) <<
|
ASSERT_TRUE(aBuffer[i] == static_cast<int64_t>(aStart + i)) <<
|
||||||
@ -46,7 +47,7 @@ void IsSequence(int16_t* aBuffer, uint32_t aSize, uint32_t aStart = 0)
|
|||||||
// Buffer is a sequence.
|
// Buffer is a sequence.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zero(int16_t* aBuffer, uint32_t aSize)
|
void Zero(std::unique_ptr<int16_t[]> aBuffer, uint32_t aSize)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < aSize; i++) {
|
for (uint32_t i = 0; i < aSize; i++) {
|
||||||
ASSERT_TRUE(aBuffer[i] == 0) <<
|
ASSERT_TRUE(aBuffer[i] == 0) <<
|
||||||
@ -65,9 +66,8 @@ TEST(AudioPacketizer, Test)
|
|||||||
{
|
{
|
||||||
AudioPacketizer<int16_t, int16_t> ap(441, channels);
|
AudioPacketizer<int16_t, int16_t> ap(441, channels);
|
||||||
for (int16_t i = 0; i < 10; i++) {
|
for (int16_t i = 0; i < 10; i++) {
|
||||||
int16_t* out = ap.Output();
|
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||||
Zero(out, 441);
|
Zero(std::move(out), 441);
|
||||||
delete[] out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Simple test, with input/output buffer size aligned on the packet size,
|
// Simple test, with input/output buffer size aligned on the packet size,
|
||||||
@ -80,9 +80,8 @@ TEST(AudioPacketizer, Test)
|
|||||||
int16_t prevEnd = seqEnd;
|
int16_t prevEnd = seqEnd;
|
||||||
seqEnd = Sequence(b.Get(), channels * 441, prevEnd);
|
seqEnd = Sequence(b.Get(), channels * 441, prevEnd);
|
||||||
ap.Input(b.Get(), 441);
|
ap.Input(b.Get(), 441);
|
||||||
int16_t* out = ap.Output();
|
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||||
IsSequence(out, 441 * channels, prevEnd);
|
IsSequence(std::move(out), 441 * channels, prevEnd);
|
||||||
delete[] out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Simple test, with input/output buffer size aligned on the packet size,
|
// Simple test, with input/output buffer size aligned on the packet size,
|
||||||
@ -99,12 +98,10 @@ TEST(AudioPacketizer, Test)
|
|||||||
seqEnd = Sequence(b1.Get(), 441 * channels, seqEnd);
|
seqEnd = Sequence(b1.Get(), 441 * channels, seqEnd);
|
||||||
ap.Input(b.Get(), 441);
|
ap.Input(b.Get(), 441);
|
||||||
ap.Input(b1.Get(), 441);
|
ap.Input(b1.Get(), 441);
|
||||||
int16_t* out = ap.Output();
|
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||||
int16_t* out2 = ap.Output();
|
std::unique_ptr<int16_t[]> out2(ap.Output());
|
||||||
IsSequence(out, 441 * channels, prevEnd0);
|
IsSequence(std::move(out), 441 * channels, prevEnd0);
|
||||||
IsSequence(out2, 441 * channels, prevEnd1);
|
IsSequence(std::move(out2), 441 * channels, prevEnd1);
|
||||||
delete[] out;
|
|
||||||
delete[] out2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Input/output buffer size not aligned on the packet size,
|
// Input/output buffer size not aligned on the packet size,
|
||||||
@ -120,14 +117,12 @@ TEST(AudioPacketizer, Test)
|
|||||||
prevSeq = Sequence(b1.Get(), 480 * channels, prevSeq);
|
prevSeq = Sequence(b1.Get(), 480 * channels, prevSeq);
|
||||||
ap.Input(b.Get(), 480);
|
ap.Input(b.Get(), 480);
|
||||||
ap.Input(b1.Get(), 480);
|
ap.Input(b1.Get(), 480);
|
||||||
int16_t* out = ap.Output();
|
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||||
int16_t* out2 = ap.Output();
|
std::unique_ptr<int16_t[]> out2(ap.Output());
|
||||||
IsSequence(out, 441 * channels, prevEnd);
|
IsSequence(std::move(out), 441 * channels, prevEnd);
|
||||||
prevEnd += 441 * channels;
|
prevEnd += 441 * channels;
|
||||||
IsSequence(out2, 441 * channels, prevEnd);
|
IsSequence(std::move(out2), 441 * channels, prevEnd);
|
||||||
prevEnd += 441 * channels;
|
prevEnd += 441 * channels;
|
||||||
delete[] out;
|
|
||||||
delete[] out2;
|
|
||||||
}
|
}
|
||||||
printf("Available: %d\n", ap.PacketsAvailable());
|
printf("Available: %d\n", ap.PacketsAvailable());
|
||||||
}
|
}
|
||||||
@ -151,7 +146,7 @@ TEST(AudioPacketizer, Test)
|
|||||||
}
|
}
|
||||||
ap.Input(b.Get(), 128);
|
ap.Input(b.Get(), 128);
|
||||||
while (ap.PacketsAvailable()) {
|
while (ap.PacketsAvailable()) {
|
||||||
int16_t* packet = ap.Output();
|
std::unique_ptr<int16_t[]> packet(ap.Output());
|
||||||
for (uint32_t k = 0; k < ap.PacketSize(); k++) {
|
for (uint32_t k = 0; k < ap.PacketSize(); k++) {
|
||||||
for (int32_t c = 0; c < channels; c++) {
|
for (int32_t c = 0; c < channels; c++) {
|
||||||
ASSERT_TRUE(packet[k * channels + c] ==
|
ASSERT_TRUE(packet[k * channels + c] ==
|
||||||
@ -159,7 +154,6 @@ TEST(AudioPacketizer, Test)
|
|||||||
}
|
}
|
||||||
outPhase++;
|
outPhase++;
|
||||||
}
|
}
|
||||||
delete [] packet;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,6 +469,14 @@ PDMFactory::GetDecoder(const TrackInfo& aTrackInfo,
|
|||||||
void
|
void
|
||||||
PDMFactory::SetCDMProxy(CDMProxy* aProxy)
|
PDMFactory::SetCDMProxy(CDMProxy* aProxy)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(aProxy);
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
if (IsWidevineKeySystem(aProxy->KeySystem())) {
|
||||||
|
mEMEPDM = new AndroidDecoderModule(aProxy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
RefPtr<PDMFactory> m = new PDMFactory();
|
RefPtr<PDMFactory> m = new PDMFactory();
|
||||||
mEMEPDM = new EMEDecoderModule(aProxy, m);
|
mEMEPDM = new EMEDecoderModule(aProxy, m);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,11 @@ GetCryptoInfoFromSample(const MediaRawData* aSample)
|
|||||||
return cryptoInfo;
|
return cryptoInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AndroidDecoderModule::AndroidDecoderModule(CDMProxy* aProxy)
|
||||||
|
{
|
||||||
|
mProxy = static_cast<MediaDrmCDMProxy*>(aProxy);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||||
DecoderDoctorDiagnostics* aDiagnostics) const
|
DecoderDoctorDiagnostics* aDiagnostics) const
|
||||||
@ -174,16 +179,24 @@ AndroidDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
|||||||
config.mDisplay.height,
|
config.mDisplay.height,
|
||||||
&format), nullptr);
|
&format), nullptr);
|
||||||
|
|
||||||
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
nsString drmStubId;
|
||||||
RemoteDataDecoder::CreateVideoDecoder(config,
|
if (mProxy) {
|
||||||
format,
|
drmStubId = mProxy->GetMediaDrmStubId();
|
||||||
aParams.mCallback,
|
}
|
||||||
aParams.mImageContainer) :
|
|
||||||
MediaCodecDataDecoder::CreateVideoDecoder(config,
|
|
||||||
format,
|
|
||||||
aParams.mCallback,
|
|
||||||
aParams.mImageContainer);
|
|
||||||
|
|
||||||
|
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
||||||
|
RemoteDataDecoder::CreateVideoDecoder(config,
|
||||||
|
format,
|
||||||
|
aParams.mCallback,
|
||||||
|
aParams.mImageContainer,
|
||||||
|
drmStubId) :
|
||||||
|
MediaCodecDataDecoder::CreateVideoDecoder(config,
|
||||||
|
format,
|
||||||
|
aParams.mCallback,
|
||||||
|
aParams.mImageContainer,
|
||||||
|
drmStubId,
|
||||||
|
mProxy,
|
||||||
|
aParams.mTaskQueue);
|
||||||
return decoder.forget();
|
return decoder.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,10 +217,18 @@ AndroidDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
|
|||||||
config.mChannels,
|
config.mChannels,
|
||||||
&format), nullptr);
|
&format), nullptr);
|
||||||
|
|
||||||
|
nsString drmStubId;
|
||||||
|
if (mProxy) {
|
||||||
|
drmStubId = mProxy->GetMediaDrmStubId();
|
||||||
|
}
|
||||||
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
||||||
RemoteDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback) :
|
RemoteDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback, drmStubId) :
|
||||||
MediaCodecDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback);
|
MediaCodecDataDecoder::CreateAudioDecoder(config,
|
||||||
|
format,
|
||||||
|
aParams.mCallback,
|
||||||
|
drmStubId,
|
||||||
|
mProxy,
|
||||||
|
aParams.mTaskQueue);
|
||||||
return decoder.forget();
|
return decoder.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#define AndroidDecoderModule_h_
|
#define AndroidDecoderModule_h_
|
||||||
|
|
||||||
#include "PlatformDecoderModule.h"
|
#include "PlatformDecoderModule.h"
|
||||||
|
#include "mozilla/MediaDrmCDMProxy.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ public:
|
|||||||
already_AddRefed<MediaDataDecoder>
|
already_AddRefed<MediaDataDecoder>
|
||||||
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
||||||
|
|
||||||
AndroidDecoderModule() {}
|
AndroidDecoderModule(CDMProxy* aProxy = nullptr);
|
||||||
virtual ~AndroidDecoderModule() {}
|
virtual ~AndroidDecoderModule() {}
|
||||||
|
|
||||||
bool SupportsMimeType(const nsACString& aMimeType,
|
bool SupportsMimeType(const nsACString& aMimeType,
|
||||||
@ -25,6 +26,9 @@ public:
|
|||||||
|
|
||||||
ConversionRequired
|
ConversionRequired
|
||||||
DecoderNeedsConversion(const TrackInfo& aConfig) const override;
|
DecoderNeedsConversion(const TrackInfo& aConfig) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<MediaDrmCDMProxy> mProxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern LazyLogModule sAndroidDecoderModuleLog;
|
extern LazyLogModule sAndroidDecoderModuleLog;
|
||||||
|
@ -56,9 +56,10 @@ public:
|
|||||||
VideoDataDecoder(const VideoInfo& aConfig,
|
VideoDataDecoder(const VideoInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer)
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
: MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
||||||
aFormat, aCallback)
|
aFormat, aCallback, aDrmStubId)
|
||||||
, mImageContainer(aImageContainer)
|
, mImageContainer(aImageContainer)
|
||||||
, mConfig(aConfig)
|
, mConfig(aConfig)
|
||||||
{
|
{
|
||||||
@ -81,7 +82,6 @@ public:
|
|||||||
if (NS_FAILED(InitDecoder(mSurfaceTexture->JavaSurface()))) {
|
if (NS_FAILED(InitDecoder(mSurfaceTexture->JavaSurface()))) {
|
||||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
|
return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,15 +127,59 @@ protected:
|
|||||||
layers::ImageContainer* mImageContainer;
|
layers::ImageContainer* mImageContainer;
|
||||||
const VideoInfo& mConfig;
|
const VideoInfo& mConfig;
|
||||||
RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
|
RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
|
||||||
|
RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EMEVideoDataDecoder : public VideoDataDecoder {
|
||||||
|
public:
|
||||||
|
EMEVideoDataDecoder(const VideoInfo& aConfig,
|
||||||
|
MediaFormat::Param aFormat,
|
||||||
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy,
|
||||||
|
TaskQueue* aTaskQueue)
|
||||||
|
: VideoDataDecoder(aConfig, aFormat, aCallback, aImageContainer, aDrmStubId)
|
||||||
|
, mSamplesWaitingForKey(new SamplesWaitingForKey(this, aCallback,
|
||||||
|
aTaskQueue, aProxy))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input(MediaRawData* aSample) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
EMEVideoDataDecoder::Input(MediaRawData* aSample)
|
||||||
|
{
|
||||||
|
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VideoDataDecoder::Input(aSample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EMEVideoDataDecoder::Shutdown()
|
||||||
|
{
|
||||||
|
VideoDataDecoder::Shutdown();
|
||||||
|
|
||||||
|
mSamplesWaitingForKey->BreakCycles();
|
||||||
|
mSamplesWaitingForKey = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
class AudioDataDecoder : public MediaCodecDataDecoder
|
class AudioDataDecoder : public MediaCodecDataDecoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AudioDataDecoder(const AudioInfo& aConfig, MediaFormat::Param aFormat,
|
AudioDataDecoder(const AudioInfo& aConfig, MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
: MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
||||||
aFormat, aCallback)
|
aFormat, aCallback, aDrmStubId)
|
||||||
{
|
{
|
||||||
JNIEnv* const env = jni::GetEnvForThread();
|
JNIEnv* const env = jni::GetEnvForThread();
|
||||||
|
|
||||||
@ -210,27 +254,89 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EMEAudioDataDecoder : public AudioDataDecoder {
|
||||||
|
public:
|
||||||
|
EMEAudioDataDecoder(const AudioInfo& aConfig, MediaFormat::Param aFormat,
|
||||||
|
MediaDataDecoderCallback* aCallback, const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy, TaskQueue* aTaskQueue)
|
||||||
|
: AudioDataDecoder(aConfig, aFormat, aCallback, aDrmStubId)
|
||||||
|
, mSamplesWaitingForKey(new SamplesWaitingForKey(this, aCallback,
|
||||||
|
aTaskQueue, aProxy))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input(MediaRawData* aSample) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
EMEAudioDataDecoder::Input(MediaRawData* aSample)
|
||||||
|
{
|
||||||
|
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AudioDataDecoder::Input(aSample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EMEAudioDataDecoder::Shutdown()
|
||||||
|
{
|
||||||
|
AudioDataDecoder::Shutdown();
|
||||||
|
|
||||||
|
mSamplesWaitingForKey->BreakCycles();
|
||||||
|
mSamplesWaitingForKey = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
MediaDataDecoder*
|
MediaDataDecoder*
|
||||||
MediaCodecDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
MediaCodecDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy,
|
||||||
|
TaskQueue* aTaskQueue)
|
||||||
{
|
{
|
||||||
return new AudioDataDecoder(aConfig, aFormat, aCallback);
|
if (!aProxy) {
|
||||||
|
return new AudioDataDecoder(aConfig, aFormat, aCallback, aDrmStubId);
|
||||||
|
} else {
|
||||||
|
return new EMEAudioDataDecoder(aConfig,
|
||||||
|
aFormat,
|
||||||
|
aCallback,
|
||||||
|
aDrmStubId,
|
||||||
|
aProxy,
|
||||||
|
aTaskQueue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDataDecoder*
|
MediaDataDecoder*
|
||||||
MediaCodecDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
MediaCodecDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer)
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy,
|
||||||
|
TaskQueue* aTaskQueue)
|
||||||
{
|
{
|
||||||
return new VideoDataDecoder(aConfig, aFormat, aCallback, aImageContainer);
|
if (!aProxy) {
|
||||||
|
return new VideoDataDecoder(aConfig, aFormat, aCallback, aImageContainer, aDrmStubId);
|
||||||
|
} else {
|
||||||
|
return new EMEVideoDataDecoder(aConfig,
|
||||||
|
aFormat,
|
||||||
|
aCallback,
|
||||||
|
aImageContainer,
|
||||||
|
aDrmStubId,
|
||||||
|
aProxy,
|
||||||
|
aTaskQueue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
||||||
const nsACString& aMimeType,
|
const nsACString& aMimeType,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: mType(aType)
|
: mType(aType)
|
||||||
, mMimeType(aMimeType)
|
, mMimeType(aMimeType)
|
||||||
, mFormat(aFormat)
|
, mFormat(aFormat)
|
||||||
@ -239,8 +345,8 @@ MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
|||||||
, mOutputBuffers(nullptr)
|
, mOutputBuffers(nullptr)
|
||||||
, mMonitor("MediaCodecDataDecoder::mMonitor")
|
, mMonitor("MediaCodecDataDecoder::mMonitor")
|
||||||
, mState(ModuleState::kDecoding)
|
, mState(ModuleState::kDecoding)
|
||||||
|
, mDrmStubId(aDrmStubId)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCodecDataDecoder::~MediaCodecDataDecoder()
|
MediaCodecDataDecoder::~MediaCodecDataDecoder()
|
||||||
@ -273,8 +379,11 @@ MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaCrypto::LocalRef crypto = MediaDrmProxy::GetMediaCrypto(mDrmStubId);
|
||||||
|
bool hascrypto = !!crypto;
|
||||||
|
LOG("Has(%d) MediaCrypto (%s)", hascrypto, NS_ConvertUTF16toUTF8(mDrmStubId).get());
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
|
NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, crypto, 0), rv);
|
||||||
NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
|
NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
|
NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
|
||||||
|
@ -23,12 +23,18 @@ class MediaCodecDataDecoder : public MediaDataDecoder {
|
|||||||
public:
|
public:
|
||||||
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback);
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy,
|
||||||
|
TaskQueue* aTaskQueue);
|
||||||
|
|
||||||
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer);
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId,
|
||||||
|
CDMProxy* aProxy,
|
||||||
|
TaskQueue* aTaskQueue);
|
||||||
|
|
||||||
virtual ~MediaCodecDataDecoder();
|
virtual ~MediaCodecDataDecoder();
|
||||||
|
|
||||||
@ -58,7 +64,8 @@ protected:
|
|||||||
MediaCodecDataDecoder(MediaData::Type aType,
|
MediaCodecDataDecoder(MediaData::Type aType,
|
||||||
const nsACString& aMimeType,
|
const nsACString& aMimeType,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback);
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId);
|
||||||
|
|
||||||
static const char* ModuleStateStr(ModuleState aState);
|
static const char* ModuleStateStr(ModuleState aState);
|
||||||
|
|
||||||
@ -119,6 +126,8 @@ protected:
|
|||||||
SampleQueue mQueue;
|
SampleQueue mQueue;
|
||||||
// Durations are stored in microseconds.
|
// Durations are stored in microseconds.
|
||||||
std::deque<media::TimeUnit> mDurations;
|
std::deque<media::TimeUnit> mDurations;
|
||||||
|
|
||||||
|
nsString mDrmStubId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -185,9 +185,10 @@ public:
|
|||||||
RemoteVideoDecoder(const VideoInfo& aConfig,
|
RemoteVideoDecoder(const VideoInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer)
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: RemoteDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
: RemoteDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
||||||
aFormat, aCallback)
|
aFormat, aCallback, aDrmStubId)
|
||||||
, mImageContainer(aImageContainer)
|
, mImageContainer(aImageContainer)
|
||||||
, mConfig(aConfig)
|
, mConfig(aConfig)
|
||||||
{
|
{
|
||||||
@ -213,7 +214,10 @@ public:
|
|||||||
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||||
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
||||||
|
|
||||||
mJavaDecoder = CodecProxy::Create(mFormat, mSurfaceTexture->JavaSurface(), mJavaCallbacks);
|
mJavaDecoder = CodecProxy::Create(mFormat,
|
||||||
|
mSurfaceTexture->JavaSurface(),
|
||||||
|
mJavaCallbacks,
|
||||||
|
mDrmStubId);
|
||||||
if (mJavaDecoder == nullptr) {
|
if (mJavaDecoder == nullptr) {
|
||||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||||
}
|
}
|
||||||
@ -281,10 +285,11 @@ class RemoteAudioDecoder final : public RemoteDataDecoder
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RemoteAudioDecoder(const AudioInfo& aConfig,
|
RemoteAudioDecoder(const AudioInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: RemoteDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
: RemoteDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
||||||
aFormat, aCallback)
|
aFormat, aCallback, aDrmStubId)
|
||||||
, mConfig(aConfig)
|
, mConfig(aConfig)
|
||||||
{
|
{
|
||||||
JNIEnv* const env = jni::GetEnvForThread();
|
JNIEnv* const env = jni::GetEnvForThread();
|
||||||
@ -311,7 +316,7 @@ public:
|
|||||||
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||||
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
||||||
|
|
||||||
mJavaDecoder = CodecProxy::Create(mFormat, nullptr, mJavaCallbacks);
|
mJavaDecoder = CodecProxy::Create(mFormat, nullptr, mJavaCallbacks, mDrmStubId);
|
||||||
if (mJavaDecoder == nullptr) {
|
if (mJavaDecoder == nullptr) {
|
||||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||||
}
|
}
|
||||||
@ -410,28 +415,32 @@ private:
|
|||||||
MediaDataDecoder*
|
MediaDataDecoder*
|
||||||
RemoteDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
RemoteDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
{
|
{
|
||||||
return new RemoteAudioDecoder(aConfig, aFormat, aCallback);
|
return new RemoteAudioDecoder(aConfig, aFormat, aCallback, aDrmStubId);
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDataDecoder*
|
MediaDataDecoder*
|
||||||
RemoteDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
RemoteDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer)
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
{
|
{
|
||||||
return new RemoteVideoDecoder(aConfig, aFormat, aCallback, aImageContainer);
|
return new RemoteVideoDecoder(aConfig, aFormat, aCallback, aImageContainer, aDrmStubId);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteDataDecoder::RemoteDataDecoder(MediaData::Type aType,
|
RemoteDataDecoder::RemoteDataDecoder(MediaData::Type aType,
|
||||||
const nsACString& aMimeType,
|
const nsACString& aMimeType,
|
||||||
MediaFormat::Param aFormat,
|
MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback)
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId)
|
||||||
: mType(aType)
|
: mType(aType)
|
||||||
, mMimeType(aMimeType)
|
, mMimeType(aMimeType)
|
||||||
, mFormat(aFormat)
|
, mFormat(aFormat)
|
||||||
, mCallback(aCallback)
|
, mCallback(aCallback)
|
||||||
|
, mDrmStubId(aDrmStubId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,14 @@ class RemoteDataDecoder : public MediaDataDecoder {
|
|||||||
public:
|
public:
|
||||||
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback);
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId);
|
||||||
|
|
||||||
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback,
|
MediaDataDecoderCallback* aCallback,
|
||||||
layers::ImageContainer* aImageContainer);
|
layers::ImageContainer* aImageContainer,
|
||||||
|
const nsString& aDrmStubId);
|
||||||
|
|
||||||
virtual ~RemoteDataDecoder() {}
|
virtual ~RemoteDataDecoder() {}
|
||||||
|
|
||||||
@ -44,7 +46,8 @@ protected:
|
|||||||
RemoteDataDecoder(MediaData::Type aType,
|
RemoteDataDecoder(MediaData::Type aType,
|
||||||
const nsACString& aMimeType,
|
const nsACString& aMimeType,
|
||||||
java::sdk::MediaFormat::Param aFormat,
|
java::sdk::MediaFormat::Param aFormat,
|
||||||
MediaDataDecoderCallback* aCallback);
|
MediaDataDecoderCallback* aCallback,
|
||||||
|
const nsString& aDrmStubId);
|
||||||
|
|
||||||
MediaData::Type mType;
|
MediaData::Type mType;
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ protected:
|
|||||||
|
|
||||||
java::CodecProxy::GlobalRef mJavaDecoder;
|
java::CodecProxy::GlobalRef mJavaDecoder;
|
||||||
java::CodecProxy::NativeCallbacks::GlobalRef mJavaCallbacks;
|
java::CodecProxy::NativeCallbacks::GlobalRef mJavaCallbacks;
|
||||||
|
nsString mDrmStubId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -222,7 +222,7 @@ public:
|
|||||||
Dispatch();
|
Dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& ReturnValue() const {
|
T ReturnValue() const {
|
||||||
if (mSuccess) {
|
if (mSuccess) {
|
||||||
return mSuccessValue;
|
return mSuccessValue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,6 +54,7 @@ public:
|
|||||||
}
|
}
|
||||||
aValues.ComputeLengthAndData();
|
aValues.ComputeLengthAndData();
|
||||||
|
|
||||||
|
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve,
|
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve,
|
||||||
aStartTime, 0.0f, 0.0f, aDuration, aValues.Data(),
|
aStartTime, 0.0f, 0.0f, aDuration, aValues.Data(),
|
||||||
aValues.Length());
|
aValues.Length());
|
||||||
@ -82,6 +83,7 @@ public:
|
|||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueAtTime,
|
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueAtTime,
|
||||||
aStartTime, aValue);
|
aStartTime, aValue);
|
||||||
|
|
||||||
@ -95,6 +97,7 @@ public:
|
|||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime());
|
||||||
EventInsertionHelper(aRv, AudioTimelineEvent::LinearRamp, aEndTime, aValue);
|
EventInsertionHelper(aRv, AudioTimelineEvent::LinearRamp, aEndTime, aValue);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -106,6 +109,7 @@ public:
|
|||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime());
|
||||||
EventInsertionHelper(aRv, AudioTimelineEvent::ExponentialRamp,
|
EventInsertionHelper(aRv, AudioTimelineEvent::ExponentialRamp,
|
||||||
aEndTime, aValue);
|
aEndTime, aValue);
|
||||||
return this;
|
return this;
|
||||||
@ -119,6 +123,7 @@ public:
|
|||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetTarget,
|
EventInsertionHelper(aRv, AudioTimelineEvent::SetTarget,
|
||||||
aStartTime, aTarget,
|
aStartTime, aTarget,
|
||||||
aTimeConstant);
|
aTimeConstant);
|
||||||
@ -133,6 +138,8 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||||
|
|
||||||
// Remove some events on the main thread copy.
|
// Remove some events on the main thread copy.
|
||||||
AudioEventTimeline::CancelScheduledValues(aStartTime);
|
AudioEventTimeline::CancelScheduledValues(aStartTime);
|
||||||
|
|
||||||
|
@ -120,8 +120,6 @@ interface RTCPeerConnection : EventTarget {
|
|||||||
sequence<MediaStream> getLocalStreams ();
|
sequence<MediaStream> getLocalStreams ();
|
||||||
[UnsafeInPrerendering, Deprecated="RTCPeerConnectionGetStreams"]
|
[UnsafeInPrerendering, Deprecated="RTCPeerConnectionGetStreams"]
|
||||||
sequence<MediaStream> getRemoteStreams ();
|
sequence<MediaStream> getRemoteStreams ();
|
||||||
[UnsafeInPrerendering]
|
|
||||||
MediaStream? getStreamById (DOMString streamId);
|
|
||||||
void addStream (MediaStream stream);
|
void addStream (MediaStream stream);
|
||||||
|
|
||||||
// replaces addStream; fails if already added
|
// replaces addStream; fails if already added
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "GPUProcessManager.h"
|
#include "GPUProcessManager.h"
|
||||||
#include "GPUProcessHost.h"
|
#include "GPUProcessHost.h"
|
||||||
#include "GPUProcessListener.h"
|
#include "GPUProcessListener.h"
|
||||||
|
#include "mozilla/Sprintf.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/layers/APZCTreeManager.h"
|
#include "mozilla/layers/APZCTreeManager.h"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "Instruments.h"
|
#include "Instruments.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ template<typename T>
|
|||||||
class AutoReleased
|
class AutoReleased
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
|
MOZ_IMPLICIT AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~AutoReleased()
|
~AutoReleased()
|
||||||
|
@ -507,7 +507,7 @@ class CodeOffsetJump
|
|||||||
return jumpTableIndex_;
|
return jumpTableIndex_;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
CodeOffsetJump(size_t offset) : offset_(offset) {}
|
explicit CodeOffsetJump(size_t offset) : offset_(offset) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CodeOffsetJump() {
|
CodeOffsetJump() {
|
||||||
|
@ -71,7 +71,7 @@ class RelocationIterator
|
|||||||
uint32_t offset_;
|
uint32_t offset_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RelocationIterator(CompactBufferReader& reader)
|
explicit RelocationIterator(CompactBufferReader& reader)
|
||||||
: reader_(reader)
|
: reader_(reader)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -160,14 +160,14 @@ static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
|
|||||||
|
|
||||||
struct ImmTag : public Imm32
|
struct ImmTag : public Imm32
|
||||||
{
|
{
|
||||||
ImmTag(JSValueTag mask)
|
explicit ImmTag(JSValueTag mask)
|
||||||
: Imm32(int32_t(mask))
|
: Imm32(int32_t(mask))
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImmType : public ImmTag
|
struct ImmType : public ImmTag
|
||||||
{
|
{
|
||||||
ImmType(JSValueType type)
|
explicit ImmType(JSValueType type)
|
||||||
: ImmTag(JSVAL_TYPE_TO_TAG(type))
|
: ImmTag(JSVAL_TYPE_TO_TAG(type))
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -736,7 +736,7 @@ class OutOfLineTruncate : public OutOfLineCodeBase<CodeGeneratorX86>
|
|||||||
LTruncateDToInt32* ins_;
|
LTruncateDToInt32* ins_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OutOfLineTruncate(LTruncateDToInt32* ins)
|
explicit OutOfLineTruncate(LTruncateDToInt32* ins)
|
||||||
: ins_(ins)
|
: ins_(ins)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -753,7 +753,7 @@ class OutOfLineTruncateFloat32 : public OutOfLineCodeBase<CodeGeneratorX86>
|
|||||||
LTruncateFToInt32* ins_;
|
LTruncateFToInt32* ins_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OutOfLineTruncateFloat32(LTruncateFToInt32* ins)
|
explicit OutOfLineTruncateFloat32(LTruncateFToInt32* ins)
|
||||||
: ins_(ins)
|
: ins_(ins)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class BaseCompiler
|
|||||||
# ifdef DEBUG
|
# ifdef DEBUG
|
||||||
BaseCompiler& bc;
|
BaseCompiler& bc;
|
||||||
public:
|
public:
|
||||||
ScratchI32(BaseCompiler& bc) : bc(bc) {
|
explicit ScratchI32(BaseCompiler& bc) : bc(bc) {
|
||||||
MOZ_ASSERT(!bc.scratchRegisterTaken());
|
MOZ_ASSERT(!bc.scratchRegisterTaken());
|
||||||
bc.setScratchRegisterTaken(true);
|
bc.setScratchRegisterTaken(true);
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ class BaseCompiler
|
|||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
public:
|
public:
|
||||||
ScratchI32(BaseCompiler& bc) {}
|
explicit ScratchI32(BaseCompiler& bc) {}
|
||||||
# endif
|
# endif
|
||||||
operator Register() const {
|
operator Register() const {
|
||||||
# ifdef JS_CODEGEN_X86
|
# ifdef JS_CODEGEN_X86
|
||||||
|
@ -1567,32 +1567,18 @@ struct MaskLayerUserData : public LayerUserData
|
|||||||
struct CSSMaskLayerUserData : public LayerUserData
|
struct CSSMaskLayerUserData : public LayerUserData
|
||||||
{
|
{
|
||||||
CSSMaskLayerUserData()
|
CSSMaskLayerUserData()
|
||||||
: mImageLayers(nsStyleImageLayers::LayerType::Mask)
|
: mFrame(nullptr)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntRect& aBounds)
|
CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntSize& aMaskSize)
|
||||||
: mImageLayers(aFrame->StyleSVGReset()->mMask),
|
: mFrame(aFrame),
|
||||||
mContentRect(aFrame->GetContentRectRelativeToSelf()),
|
mMaskSize(aMaskSize)
|
||||||
mPaddingRect(aFrame->GetPaddingRectRelativeToSelf()),
|
{ }
|
||||||
mBorderRect(aFrame->GetRectRelativeToSelf()),
|
|
||||||
mMarginRect(aFrame->GetMarginRectRelativeToSelf()),
|
|
||||||
mBounds(aBounds)
|
|
||||||
{
|
|
||||||
Hash(aFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
CSSMaskLayerUserData& operator=(const CSSMaskLayerUserData& aOther)
|
CSSMaskLayerUserData& operator=(const CSSMaskLayerUserData& aOther)
|
||||||
{
|
{
|
||||||
mImageLayers = aOther.mImageLayers;
|
mFrame = aOther.mFrame;
|
||||||
|
mMaskSize = aOther.mMaskSize;
|
||||||
mContentRect = aOther.mContentRect;
|
|
||||||
mPaddingRect = aOther.mPaddingRect;
|
|
||||||
mBorderRect = aOther.mBorderRect;
|
|
||||||
mMarginRect = aOther.mMarginRect;
|
|
||||||
|
|
||||||
mBounds = aOther.mBounds;
|
|
||||||
|
|
||||||
mHash = aOther.mHash;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1600,22 +1586,16 @@ struct CSSMaskLayerUserData : public LayerUserData
|
|||||||
bool
|
bool
|
||||||
operator==(const CSSMaskLayerUserData& aOther) const
|
operator==(const CSSMaskLayerUserData& aOther) const
|
||||||
{
|
{
|
||||||
if (mHash != aOther.mHash) {
|
if (mFrame != aOther.mFrame) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mImageLayers.mLayers != aOther.mImageLayers.mLayers) {
|
// Even if the frame is valid, check the size of the display item's
|
||||||
return false;
|
// boundary is still necessary. For example, if we scale the masked frame
|
||||||
}
|
// by adding a transform property on it, the masked frame is valid itself
|
||||||
|
// but we have to regenerate mask according to the new size in device
|
||||||
if (!mContentRect.IsEqualEdges(aOther.mContentRect) ||
|
// space.
|
||||||
!mPaddingRect.IsEqualEdges(aOther.mPaddingRect) ||
|
if (mMaskSize != aOther.mMaskSize) {
|
||||||
!mBorderRect.IsEqualEdges(aOther.mBorderRect) ||
|
|
||||||
!mMarginRect.IsEqualEdges(aOther.mMarginRect)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mBounds.IsEqualEdges(aOther.mBounds)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1623,36 +1603,8 @@ struct CSSMaskLayerUserData : public LayerUserData
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Hash(nsIFrame* aFrame)
|
nsIFrame* mFrame;
|
||||||
{
|
nsIntSize mMaskSize;
|
||||||
uint32_t hash = 0;
|
|
||||||
|
|
||||||
const nsStyleImageLayers& imageLayers = aFrame->StyleSVGReset()->mMask;
|
|
||||||
for (uint32_t i = 0; i < imageLayers.mLayers.Length(); i++) {
|
|
||||||
const nsStyleImageLayers::Layer& newLayer = imageLayers.mLayers[i];
|
|
||||||
hash = AddToHash(hash, HashBytes(&newLayer, sizeof(newLayer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = AddToHash(hash, HashBytes(&mContentRect, sizeof(mContentRect)));
|
|
||||||
hash = AddToHash(hash, HashBytes(&mPaddingRect, sizeof(mPaddingRect)));
|
|
||||||
hash = AddToHash(hash, HashBytes(&mBorderRect, sizeof(mBorderRect)));
|
|
||||||
hash = AddToHash(hash, HashBytes(&mMarginRect, sizeof(mMarginRect)));
|
|
||||||
|
|
||||||
hash = AddToHash(hash, HashBytes(&mBounds, sizeof(mBounds)));
|
|
||||||
|
|
||||||
mHash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsStyleImageLayers mImageLayers;
|
|
||||||
|
|
||||||
nsRect mContentRect;
|
|
||||||
nsRect mPaddingRect;
|
|
||||||
nsRect mBorderRect;
|
|
||||||
nsRect mMarginRect;
|
|
||||||
|
|
||||||
nsIntRect mBounds;
|
|
||||||
|
|
||||||
uint32_t mHash;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3915,8 +3867,9 @@ ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
|
|||||||
bool snap;
|
bool snap;
|
||||||
nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
|
nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
|
||||||
nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
|
nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
|
||||||
CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect);
|
CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect.Size());
|
||||||
if (*oldUserData == newUserData) {
|
nsRect dirtyRect;
|
||||||
|
if (!aMaskItem->IsInvalid(dirtyRect) && *oldUserData == newUserData) {
|
||||||
aLayer->SetMaskLayer(maskLayer);
|
aLayer->SetMaskLayer(maskLayer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -7140,10 +7140,13 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
|||||||
nsSVGUtils::MaskUsage maskUsage;
|
nsSVGUtils::MaskUsage maskUsage;
|
||||||
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
||||||
|
|
||||||
if (!maskUsage.shouldGenerateMaskLayer ||
|
if (!maskUsage.shouldGenerateMaskLayer &&
|
||||||
maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
!maskUsage.shouldGenerateClipMaskLayer) {
|
||||||
maskUsage.shouldApplyBasicShape ||
|
return false;
|
||||||
maskUsage.shouldGenerateClipMaskLayer) {
|
}
|
||||||
|
|
||||||
|
if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
||||||
|
maskUsage.shouldApplyBasicShape) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7151,20 +7154,6 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX temporary disable drawing SVG mask onto mask layer before bug 1313877
|
|
||||||
// been fixed.
|
|
||||||
nsIFrame* firstFrame =
|
|
||||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
|
||||||
nsSVGEffects::EffectProperties effectProperties =
|
|
||||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
||||||
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
|
||||||
for (size_t i = 0; i < maskFrames.Length() ; i++) {
|
|
||||||
nsSVGMaskFrame *maskFrame = maskFrames[i];
|
|
||||||
if (maskFrame) {
|
|
||||||
return false; // Found SVG mask.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gfxPrefs::DrawMaskLayer()) {
|
if (gfxPrefs::DrawMaskLayer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1277,11 +1277,13 @@ public:
|
|||||||
uint16_t mPointerType;
|
uint16_t mPointerType;
|
||||||
bool mActiveState;
|
bool mActiveState;
|
||||||
bool mPrimaryState;
|
bool mPrimaryState;
|
||||||
|
bool mPreventMouseEventByContent;
|
||||||
explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
|
explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
|
||||||
bool aPrimaryState)
|
bool aPrimaryState)
|
||||||
: mPointerType(aPointerType)
|
: mPointerType(aPointerType)
|
||||||
, mActiveState(aActiveState)
|
, mActiveState(aActiveState)
|
||||||
, mPrimaryState(aPrimaryState)
|
, mPrimaryState(aPrimaryState)
|
||||||
|
, mPreventMouseEventByContent(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -6834,6 +6834,82 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles the preventDefault behavior of pointerdown. When user
|
||||||
|
* preventDefault on pointerdown, We have to mark the active pointer to prevent
|
||||||
|
* sebsequent mouse events (except mouse transition events) and default
|
||||||
|
* behaviors.
|
||||||
|
*
|
||||||
|
* We add mPreventMouseEventByContent flag in PointerInfo to represent the
|
||||||
|
* active pointer won't firing compatible mouse events. It's set to true when
|
||||||
|
* content preventDefault on pointerdown
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
PostHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
|
||||||
|
WidgetGUIEvent* aMouseOrTouchEvent)
|
||||||
|
{
|
||||||
|
if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
|
||||||
|
!aPointerEvent->DefaultPreventedByContent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nsIPresShell::PointerInfo* pointerInfo = nullptr;
|
||||||
|
if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
|
||||||
|
!pointerInfo) {
|
||||||
|
// We already added the PointerInfo for active pointer when
|
||||||
|
// PresShell::HandleEvent handling pointerdown event.
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
|
||||||
|
#endif // #ifdef DEBUG
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// PreventDefault only applied for active pointers.
|
||||||
|
if (!pointerInfo->mActiveState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aMouseOrTouchEvent->PreventDefault(false);
|
||||||
|
pointerInfo->mPreventMouseEventByContent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles the case when content had called preventDefault on the
|
||||||
|
* active pointer. In that case we have to prevent firing subsequent mouse
|
||||||
|
* to content. We check the flag PointerInfo::mPreventMouseEventByContent and
|
||||||
|
* call PreventDefault(false) to stop default behaviors and stop firing mouse
|
||||||
|
* events to content and chrome.
|
||||||
|
*
|
||||||
|
* note: mouse transition events are excluded
|
||||||
|
* note: we have to clean mPreventMouseEventByContent on pointerup for those
|
||||||
|
* devices support hover
|
||||||
|
* note: we don't suppress firing mouse events to chrome and system group
|
||||||
|
* handlers because they may implement default behaviors
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
PreHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
|
||||||
|
WidgetGUIEvent* aMouseOrTouchEvent)
|
||||||
|
{
|
||||||
|
if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nsIPresShell::PointerInfo* pointerInfo = nullptr;
|
||||||
|
if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
|
||||||
|
!pointerInfo) {
|
||||||
|
// The PointerInfo for active pointer should be added for normal cases. But
|
||||||
|
// in some cases, we may receive mouse events before adding PointerInfo in
|
||||||
|
// sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
|
||||||
|
// or change preference 'dom.w3c_pointer_events.enabled' from off to on).
|
||||||
|
// In these cases, we could ignore them because they are not the events
|
||||||
|
// between a DefaultPrevented pointerdown and the corresponding pointerup.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pointerInfo->mPreventMouseEventByContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aMouseOrTouchEvent->PreventDefault(false);
|
||||||
|
if (aPointerEvent->mMessage == ePointerUp) {
|
||||||
|
pointerInfo->mPreventMouseEventByContent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
||||||
nsIFrame* aFrame,
|
nsIFrame* aFrame,
|
||||||
@ -6880,8 +6956,10 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
|||||||
mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
|
mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
|
||||||
0.0f;
|
0.0f;
|
||||||
event.convertToPointer = mouseEvent->convertToPointer = false;
|
event.convertToPointer = mouseEvent->convertToPointer = false;
|
||||||
|
PreHandlePointerEventsPreventDefault(&event, aEvent);
|
||||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
||||||
aTargetContent);
|
aTargetContent);
|
||||||
|
PostHandlePointerEventsPreventDefault(&event, aEvent);
|
||||||
} else if (aEvent->mClass == eTouchEventClass) {
|
} else if (aEvent->mClass == eTouchEventClass) {
|
||||||
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
||||||
// loop over all touches and dispatch pointer events on each touch
|
// loop over all touches and dispatch pointer events on each touch
|
||||||
@ -6926,8 +7004,10 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
|||||||
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
|
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
|
||||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||||
event.convertToPointer = touch->convertToPointer = false;
|
event.convertToPointer = touch->convertToPointer = false;
|
||||||
|
PreHandlePointerEventsPreventDefault(&event, aEvent);
|
||||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
||||||
aTargetContent);
|
aTargetContent);
|
||||||
|
PostHandlePointerEventsPreventDefault(&event, aEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
40
layout/reftests/invalidation/clip-path-invalidation-1a.html
Normal file
40
layout/reftests/invalidation/clip-path-invalidation-1a.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: clipPath invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: scale(20);
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clipped {
|
||||||
|
clip-path: url(#cp1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer clipped"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeTransform()
|
||||||
|
{
|
||||||
|
document.getElementById("d1").style.transform = "scale(10)";
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeTransform, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<clipPath id="cp1">
|
||||||
|
<rect x="10" y="10" width="5" height="5"/>
|
||||||
|
</clipPath>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
47
layout/reftests/invalidation/clip-path-invalidation-1b.html
Normal file
47
layout/reftests/invalidation/clip-path-invalidation-1b.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: clipPath invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: scale(20);
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clipped {
|
||||||
|
clip-path: url(#cp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer clipped"><div class="inner"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeTransform()
|
||||||
|
{
|
||||||
|
document.getElementById("d1").style.transform = "scale(10)";
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeTransform, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<clipPath id="cp1">
|
||||||
|
<rect x="10" y="10" width="5" height="5"/>
|
||||||
|
</clipPath>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
42
layout/reftests/invalidation/clip-path-invalidation-1c.html
Normal file
42
layout/reftests/invalidation/clip-path-invalidation-1c.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: clipPath invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clipped {
|
||||||
|
clip-path: url(#cp1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer clipped"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeClipPath()
|
||||||
|
{
|
||||||
|
document.getElementById("r1").setAttribute("width", "50");
|
||||||
|
document.getElementById("r1").setAttribute("height", "50");
|
||||||
|
document.getElementById("r1").setAttribute("x", "100");
|
||||||
|
document.getElementById("r1").setAttribute("y", "100");
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeClipPath, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<clipPath id="cp1">
|
||||||
|
<rect id="r1" x="50" y="50" width="100" height="100"/>
|
||||||
|
</clipPath>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
50
layout/reftests/invalidation/clip-path-invalidation-1d.html
Normal file
50
layout/reftests/invalidation/clip-path-invalidation-1d.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: clipPath invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clipped {
|
||||||
|
clip-path: url(#cp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer clipped"><div class="inner"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeClipPath()
|
||||||
|
{
|
||||||
|
document.getElementById("r1").setAttribute("width", "50");
|
||||||
|
document.getElementById("r1").setAttribute("height", "50");
|
||||||
|
document.getElementById("r1").setAttribute("x", "100");
|
||||||
|
document.getElementById("r1").setAttribute("y", "100");
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeClipPath, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<clipPath id="cp1">
|
||||||
|
<rect id="r1" x="50" y="50" width="100" height="100"/>
|
||||||
|
</clipPath>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
22
layout/reftests/invalidation/mask-invalidation-1-ref.html
Normal file
22
layout/reftests/invalidation/mask-invalidation-1-ref.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask repainting.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div {
|
||||||
|
background-color: purple;
|
||||||
|
position: absolute;
|
||||||
|
margin: 1px 2px 3px 4px;
|
||||||
|
border: solid purple;
|
||||||
|
width: 44px;
|
||||||
|
height: 9px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="outer" style="top: 15px; left: 15px;"></div>
|
||||||
|
<div class="outer" style="top: 15px; left: 115px;"></div>
|
||||||
|
<div class="outer" style="top: 15px; left: 215px;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
77
layout/reftests/invalidation/mask-invalidation-1a.html
Normal file
77
layout/reftests/invalidation/mask-invalidation-1a.html
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
background-color: purple;
|
||||||
|
position: absolute;
|
||||||
|
margin: 1px 2px 3px 4px;
|
||||||
|
border: solid purple;
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
mask-origin: border-box;
|
||||||
|
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="100%" height="50%" fill="blue" fill-opacity="1"/><rect x="0" y="50%" width="100%" height="50%" fill="blue" fill-opacity="0"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
#d1 {
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
mask-clip: padding-box;
|
||||||
|
border-width: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#d2 {
|
||||||
|
top: 10px;
|
||||||
|
left: 110px;
|
||||||
|
mask-clip: padding-box;
|
||||||
|
border-width: 0px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#d3 {
|
||||||
|
top: 15px;
|
||||||
|
left: 215px;
|
||||||
|
mask-clip: content-box;
|
||||||
|
border-width: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"></div>
|
||||||
|
<div id="d2" class="outer mask"></div>
|
||||||
|
<div id="d3" class="outer mask"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function invalidateMaskedElements()
|
||||||
|
{
|
||||||
|
// Shrink border area, thicken padding area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d1").style.borderWidth = "5px";
|
||||||
|
document.getElementById("d1").style.padding = "5px";
|
||||||
|
|
||||||
|
// Shrink padding area, thicken border area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d2").style.borderWidth = "5px";
|
||||||
|
document.getElementById("d2").style.padding = "5px";
|
||||||
|
|
||||||
|
// Shrink border area, thicken content area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d3").style.width = "50px";
|
||||||
|
document.getElementById("d3").style.height = "30px";
|
||||||
|
document.getElementById("d3").style.borderWidth = "0px";
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
invalidateMaskedElements, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
84
layout/reftests/invalidation/mask-invalidation-1b.html
Normal file
84
layout/reftests/invalidation/mask-invalidation-1b.html
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
background-color: purple;
|
||||||
|
position: absolute;
|
||||||
|
margin: 1px 2px 3px 4px;
|
||||||
|
border: solid purple;
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
mask-origin: border-box;
|
||||||
|
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="100%" height="50%" fill="blue" fill-opacity="1"/><rect x="0" y="50%" width="100%" height="50%" fill="blue" fill-opacity="0"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
#d1 {
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
mask-clip: padding-box;
|
||||||
|
border-width: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#d2 {
|
||||||
|
top: 10px;
|
||||||
|
left: 110px;
|
||||||
|
mask-clip: padding-box;
|
||||||
|
border-width: 0px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#d3 {
|
||||||
|
top: 15px;
|
||||||
|
left: 215px;
|
||||||
|
mask-clip: content-box;
|
||||||
|
border-width: 10px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"><div class="inner"></div></div>
|
||||||
|
<div id="d2" class="outer mask"><div class="inner"></div></div>
|
||||||
|
<div id="d3" class="outer mask"><div class="inner"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function invalidateMaskedElements()
|
||||||
|
{
|
||||||
|
// Shrink border area, thicken padding area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d1").style.borderWidth = "5px";
|
||||||
|
document.getElementById("d1").style.padding = "5px";
|
||||||
|
|
||||||
|
// Shrink padding area, thicken border area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d2").style.borderWidth = "5px";
|
||||||
|
document.getElementById("d2").style.padding = "5px";
|
||||||
|
|
||||||
|
// Shrink border area, thicken content area. Keep ths size of this
|
||||||
|
// division unchanged.
|
||||||
|
document.getElementById("d3").style.width = "50px";
|
||||||
|
document.getElementById("d3").style.height = "30px";
|
||||||
|
document.getElementById("d3").style.borderWidth = "0px";
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
invalidateMaskedElements, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
layout/reftests/invalidation/mask-invalidation-2-ref.html
Normal file
14
layout/reftests/invalidation/mask-invalidation-2-ref.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask repainting.</title>
|
||||||
|
<link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
|
||||||
|
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<svg width="200" height="200">
|
||||||
|
<rect x="100" y="100" width="50" height="50" style="stroke:none; fill: purple;"/>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
36
layout/reftests/invalidation/mask-invalidation-2a.html
Normal file
36
layout/reftests/invalidation/mask-invalidation-2a.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: scale(20);
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><rect x="10" y="10" width="5" height="5" fill="black"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeTransform()
|
||||||
|
{
|
||||||
|
document.getElementById("d1").style.transform = "scale(10)";
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeTransform, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
43
layout/reftests/invalidation/mask-invalidation-2b.html
Normal file
43
layout/reftests/invalidation/mask-invalidation-2b.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: scale(20);
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><rect x="10" y="10" width="5" height="5" fill="black"/></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"><div class="inner"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeTransform()
|
||||||
|
{
|
||||||
|
document.getElementById("d1").style.transform = "scale(10)";
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeTransform, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
42
layout/reftests/invalidation/mask-invalidation-2c.html
Normal file
42
layout/reftests/invalidation/mask-invalidation-2c.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-image: url(#m1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeMask()
|
||||||
|
{
|
||||||
|
document.getElementById("r1").setAttribute("width", "50");
|
||||||
|
document.getElementById("r1").setAttribute("height", "50");
|
||||||
|
document.getElementById("r1").setAttribute("x", "100");
|
||||||
|
document.getElementById("r1").setAttribute("y", "100");
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeMask, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<mask id="m1" x="0" y="0" width="1" height="1">
|
||||||
|
<rect id="r1" x="50" y="50" width="100" height="100" style="stroke:none; fill: #ffffff;"/>
|
||||||
|
</mask>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
50
layout/reftests/invalidation/mask-invalidation-2d.html
Normal file
50
layout/reftests/invalidation/mask-invalidation-2d.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Masking: mask invalidation.</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div.outer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: purple;
|
||||||
|
border: solid purple;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mask {
|
||||||
|
mask-image: url(#m1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="d1" class="outer mask"><div class="inner"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function changeMask()
|
||||||
|
{
|
||||||
|
document.getElementById("r1").setAttribute("width", "50");
|
||||||
|
document.getElementById("r1").setAttribute("height", "50");
|
||||||
|
document.getElementById("r1").setAttribute("x", "100");
|
||||||
|
document.getElementById("r1").setAttribute("y", "100");
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("MozReftestInvalidate",
|
||||||
|
changeMask, false);
|
||||||
|
</script>
|
||||||
|
<svg height="0">
|
||||||
|
<mask id="m1" x="0" y="0" width="1" height="1">
|
||||||
|
<rect id="r1" x="50" y="50" width="100" height="100" style="stroke:none; fill: #ffffff;"/>
|
||||||
|
</mask>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -78,3 +78,16 @@ pref(layers.single-tile.enabled,false) != fast-scrolling.html about:blank
|
|||||||
== zero-opacity-animation.html about:blank
|
== zero-opacity-animation.html about:blank
|
||||||
== zero-opacity-text.html about:blank
|
== zero-opacity-text.html about:blank
|
||||||
== negative-w-component.html negative-w-component-ref.html
|
== negative-w-component.html negative-w-component-ref.html
|
||||||
|
|
||||||
|
== mask-invalidation-1a.html mask-invalidation-1-ref.html
|
||||||
|
== mask-invalidation-1b.html mask-invalidation-1-ref.html
|
||||||
|
|
||||||
|
== mask-invalidation-2a.html mask-invalidation-2-ref.html
|
||||||
|
== mask-invalidation-2b.html mask-invalidation-2-ref.html
|
||||||
|
== mask-invalidation-2c.html mask-invalidation-2-ref.html
|
||||||
|
== mask-invalidation-2d.html mask-invalidation-2-ref.html
|
||||||
|
|
||||||
|
== clip-path-invalidation-1a.html mask-invalidation-2-ref.html
|
||||||
|
== clip-path-invalidation-1b.html mask-invalidation-2-ref.html
|
||||||
|
== clip-path-invalidation-1c.html mask-invalidation-2-ref.html
|
||||||
|
== clip-path-invalidation-1d.html mask-invalidation-2-ref.html
|
||||||
|
@ -27,6 +27,8 @@ namespace css {
|
|||||||
* typedef ... input_type;
|
* typedef ... input_type;
|
||||||
* typedef ... input_array_type;
|
* typedef ... input_array_type;
|
||||||
*
|
*
|
||||||
|
* typedef ... coeff_type;
|
||||||
|
*
|
||||||
* typedef ... result_type;
|
* typedef ... result_type;
|
||||||
*
|
*
|
||||||
* // GetUnit(avalue) must return the correct nsCSSUnit for any
|
* // GetUnit(avalue) must return the correct nsCSSUnit for any
|
||||||
@ -40,17 +42,17 @@ namespace css {
|
|||||||
*
|
*
|
||||||
* result_type
|
* result_type
|
||||||
* MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
* MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||||
* float aValue1, result_type aValue2);
|
* coeff_type aValue1, result_type aValue2);
|
||||||
*
|
*
|
||||||
* result_type
|
* result_type
|
||||||
* MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
* MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||||
* result_type aValue1, float aValue2);
|
* result_type aValue1, coeff_type aValue2);
|
||||||
*
|
*
|
||||||
* result_type
|
* result_type
|
||||||
* ComputeLeafValue(const input_type& aValue);
|
* ComputeLeafValue(const input_type& aValue);
|
||||||
*
|
*
|
||||||
* float
|
* coeff_type
|
||||||
* ComputeNumber(const input_type& aValue);
|
* ComputeCoefficient(const coeff_type& aValue);
|
||||||
*
|
*
|
||||||
* The CalcOps methods might compute the calc() expression down to a
|
* The CalcOps methods might compute the calc() expression down to a
|
||||||
* number, reduce some parts of it to a number but replicate other
|
* number, reduce some parts of it to a number but replicate other
|
||||||
@ -59,18 +61,21 @@ namespace css {
|
|||||||
* values).
|
* values).
|
||||||
*
|
*
|
||||||
* For each leaf in the calc() expression, ComputeCalc will call either
|
* For each leaf in the calc() expression, ComputeCalc will call either
|
||||||
* ComputeNumber (when the leaf is the left side of a Times_L or the
|
* ComputeCoefficient (when the leaf is the left side of a Times_L or the
|
||||||
* right side of a Times_R or Divided) or ComputeLeafValue (otherwise).
|
* right side of a Times_R or Divided) or ComputeLeafValue (otherwise).
|
||||||
* (The CalcOps in the CSS parser that reduces purely numeric
|
* (The CalcOps in the CSS parser that reduces purely numeric
|
||||||
* expressions in turn calls ComputeCalc on numbers; other ops can
|
* expressions in turn calls ComputeCalc on numbers; other ops can
|
||||||
* presume that expressions in the number positions have already been
|
* presume that expressions in the coefficient positions have already been
|
||||||
* normalized to a single numeric value and derive from
|
* normalized to a single numeric value and derive from, if their coefficient
|
||||||
* NumbersAlreadyNormalizedCalcOps.)
|
* types are floats, FloatCoeffsAlreadyNormalizedCalcOps.)
|
||||||
|
*
|
||||||
|
* coeff_type will be float most of the time, but it's templatized so that
|
||||||
|
* ParseCalc can be used with <integer>s too.
|
||||||
*
|
*
|
||||||
* For non-leaves, one of the Merge functions will be called:
|
* For non-leaves, one of the Merge functions will be called:
|
||||||
* MergeAdditive for Plus and Minus
|
* MergeAdditive for Plus and Minus
|
||||||
* MergeMultiplicativeL for Times_L (number * value)
|
* MergeMultiplicativeL for Times_L (coeff * value)
|
||||||
* MergeMultiplicativeR for Times_R (value * number) and Divided
|
* MergeMultiplicativeR for Times_R (value * coeff) and Divided
|
||||||
*/
|
*/
|
||||||
template <class CalcOps>
|
template <class CalcOps>
|
||||||
static typename CalcOps::result_type
|
static typename CalcOps::result_type
|
||||||
@ -93,7 +98,7 @@ ComputeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
|||||||
case eCSSUnit_Calc_Times_L: {
|
case eCSSUnit_Calc_Times_L: {
|
||||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||||
float lhs = aOps.ComputeNumber(arr->Item(0));
|
typename CalcOps::coeff_type lhs = aOps.ComputeCoefficient(arr->Item(0));
|
||||||
typename CalcOps::result_type rhs = ComputeCalc(arr->Item(1), aOps);
|
typename CalcOps::result_type rhs = ComputeCalc(arr->Item(1), aOps);
|
||||||
return aOps.MergeMultiplicativeL(CalcOps::GetUnit(aValue), lhs, rhs);
|
return aOps.MergeMultiplicativeL(CalcOps::GetUnit(aValue), lhs, rhs);
|
||||||
}
|
}
|
||||||
@ -102,7 +107,7 @@ ComputeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
|||||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||||
typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps);
|
typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps);
|
||||||
float rhs = aOps.ComputeNumber(arr->Item(1));
|
typename CalcOps::coeff_type rhs = aOps.ComputeCoefficient(arr->Item(1));
|
||||||
return aOps.MergeMultiplicativeR(CalcOps::GetUnit(aValue), lhs, rhs);
|
return aOps.MergeMultiplicativeR(CalcOps::GetUnit(aValue), lhs, rhs);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -135,6 +140,7 @@ struct CSSValueInputCalcOps
|
|||||||
struct BasicCoordCalcOps
|
struct BasicCoordCalcOps
|
||||||
{
|
{
|
||||||
typedef nscoord result_type;
|
typedef nscoord result_type;
|
||||||
|
typedef float coeff_type;
|
||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||||
@ -150,7 +156,7 @@ struct BasicCoordCalcOps
|
|||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||||
float aValue1, result_type aValue2)
|
coeff_type aValue1, result_type aValue2)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||||
"unexpected unit");
|
"unexpected unit");
|
||||||
@ -159,7 +165,7 @@ struct BasicCoordCalcOps
|
|||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||||
result_type aValue1, float aValue2)
|
result_type aValue1, coeff_type aValue2)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_R ||
|
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_R ||
|
||||||
aCalcFunction == eCSSUnit_Calc_Divided,
|
aCalcFunction == eCSSUnit_Calc_Divided,
|
||||||
@ -174,6 +180,7 @@ struct BasicCoordCalcOps
|
|||||||
struct BasicFloatCalcOps
|
struct BasicFloatCalcOps
|
||||||
{
|
{
|
||||||
typedef float result_type;
|
typedef float result_type;
|
||||||
|
typedef float coeff_type;
|
||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||||
@ -189,7 +196,7 @@ struct BasicFloatCalcOps
|
|||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||||
float aValue1, result_type aValue2)
|
coeff_type aValue1, result_type aValue2)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||||
"unexpected unit");
|
"unexpected unit");
|
||||||
@ -198,7 +205,7 @@ struct BasicFloatCalcOps
|
|||||||
|
|
||||||
result_type
|
result_type
|
||||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||||
result_type aValue1, float aValue2)
|
result_type aValue1, coeff_type aValue2)
|
||||||
{
|
{
|
||||||
if (aCalcFunction == eCSSUnit_Calc_Times_R) {
|
if (aCalcFunction == eCSSUnit_Calc_Times_R) {
|
||||||
return aValue1 * aValue2;
|
return aValue1 * aValue2;
|
||||||
@ -209,13 +216,55 @@ struct BasicFloatCalcOps
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
struct BasicIntegerCalcOps
|
||||||
* A ComputeNumber implementation for callers that can assume numbers
|
|
||||||
* are already normalized (i.e., anything past the parser).
|
|
||||||
*/
|
|
||||||
struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
|
|
||||||
{
|
{
|
||||||
float ComputeNumber(const nsCSSValue& aValue)
|
typedef int result_type;
|
||||||
|
typedef int coeff_type;
|
||||||
|
|
||||||
|
result_type
|
||||||
|
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||||
|
result_type aValue1, result_type aValue2)
|
||||||
|
{
|
||||||
|
if (aCalcFunction == eCSSUnit_Calc_Plus) {
|
||||||
|
return aValue1 + aValue2;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Minus,
|
||||||
|
"unexpected unit");
|
||||||
|
return aValue1 - aValue2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_type
|
||||||
|
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||||
|
coeff_type aValue1, result_type aValue2)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||||
|
"unexpected unit");
|
||||||
|
return aValue1 * aValue2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_type
|
||||||
|
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||||
|
result_type aValue1, coeff_type aValue2)
|
||||||
|
{
|
||||||
|
if (aCalcFunction == eCSSUnit_Calc_Times_R) {
|
||||||
|
return aValue1 * aValue2;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT_UNREACHABLE("We should catch and prevent divisions in integer "
|
||||||
|
"calc()s in the parser.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ComputeCoefficient implementation for callers that can assume coefficients
|
||||||
|
* are floats and are already normalized (i.e., anything past the parser except
|
||||||
|
* pure-integer calcs, whose coefficients are integers).
|
||||||
|
*/
|
||||||
|
struct FloatCoeffsAlreadyNormalizedOps : public CSSValueInputCalcOps
|
||||||
|
{
|
||||||
|
typedef float coeff_type;
|
||||||
|
|
||||||
|
coeff_type ComputeCoefficient(const nsCSSValue& aValue)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
||||||
return aValue.GetFloatValue();
|
return aValue.GetFloatValue();
|
||||||
@ -240,7 +289,11 @@ struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
|
|||||||
*
|
*
|
||||||
* void Append(const char* aString);
|
* void Append(const char* aString);
|
||||||
* void AppendLeafValue(const input_type& aValue);
|
* void AppendLeafValue(const input_type& aValue);
|
||||||
* void AppendNumber(const input_type& aValue);
|
*
|
||||||
|
* // AppendCoefficient accepts an input_type value, which represents a
|
||||||
|
* // value in the coefficient position, not a value of coeff_type,
|
||||||
|
* // because we're serializing the calc() expression itself.
|
||||||
|
* void AppendCoefficient(const input_type& aValue);
|
||||||
*
|
*
|
||||||
* Data structures given may or may not have a toplevel eCSSUnit_Calc
|
* Data structures given may or may not have a toplevel eCSSUnit_Calc
|
||||||
* node representing a calc whose toplevel is not min() or max().
|
* node representing a calc whose toplevel is not min() or max().
|
||||||
@ -320,7 +373,7 @@ SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
|||||||
aOps.Append("(");
|
aOps.Append("(");
|
||||||
}
|
}
|
||||||
if (unit == eCSSUnit_Calc_Times_L) {
|
if (unit == eCSSUnit_Calc_Times_L) {
|
||||||
aOps.AppendNumber(array->Item(0));
|
aOps.AppendCoefficient(array->Item(0));
|
||||||
} else {
|
} else {
|
||||||
SerializeCalcInternal(array->Item(0), aOps);
|
SerializeCalcInternal(array->Item(0), aOps);
|
||||||
}
|
}
|
||||||
@ -344,7 +397,7 @@ SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
|||||||
if (unit == eCSSUnit_Calc_Times_L) {
|
if (unit == eCSSUnit_Calc_Times_L) {
|
||||||
SerializeCalcInternal(array->Item(1), aOps);
|
SerializeCalcInternal(array->Item(1), aOps);
|
||||||
} else {
|
} else {
|
||||||
aOps.AppendNumber(array->Item(1));
|
aOps.AppendCoefficient(array->Item(1));
|
||||||
}
|
}
|
||||||
if (needParens) {
|
if (needParens) {
|
||||||
aOps.Append(")");
|
aOps.Append(")");
|
||||||
@ -354,6 +407,48 @@ SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReduceNumberCalcOps is a CalcOps implementation for pure-number calc()
|
||||||
|
* (sub-)expressions, input as nsCSSValues.
|
||||||
|
* For example, nsCSSParser::ParseCalcMultiplicativeExpression uses it to
|
||||||
|
* simplify numeric sub-expressions in order to check for division-by-zero.
|
||||||
|
*/
|
||||||
|
struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps,
|
||||||
|
public mozilla::css::CSSValueInputCalcOps
|
||||||
|
{
|
||||||
|
result_type ComputeLeafValue(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
||||||
|
return aValue.GetFloatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
coeff_type ComputeCoefficient(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
return mozilla::css::ComputeCalc(aValue, *this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReduceIntegerCalcOps is a CalcOps implementation for pure-integer calc()
|
||||||
|
* (sub-)expressions, input as nsCSSValues.
|
||||||
|
*/
|
||||||
|
struct ReduceIntegerCalcOps : public mozilla::css::BasicIntegerCalcOps,
|
||||||
|
public mozilla::css::CSSValueInputCalcOps
|
||||||
|
{
|
||||||
|
result_type
|
||||||
|
ComputeLeafValue(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Integer, "unexpected unit");
|
||||||
|
return aValue.GetIntValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
coeff_type
|
||||||
|
ComputeCoefficient(const nsCSSValue& aValue)
|
||||||
|
{
|
||||||
|
return mozilla::css::ComputeCalc(aValue, *this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace css
|
} // namespace css
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -8148,10 +8148,14 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
|
|||||||
}
|
}
|
||||||
if ((aVariantMask & VARIANT_CALC) &&
|
if ((aVariantMask & VARIANT_CALC) &&
|
||||||
IsCSSTokenCalcFunction(*tk)) {
|
IsCSSTokenCalcFunction(*tk)) {
|
||||||
// calc() currently allows only lengths and percents and number inside it.
|
// calc() currently allows only lengths, percents, numbers, and integers.
|
||||||
// And note that in current implementation, number cannot be mixed with
|
//
|
||||||
// length and percent.
|
// Note that VARIANT_NUMBER can be mixed with VARIANT_LENGTH and
|
||||||
if (!ParseCalc(aValue, aVariantMask & VARIANT_LPN)) {
|
// VARIANT_PERCENTAGE in the list of allowed types (numbers can be used as
|
||||||
|
// coefficients).
|
||||||
|
// However, the the resulting type is not a mixed type with number.
|
||||||
|
// VARIANT_INTEGER can't be mixed with anything else.
|
||||||
|
if (!ParseCalc(aValue, aVariantMask & (VARIANT_LPN | VARIANT_INTEGER))) {
|
||||||
return CSSParseResult::Error;
|
return CSSParseResult::Error;
|
||||||
}
|
}
|
||||||
return CSSParseResult::Ok;
|
return CSSParseResult::Ok;
|
||||||
@ -13638,6 +13642,9 @@ CSSParserImpl::ParseCalc(nsCSSValue &aValue, uint32_t aVariantMask)
|
|||||||
// This can be done without lookahead when we assume that the property
|
// This can be done without lookahead when we assume that the property
|
||||||
// values cannot themselves be numbers.
|
// values cannot themselves be numbers.
|
||||||
MOZ_ASSERT(aVariantMask != 0, "unexpected variant mask");
|
MOZ_ASSERT(aVariantMask != 0, "unexpected variant mask");
|
||||||
|
MOZ_ASSERT(!(aVariantMask & VARIANT_LPN) != !(aVariantMask & VARIANT_INTEGER),
|
||||||
|
"variant mask must intersect with exactly one of VARIANT_LPN "
|
||||||
|
"or VARIANT_INTEGER");
|
||||||
|
|
||||||
bool oldUnitlessLengthQuirk = mUnitlessLengthQuirk;
|
bool oldUnitlessLengthQuirk = mUnitlessLengthQuirk;
|
||||||
mUnitlessLengthQuirk = false;
|
mUnitlessLengthQuirk = false;
|
||||||
@ -13708,21 +13715,6 @@ CSSParserImpl::ParseCalcAdditiveExpression(nsCSSValue& aValue,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps,
|
|
||||||
public mozilla::css::CSSValueInputCalcOps
|
|
||||||
{
|
|
||||||
result_type ComputeLeafValue(const nsCSSValue& aValue)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
|
||||||
return aValue.GetFloatValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
float ComputeNumber(const nsCSSValue& aValue)
|
|
||||||
{
|
|
||||||
return mozilla::css::ComputeCalc(aValue, *this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// * If aVariantMask is VARIANT_NUMBER, this function parses the
|
// * If aVariantMask is VARIANT_NUMBER, this function parses the
|
||||||
// <number-multiplicative-expression> production.
|
// <number-multiplicative-expression> production.
|
||||||
// * If aVariantMask does not contain VARIANT_NUMBER, this function
|
// * If aVariantMask does not contain VARIANT_NUMBER, this function
|
||||||
@ -13748,9 +13740,18 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
|||||||
nsCSSValue *storage = &aValue;
|
nsCSSValue *storage = &aValue;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint32_t variantMask;
|
uint32_t variantMask;
|
||||||
if (afterDivision || gotValue) {
|
if (aVariantMask & VARIANT_INTEGER) {
|
||||||
|
MOZ_ASSERT(aVariantMask == VARIANT_INTEGER,
|
||||||
|
"integers in calc expressions can't be mixed with anything "
|
||||||
|
"else.");
|
||||||
|
variantMask = aVariantMask;
|
||||||
|
} else if (afterDivision || gotValue) {
|
||||||
|
// At this point in the calc expression, we expect a coefficient or a
|
||||||
|
// divisor, which must be a number. (Not a length/%/etc.)
|
||||||
variantMask = VARIANT_NUMBER;
|
variantMask = VARIANT_NUMBER;
|
||||||
} else {
|
} else {
|
||||||
|
// At this point in the calc expression, we'll accept a coefficient
|
||||||
|
// (a number) or a value of whatever type |aVariantMask| specifies.
|
||||||
variantMask = aVariantMask | VARIANT_NUMBER;
|
variantMask = aVariantMask | VARIANT_NUMBER;
|
||||||
}
|
}
|
||||||
if (!ParseCalcTerm(*storage, variantMask))
|
if (!ParseCalcTerm(*storage, variantMask))
|
||||||
@ -13764,7 +13765,7 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
|||||||
if (variantMask & VARIANT_NUMBER) {
|
if (variantMask & VARIANT_NUMBER) {
|
||||||
// Simplify the value immediately so we can check for division by
|
// Simplify the value immediately so we can check for division by
|
||||||
// zero.
|
// zero.
|
||||||
ReduceNumberCalcOps ops;
|
mozilla::css::ReduceNumberCalcOps ops;
|
||||||
float number = mozilla::css::ComputeCalc(*storage, ops);
|
float number = mozilla::css::ComputeCalc(*storage, ops);
|
||||||
if (number == 0.0 && afterDivision)
|
if (number == 0.0 && afterDivision)
|
||||||
return false;
|
return false;
|
||||||
@ -13778,9 +13779,15 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
|||||||
MOZ_ASSERT(storage == &aValue.GetArrayValue()->Item(1),
|
MOZ_ASSERT(storage == &aValue.GetArrayValue()->Item(1),
|
||||||
"unexpected relationship to current storage");
|
"unexpected relationship to current storage");
|
||||||
nsCSSValue &leftValue = aValue.GetArrayValue()->Item(0);
|
nsCSSValue &leftValue = aValue.GetArrayValue()->Item(0);
|
||||||
ReduceNumberCalcOps ops;
|
if (variantMask & VARIANT_INTEGER) {
|
||||||
float number = mozilla::css::ComputeCalc(leftValue, ops);
|
mozilla::css::ReduceIntegerCalcOps ops;
|
||||||
leftValue.SetFloatValue(number, eCSSUnit_Number);
|
int integer = mozilla::css::ComputeCalc(leftValue, ops);
|
||||||
|
leftValue.SetIntValue(integer, eCSSUnit_Integer);
|
||||||
|
} else {
|
||||||
|
mozilla::css::ReduceNumberCalcOps ops;
|
||||||
|
float number = mozilla::css::ComputeCalc(leftValue, ops);
|
||||||
|
leftValue.SetFloatValue(number, eCSSUnit_Number);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13794,6 +13801,19 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
|||||||
unit = gotValue ? eCSSUnit_Calc_Times_R : eCSSUnit_Calc_Times_L;
|
unit = gotValue ? eCSSUnit_Calc_Times_R : eCSSUnit_Calc_Times_L;
|
||||||
afterDivision = false;
|
afterDivision = false;
|
||||||
} else if (mToken.IsSymbol('/')) {
|
} else if (mToken.IsSymbol('/')) {
|
||||||
|
if (variantMask & VARIANT_INTEGER) {
|
||||||
|
// Integers aren't mixed with anything else (see the assert at the top
|
||||||
|
// of CSSParserImpl::ParseCalc).
|
||||||
|
// We don't allow division at all in calc()s for expressions where an
|
||||||
|
// integer is expected, because calc() division can't be resolved to
|
||||||
|
// an integer, as implied by spec text about '/' here:
|
||||||
|
// https://drafts.csswg.org/css-values-3/#calc-type-checking
|
||||||
|
// We've consumed the '/' token, but it doesn't matter as we're in an
|
||||||
|
// error-handling situation where we've already consumed a lot of
|
||||||
|
// other tokens (e.g. the token before the '/'). ParseVariant will
|
||||||
|
// indicate this with CSSParseResult::Error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
unit = eCSSUnit_Calc_Divided;
|
unit = eCSSUnit_Calc_Divided;
|
||||||
afterDivision = true;
|
afterDivision = true;
|
||||||
} else {
|
} else {
|
||||||
@ -13853,15 +13873,24 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, uint32_t& aVariantMask)
|
|||||||
}
|
}
|
||||||
// ... or just a value
|
// ... or just a value
|
||||||
UngetToken();
|
UngetToken();
|
||||||
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
|
if (aVariantMask & VARIANT_INTEGER) {
|
||||||
// always gets picked up
|
// Integers aren't mixed with anything else (see the assert at the
|
||||||
if (ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr) !=
|
// top of CSSParserImpl::ParseCalc).
|
||||||
CSSParseResult::Ok) {
|
if (ParseVariant(aValue, aVariantMask, nullptr) != CSSParseResult::Ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// ...and do the VARIANT_NUMBER check ourselves.
|
} else {
|
||||||
if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) {
|
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
|
||||||
return false;
|
// always gets picked up (we want to catch unitless zeroes using
|
||||||
|
// VARIANT_NUMBER and then error out)
|
||||||
|
if (ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr) !=
|
||||||
|
CSSParseResult::Ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// ...and do the VARIANT_NUMBER check ourselves.
|
||||||
|
if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If we did the value parsing, we need to adjust aVariantMask to
|
// If we did the value parsing, we need to adjust aVariantMask to
|
||||||
// reflect which option we took (see above).
|
// reflect which option we took (see above).
|
||||||
|
@ -953,7 +953,7 @@ struct CSSValueSerializeCalcOps {
|
|||||||
aValue.AppendToString(mProperty, mResult, mValueSerialization);
|
aValue.AppendToString(mProperty, mResult, mValueSerialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendNumber(const input_type& aValue)
|
void AppendCoefficient(const input_type& aValue)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
||||||
aValue.AppendToString(mProperty, mResult, mValueSerialization);
|
aValue.AppendToString(mProperty, mResult, mValueSerialization);
|
||||||
|
@ -327,8 +327,13 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
|||||||
RuleNodeCacheConditions& aConditions);
|
RuleNodeCacheConditions& aConditions);
|
||||||
|
|
||||||
struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
||||||
public css::NumbersAlreadyNormalizedOps
|
public css::FloatCoeffsAlreadyNormalizedOps
|
||||||
{
|
{
|
||||||
|
// Declare that we have floats as coefficients so that we unambiguously
|
||||||
|
// resolve coeff_type (BasicCoordCalcOps and FloatCoeffsAlreadyNormalizedOps
|
||||||
|
// both have |typedef float coeff_type|).
|
||||||
|
typedef float coeff_type;
|
||||||
|
|
||||||
// All of the parameters to CalcLengthWith except aValue.
|
// All of the parameters to CalcLengthWith except aValue.
|
||||||
const nscoord mFontSize;
|
const nscoord mFontSize;
|
||||||
const nsStyleFont* const mStyleFont;
|
const nsStyleFont* const mStyleFont;
|
||||||
@ -667,7 +672,7 @@ nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
|||||||
true, false, conditions);
|
true, false, conditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
|
struct LengthPercentPairCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
|
||||||
{
|
{
|
||||||
typedef nsRuleNode::ComputedCalc result_type;
|
typedef nsRuleNode::ComputedCalc result_type;
|
||||||
|
|
||||||
@ -3318,8 +3323,13 @@ nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
|
struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
|
||||||
public css::NumbersAlreadyNormalizedOps
|
public css::FloatCoeffsAlreadyNormalizedOps
|
||||||
{
|
{
|
||||||
|
// Declare that we have floats as coefficients so that we unambiguously
|
||||||
|
// resolve coeff_type (BasicCoordCalcOps and FloatCoeffsAlreadyNormalizedOps
|
||||||
|
// both have |typedef float coeff_type|).
|
||||||
|
typedef float coeff_type;
|
||||||
|
|
||||||
// The parameters beyond aValue that we need for CalcLengthWith.
|
// The parameters beyond aValue that we need for CalcLengthWith.
|
||||||
const nscoord mParentSize;
|
const nscoord mParentSize;
|
||||||
const nsStyleFont* const mParentFont;
|
const nsStyleFont* const mParentFont;
|
||||||
@ -4449,7 +4459,7 @@ struct LineHeightCalcObj
|
|||||||
bool mIsNumber;
|
bool mIsNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetLineHeightCalcOps : public css::NumbersAlreadyNormalizedOps
|
struct SetLineHeightCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
|
||||||
{
|
{
|
||||||
typedef LineHeightCalcObj result_type;
|
typedef LineHeightCalcObj result_type;
|
||||||
nsStyleContext* const mStyleContext;
|
nsStyleContext* const mStyleContext;
|
||||||
|
@ -478,10 +478,9 @@ PaintMaskSurface(const PaintFramesParams& aParams,
|
|||||||
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
||||||
|
|
||||||
maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
|
maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
|
||||||
Rect drawRect = IntRectToRect(IntRect(IntPoint(0, 0), svgMask->GetSize()));
|
|
||||||
aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
|
aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
|
||||||
drawRect.TopLeft(),
|
Point(0, 0),
|
||||||
DrawOptions(1.0, compositionOp));
|
DrawOptions(1.0, compositionOp));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
||||||
@ -704,7 +703,8 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
|
|||||||
nsSVGUtils::MaskUsage maskUsage;
|
nsSVGUtils::MaskUsage maskUsage;
|
||||||
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
|
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
|
||||||
maskUsage);
|
maskUsage);
|
||||||
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
|
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer ||
|
||||||
|
maskUsage.shouldGenerateClipMaskLayer);
|
||||||
|
|
||||||
nsIFrame* frame = aParams.frame;
|
nsIFrame* frame = aParams.frame;
|
||||||
if (!ValidateSVGFrame(frame)) {
|
if (!ValidateSVGFrame(frame)) {
|
||||||
@ -716,25 +716,77 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfxContext& ctx = aParams.ctx;
|
gfxContext& ctx = aParams.ctx;
|
||||||
|
|
||||||
gfxContextMatrixAutoSaveRestore matSR(&ctx);
|
|
||||||
|
|
||||||
nsIFrame* firstFrame =
|
nsIFrame* firstFrame =
|
||||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||||
nsSVGEffects::EffectProperties effectProperties =
|
nsSVGEffects::EffectProperties effectProperties =
|
||||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||||
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
|
||||||
bool opacityApplied = !HasNonSVGMask(maskFrames);
|
|
||||||
|
|
||||||
|
DrawResult result = DrawResult::SUCCESS;
|
||||||
nsPoint offsetToBoundingBox;
|
nsPoint offsetToBoundingBox;
|
||||||
nsPoint offsetToUserSpace;
|
nsPoint offsetToUserSpace;
|
||||||
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
|
gfxContextMatrixAutoSaveRestore matSR;
|
||||||
offsetToUserSpace, false);
|
DrawTarget* target = ctx.GetDrawTarget();
|
||||||
|
|
||||||
return PaintMaskSurface(aParams, ctx.GetDrawTarget(),
|
// Paint mask onto ctx.
|
||||||
opacityApplied ? maskUsage.opacity : 1.0,
|
if (maskUsage.shouldGenerateMaskLayer) {
|
||||||
firstFrame->StyleContext(), maskFrames,
|
matSR.SetContext(&ctx);
|
||||||
ctx.CurrentMatrix(), offsetToUserSpace);
|
|
||||||
|
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
|
||||||
|
offsetToUserSpace, false);
|
||||||
|
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
||||||
|
bool opacityApplied = !HasNonSVGMask(maskFrames);
|
||||||
|
result = PaintMaskSurface(aParams, target,
|
||||||
|
opacityApplied ? maskUsage.opacity : 1.0,
|
||||||
|
firstFrame->StyleContext(), maskFrames,
|
||||||
|
ctx.CurrentMatrix(), offsetToUserSpace);
|
||||||
|
if (result != DrawResult::SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paint clip-path onto ctx.
|
||||||
|
if (maskUsage.shouldGenerateClipMaskLayer) {
|
||||||
|
matSR.Restore();
|
||||||
|
matSR.SetContext(&ctx);
|
||||||
|
|
||||||
|
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||||
|
offsetToUserSpace, false);
|
||||||
|
Matrix clipMaskTransform;
|
||||||
|
gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
|
||||||
|
|
||||||
|
bool isOK = true;
|
||||||
|
nsSVGClipPathFrame *clipPathFrame =
|
||||||
|
effectProperties.GetClipPathFrame(&isOK);
|
||||||
|
// XXX Bug 1317636. Split nsSVGClipPathFrame::GetClipMask into two
|
||||||
|
// functions:
|
||||||
|
// 1. nsSVGClipPathFrame::CreateClipMask
|
||||||
|
// Create an A8 surface with right size for painting clip-path mask.
|
||||||
|
// 2. nsSVGClipPathFrame::PaintClipMask
|
||||||
|
// Paint the content of clip-path _direct_ onto a given A8 surface.
|
||||||
|
// With this change, we can skip one extra draw call
|
||||||
|
// (DrawTarget::MaskSurface) bellow.
|
||||||
|
RefPtr<SourceSurface> clipMaskSurface =
|
||||||
|
clipPathFrame->GetClipMask(ctx, frame, cssPxToDevPxMatrix,
|
||||||
|
&clipMaskTransform, nullptr,
|
||||||
|
ToMatrix(ctx.CurrentMatrix()), &result);
|
||||||
|
|
||||||
|
if (clipMaskSurface) {
|
||||||
|
gfxContextMatrixAutoSaveRestore matRestore(&ctx);
|
||||||
|
ctx.Multiply(ThebesMatrix(clipMaskTransform));
|
||||||
|
CompositionOp op = maskUsage.shouldGenerateMaskLayer
|
||||||
|
? CompositionOp::OP_IN : CompositionOp::OP_OVER;
|
||||||
|
target->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)),
|
||||||
|
clipMaskSurface,
|
||||||
|
Point(),
|
||||||
|
DrawOptions(1.0, op));
|
||||||
|
} else {
|
||||||
|
// Either entire surface is clipped out, or gfx buffer allocation
|
||||||
|
// failure in nsSVGClipPathFrame::GetClipMask.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawResult
|
DrawResult
|
||||||
@ -828,15 +880,15 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||||||
|
|
||||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||||
offsetToUserSpace, false);
|
offsetToUserSpace, false);
|
||||||
Matrix clippedMaskTransform;
|
Matrix clipMaskTransform;
|
||||||
RefPtr<SourceSurface> clipMaskSurface =
|
RefPtr<SourceSurface> clipMaskSurface =
|
||||||
clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
|
clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
|
||||||
&clippedMaskTransform, maskSurface,
|
&clipMaskTransform, maskSurface,
|
||||||
maskTransform, &result);
|
maskTransform, &result);
|
||||||
|
|
||||||
if (clipMaskSurface) {
|
if (clipMaskSurface) {
|
||||||
maskSurface = clipMaskSurface;
|
maskSurface = clipMaskSurface;
|
||||||
maskTransform = clippedMaskTransform;
|
maskTransform = clipMaskTransform;
|
||||||
} else {
|
} else {
|
||||||
// Either entire surface is clipped out, or gfx buffer allocation
|
// Either entire surface is clipped out, or gfx buffer allocation
|
||||||
// failure in nsSVGClipPathFrame::GetClipMask.
|
// failure in nsSVGClipPathFrame::GetClipMask.
|
||||||
|
@ -122,4 +122,5 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
|||||||
GYP_DIRS['signalingtest'].sandbox_vars['ALLOW_COMPILER_WARNINGS'] = True
|
GYP_DIRS['signalingtest'].sandbox_vars['ALLOW_COMPILER_WARNINGS'] = True
|
||||||
GYP_DIRS['signalingtest'].non_unified_sources += signaling_non_unified_sources
|
GYP_DIRS['signalingtest'].non_unified_sources += signaling_non_unified_sources
|
||||||
|
|
||||||
DIRS += ['signaling/fuzztest']
|
if CONFIG['ENABLE_TESTS']:
|
||||||
|
DIRS += ['signaling/fuzztest']
|
||||||
|
@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
#define GTEST_HAS_RTTI 0
|
#define GTEST_HAS_RTTI 0
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "gtest_utils.h"
|
|
||||||
|
|
||||||
#include "FakeMediaStreams.h"
|
|
||||||
#include "FakeMediaStreamsImpl.h"
|
|
||||||
#include "FakeLogging.h"
|
|
||||||
|
|
||||||
#include "signaling/src/sdp/SdpMediaSection.h"
|
#include "signaling/src/sdp/SdpMediaSection.h"
|
||||||
#include "signaling/src/sdp/SipccSdpParser.h"
|
#include "signaling/src/sdp/SipccSdpParser.h"
|
||||||
@ -30,19 +25,17 @@
|
|||||||
#include "signaling/src/jsep/JsepSessionImpl.h"
|
#include "signaling/src/jsep/JsepSessionImpl.h"
|
||||||
#include "signaling/src/jsep/JsepTrack.h"
|
#include "signaling/src/jsep/JsepTrack.h"
|
||||||
|
|
||||||
#include "mtransport_test_utils.h"
|
|
||||||
|
|
||||||
#include "FakeIPC.h"
|
|
||||||
#include "FakeIPC.cpp"
|
|
||||||
|
|
||||||
#include "TestHarness.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
static std::string kAEqualsCandidate("a=candidate:");
|
static std::string kAEqualsCandidate("a=candidate:");
|
||||||
const static size_t kNumCandidatesPerComponent = 3;
|
const static size_t kNumCandidatesPerComponent = 3;
|
||||||
|
|
||||||
class JsepSessionTestBase : public ::testing::Test
|
class JsepSessionTestBase : public ::testing::Test
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static void SetUpTestCase() {
|
||||||
|
NSS_NoDB_Init(nullptr);
|
||||||
|
NSS_SetDomesticPolicy();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class FakeUuidGenerator : public mozilla::JsepUuidGenerator
|
class FakeUuidGenerator : public mozilla::JsepUuidGenerator
|
||||||
@ -4220,16 +4213,3 @@ TEST_F(JsepSessionTest, TestNonDefaultProtocol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
// Prevents some log spew
|
|
||||||
ScopedXPCOM xpcom("jsep_session_unittest");
|
|
||||||
|
|
||||||
NSS_NoDB_Init(nullptr);
|
|
||||||
NSS_SetDomesticPolicy();
|
|
||||||
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
@ -6,24 +6,11 @@
|
|||||||
|
|
||||||
#define GTEST_HAS_RTTI 0
|
#define GTEST_HAS_RTTI 0
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "gtest_utils.h"
|
|
||||||
|
|
||||||
// Magic linker includes :(
|
|
||||||
#include "FakeMediaStreams.h"
|
|
||||||
#include "FakeMediaStreamsImpl.h"
|
|
||||||
#include "FakeLogging.h"
|
|
||||||
|
|
||||||
#include "signaling/src/jsep/JsepTrack.h"
|
#include "signaling/src/jsep/JsepTrack.h"
|
||||||
#include "signaling/src/sdp/SipccSdp.h"
|
#include "signaling/src/sdp/SipccSdp.h"
|
||||||
#include "signaling/src/sdp/SdpHelper.h"
|
#include "signaling/src/sdp/SdpHelper.h"
|
||||||
|
|
||||||
#include "mtransport_test_utils.h"
|
|
||||||
|
|
||||||
#include "FakeIPC.h"
|
|
||||||
#include "FakeIPC.cpp"
|
|
||||||
|
|
||||||
#include "TestHarness.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class JsepTrackTest : public ::testing::Test
|
class JsepTrackTest : public ::testing::Test
|
||||||
@ -1256,14 +1243,3 @@ TEST_F(JsepTrackTest, NonDefaultOpusParameters)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
// Prevents some log spew
|
|
||||||
ScopedXPCOM xpcom("jsep_track_unittest");
|
|
||||||
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
|
|
@ -17,6 +17,8 @@ if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk' and
|
|||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
'jsep_session_unittest.cpp',
|
||||||
|
'jsep_track_unittest.cpp',
|
||||||
'sdp_unittests.cpp',
|
'sdp_unittests.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
# TODO: bug 1172551 - get these tests working on iOS
|
# TODO: bug 1172551 - get these tests working on iOS
|
||||||
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit':
|
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'uikit':
|
||||||
GeckoCppUnitTests([
|
GeckoCppUnitTests([
|
||||||
'jsep_session_unittest',
|
|
||||||
'jsep_track_unittest',
|
|
||||||
'mediaconduit_unittests',
|
'mediaconduit_unittests',
|
||||||
'mediapipeline_unittest',
|
'mediapipeline_unittest',
|
||||||
'signaling_unittests',
|
'signaling_unittests',
|
||||||
|
@ -13,7 +13,7 @@ import org.mozilla.gecko.media.Sample;
|
|||||||
|
|
||||||
interface ICodec {
|
interface ICodec {
|
||||||
void setCallbacks(in ICodecCallbacks callbacks);
|
void setCallbacks(in ICodecCallbacks callbacks);
|
||||||
boolean configure(in FormatParam format, inout Surface surface, int flags);
|
boolean configure(in FormatParam format, inout Surface surface, int flags, in String drmStubId);
|
||||||
oneway void start();
|
oneway void start();
|
||||||
oneway void stop();
|
oneway void stop();
|
||||||
oneway void flush();
|
oneway void flush();
|
||||||
|
@ -200,7 +200,7 @@ public class HomeAdapter extends FragmentStatePagerAdapter {
|
|||||||
|
|
||||||
// Override top_sites with ActivityStream panel when enabled
|
// Override top_sites with ActivityStream panel when enabled
|
||||||
// PanelType.toString() returns the panel id
|
// PanelType.toString() returns the panel id
|
||||||
if (type.toString() == "top_sites" &&
|
if ("top_sites".equals(type.toString()) &&
|
||||||
ActivityStream.isEnabled(context) &&
|
ActivityStream.isEnabled(context) &&
|
||||||
ActivityStream.isHomePanel()) {
|
ActivityStream.isHomePanel()) {
|
||||||
return ActivityStreamHomeFragment.class.getName();
|
return ActivityStreamHomeFragment.class.getName();
|
||||||
|
@ -126,9 +126,10 @@ public class JavaAddonManagerV1 implements NativeEventListener {
|
|||||||
if (dispatcher == null) {
|
if (dispatcher == null) {
|
||||||
Log.w(LOGTAG, "Attempting to unload addon with unknown associated dispatcher; ignoring.");
|
Log.w(LOGTAG, "Attempting to unload addon with unknown associated dispatcher; ignoring.");
|
||||||
callback.sendSuccess(false);
|
callback.sendSuccess(false);
|
||||||
|
} else {
|
||||||
|
dispatcher.unregisterAllEventListeners();
|
||||||
|
callback.sendSuccess(true);
|
||||||
}
|
}
|
||||||
dispatcher.unregisterAllEventListeners();
|
|
||||||
callback.sendSuccess(true);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
package org.mozilla.gecko.media;
|
package org.mozilla.gecko.media;
|
||||||
|
|
||||||
import android.media.MediaCodec.BufferInfo;
|
import android.media.MediaCodec.BufferInfo;
|
||||||
|
import android.media.MediaCodec.CryptoInfo;
|
||||||
|
import android.media.MediaCrypto;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@ -22,7 +24,7 @@ public interface AsyncCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract void setCallbacks(Callbacks callbacks, Handler handler);
|
public abstract void setCallbacks(Callbacks callbacks, Handler handler);
|
||||||
public abstract void configure(MediaFormat format, Surface surface, int flags);
|
public abstract void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags);
|
||||||
public abstract void start();
|
public abstract void start();
|
||||||
public abstract void stop();
|
public abstract void stop();
|
||||||
public abstract void flush();
|
public abstract void flush();
|
||||||
@ -30,5 +32,6 @@ public interface AsyncCodec {
|
|||||||
public abstract ByteBuffer getInputBuffer(int index);
|
public abstract ByteBuffer getInputBuffer(int index);
|
||||||
public abstract ByteBuffer getOutputBuffer(int index);
|
public abstract ByteBuffer getOutputBuffer(int index);
|
||||||
public abstract void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);
|
public abstract void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);
|
||||||
|
public abstract void queueSecureInputBuffer(int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
|
||||||
public abstract void releaseOutputBuffer(int index, boolean render);
|
public abstract void releaseOutputBuffer(int index, boolean render);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.media;
|
|||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.media.MediaCodecList;
|
import android.media.MediaCodecList;
|
||||||
|
import android.media.MediaCrypto;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@ -167,6 +168,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
Sample sample = mInputSamples.poll();
|
Sample sample = mInputSamples.poll();
|
||||||
long pts = sample.info.presentationTimeUs;
|
long pts = sample.info.presentationTimeUs;
|
||||||
int flags = sample.info.flags;
|
int flags = sample.info.flags;
|
||||||
|
MediaCodec.CryptoInfo cryptoInfo = sample.cryptoInfo;
|
||||||
if (!sample.isEOS() && sample.buffer != null) {
|
if (!sample.isEOS() && sample.buffer != null) {
|
||||||
len = sample.info.size;
|
len = sample.info.size;
|
||||||
ByteBuffer buf = mCodec.getInputBuffer(index);
|
ByteBuffer buf = mCodec.getInputBuffer(index);
|
||||||
@ -180,7 +182,12 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
}
|
}
|
||||||
mSamplePool.recycleInput(sample);
|
mSamplePool.recycleInput(sample);
|
||||||
}
|
}
|
||||||
mCodec.queueInputBuffer(index, 0, len, pts, flags);
|
|
||||||
|
if (cryptoInfo != null) {
|
||||||
|
mCodec.queueSecureInputBuffer(index, 0, cryptoInfo, pts, flags);
|
||||||
|
} else {
|
||||||
|
mCodec.queueInputBuffer(index, 0, len, pts, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +221,10 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean configure(FormatParam format, Surface surface, int flags) throws RemoteException {
|
public synchronized boolean configure(FormatParam format,
|
||||||
|
Surface surface,
|
||||||
|
int flags,
|
||||||
|
String drmStubId) throws RemoteException {
|
||||||
if (mCallbacks == null) {
|
if (mCallbacks == null) {
|
||||||
Log.e(LOGTAG, "FAIL: callbacks must be set before calling configure()");
|
Log.e(LOGTAG, "FAIL: callbacks must be set before calling configure()");
|
||||||
return false;
|
return false;
|
||||||
@ -236,8 +246,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
AsyncCodec codec = AsyncCodecFactory.create(codecName);
|
AsyncCodec codec = AsyncCodecFactory.create(codecName);
|
||||||
|
|
||||||
|
MediaCrypto crypto = RemoteMediaDrmBridgeStub.getMediaCrypto(drmStubId);
|
||||||
|
if (DEBUG) {
|
||||||
|
boolean hasCrypto = crypto != null;
|
||||||
|
Log.d(LOGTAG, "configure mediacodec with crypto(" + hasCrypto + ") / Id :" + drmStubId);
|
||||||
|
}
|
||||||
|
|
||||||
codec.setCallbacks(new Callbacks(mCallbacks), null);
|
codec.setCallbacks(new Callbacks(mCallbacks), null);
|
||||||
codec.configure(fmt, surface, flags);
|
codec.configure(fmt, surface, crypto, flags);
|
||||||
mCodec = codec;
|
mCodec = codec;
|
||||||
mInputProcessor = new InputProcessor();
|
mInputProcessor = new InputProcessor();
|
||||||
mSamplePool = new SamplePool(codecName);
|
mSamplePool = new SamplePool(codecName);
|
||||||
|
@ -28,6 +28,7 @@ public final class CodecProxy {
|
|||||||
private FormatParam mFormat;
|
private FormatParam mFormat;
|
||||||
private Surface mOutputSurface;
|
private Surface mOutputSurface;
|
||||||
private CallbacksForwarder mCallbacks;
|
private CallbacksForwarder mCallbacks;
|
||||||
|
private String mRemoteDrmStubId;
|
||||||
|
|
||||||
public interface Callbacks {
|
public interface Callbacks {
|
||||||
void onInputExhausted();
|
void onInputExhausted();
|
||||||
@ -82,24 +83,31 @@ public final class CodecProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI
|
@WrapForJNI
|
||||||
public static CodecProxy create(MediaFormat format, Surface surface, Callbacks callbacks) {
|
public static CodecProxy create(MediaFormat format,
|
||||||
return RemoteManager.getInstance().createCodec(format, surface, callbacks);
|
Surface surface,
|
||||||
|
Callbacks callbacks,
|
||||||
|
String drmStubId) {
|
||||||
|
return RemoteManager.getInstance().createCodec(format, surface, callbacks, drmStubId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CodecProxy createCodecProxy(MediaFormat format, Surface surface, Callbacks callbacks) {
|
public static CodecProxy createCodecProxy(MediaFormat format,
|
||||||
return new CodecProxy(format, surface, callbacks);
|
Surface surface,
|
||||||
|
Callbacks callbacks,
|
||||||
|
String drmStubId) {
|
||||||
|
return new CodecProxy(format, surface, callbacks, drmStubId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodecProxy(MediaFormat format, Surface surface, Callbacks callbacks) {
|
private CodecProxy(MediaFormat format, Surface surface, Callbacks callbacks, String drmStubId) {
|
||||||
mFormat = new FormatParam(format);
|
mFormat = new FormatParam(format);
|
||||||
mOutputSurface = surface;
|
mOutputSurface = surface;
|
||||||
|
mRemoteDrmStubId = drmStubId;
|
||||||
mCallbacks = new CallbacksForwarder(callbacks);
|
mCallbacks = new CallbacksForwarder(callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean init(ICodec remote) {
|
boolean init(ICodec remote) {
|
||||||
try {
|
try {
|
||||||
remote.setCallbacks(mCallbacks);
|
remote.setCallbacks(mCallbacks);
|
||||||
remote.configure(mFormat, mOutputSurface, 0);
|
remote.configure(mFormat, mOutputSurface, 0, mRemoteDrmStubId);
|
||||||
remote.start();
|
remote.start();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -128,7 +136,6 @@ public final class CodecProxy {
|
|||||||
Log.e(LOGTAG, "cannot send input to an ended codec");
|
Log.e(LOGTAG, "cannot send input to an ended codec");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
||||||
Sample.EOS : mRemote.dequeueInput(info.size).set(bytes, info, cryptoInfo);
|
Sample.EOS : mRemote.dequeueInput(info.size).set(bytes, info, cryptoInfo);
|
||||||
|
@ -21,14 +21,16 @@ import android.annotation.SuppressLint;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
|
import android.media.DeniedByServerException;
|
||||||
import android.media.MediaCrypto;
|
import android.media.MediaCrypto;
|
||||||
import android.media.MediaCryptoException;
|
import android.media.MediaCryptoException;
|
||||||
import android.media.MediaDrm;
|
import android.media.MediaDrm;
|
||||||
import android.media.MediaDrmException;
|
import android.media.MediaDrmException;
|
||||||
|
import android.media.NotProvisionedException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||||
private static final String LOGTAG = "GeckoMediaDrmBridgeV21";
|
protected final String LOGTAG;
|
||||||
private static final String INVALID_SESSION_ID = "Invalid";
|
private static final String INVALID_SESSION_ID = "Invalid";
|
||||||
private static final String WIDEVINE_KEY_SYSTEM = "com.widevine.alpha";
|
private static final String WIDEVINE_KEY_SYSTEM = "com.widevine.alpha";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
@ -98,7 +100,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GeckoMediaDrmBridgeV21(String keySystem) throws Exception {
|
GeckoMediaDrmBridgeV21(String keySystem) throws Exception {
|
||||||
if (DEBUG) Log.d(LOGTAG, "GeckoMediaDrmBridgeV21()");
|
LOGTAG = getClass().getSimpleName();
|
||||||
|
if (DEBUG) Log.d(LOGTAG, "GeckoMediaDrmBridgeV21 ctor");
|
||||||
|
|
||||||
mProvisioningPromiseId = 0;
|
mProvisioningPromiseId = 0;
|
||||||
mSessionIds = new HashSet<ByteBuffer>();
|
mSessionIds = new HashSet<ByteBuffer>();
|
||||||
@ -142,7 +145,6 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer sessionId = null;
|
ByteBuffer sessionId = null;
|
||||||
String strSessionId = null;
|
|
||||||
try {
|
try {
|
||||||
boolean hasMediaCrypto = ensureMediaCryptoCreated();
|
boolean hasMediaCrypto = ensureMediaCryptoCreated();
|
||||||
if (!hasMediaCrypto) {
|
if (!hasMediaCrypto) {
|
||||||
@ -170,9 +172,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
LICENSE_REQUEST_INITIAL,
|
LICENSE_REQUEST_INITIAL,
|
||||||
request.getData());
|
request.getData());
|
||||||
mSessionMIMETypes.put(sessionId, initDataType);
|
mSessionMIMETypes.put(sessionId, initDataType);
|
||||||
strSessionId = new String(sessionId.array());
|
|
||||||
mSessionIds.add(sessionId);
|
mSessionIds.add(sessionId);
|
||||||
if (DEBUG) Log.d(LOGTAG, " StringID : " + strSessionId + " is put into mSessionIds ");
|
if (DEBUG) Log.d(LOGTAG, " StringID : " + new String(sessionId.array()) + " is put into mSessionIds ");
|
||||||
} catch (android.media.NotProvisionedException e) {
|
} catch (android.media.NotProvisionedException e) {
|
||||||
if (DEBUG) Log.d(LOGTAG, "Device not provisioned:" + e.getMessage());
|
if (DEBUG) Log.d(LOGTAG, "Device not provisioned:" + e.getMessage());
|
||||||
if (sessionId != null) {
|
if (sessionId != null) {
|
||||||
@ -218,18 +219,10 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
if (DEBUG) Log.d(LOGTAG, "Key successfully added for session " + sessionId);
|
if (DEBUG) Log.d(LOGTAG, "Key successfully added for session " + sessionId);
|
||||||
onSessionUpdated(promiseId, session.array());
|
onSessionUpdated(promiseId, session.array());
|
||||||
return;
|
return;
|
||||||
} catch (android.media.NotProvisionedException e) {
|
} catch (final NotProvisionedException | DeniedByServerException | IllegalStateException e) {
|
||||||
if (DEBUG) Log.d(LOGTAG, "Failed to provide key response:" + e.getMessage());
|
if (DEBUG) Log.d(LOGTAG, "Failed to provide key response:", e);
|
||||||
onSessionError(session.array(), "Got NotProvisionedException.");
|
onSessionError(session.array(), "Got exception during updateSession.");
|
||||||
onRejectPromise(promiseId, "Not provisioned during updateSession.");
|
onRejectPromise(promiseId, "Got exception during updateSession.");
|
||||||
} catch (android.media.DeniedByServerException e) {
|
|
||||||
if (DEBUG) Log.d(LOGTAG, "Failed to provide key response:" + e.getMessage());
|
|
||||||
onSessionError(session.array(), "Got DeniedByServerException.");
|
|
||||||
onRejectPromise(promiseId, "Denied by server during updateSession.");
|
|
||||||
} catch (java.lang.IllegalStateException e) {
|
|
||||||
if (DEBUG) Log.d(LOGTAG, "Exception when calling provideKeyResponse():" + e.getMessage());
|
|
||||||
onSessionError(session.array(), "Got IllegalStateException.");
|
|
||||||
onRejectPromise(promiseId, "Rejected during updateSession.");
|
|
||||||
}
|
}
|
||||||
release();
|
release();
|
||||||
return;
|
return;
|
||||||
@ -371,7 +364,6 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
}
|
}
|
||||||
// On L, these events are treated as exceptions and handled correspondingly.
|
// On L, these events are treated as exceptions and handled correspondingly.
|
||||||
// Leaving this code block for logging message.
|
// Leaving this code block for logging message.
|
||||||
String sessionId = new String(session.array());
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case MediaDrm.EVENT_PROVISION_REQUIRED:
|
case MediaDrm.EVENT_PROVISION_REQUIRED:
|
||||||
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_PROVISION_REQUIRED");
|
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_PROVISION_REQUIRED");
|
||||||
@ -381,10 +373,10 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
// No need to handle here if we're not in privacy mode.
|
// No need to handle here if we're not in privacy mode.
|
||||||
break;
|
break;
|
||||||
case MediaDrm.EVENT_KEY_EXPIRED:
|
case MediaDrm.EVENT_KEY_EXPIRED:
|
||||||
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_KEY_EXPIRED, sessionId=" + sessionId);
|
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_KEY_EXPIRED, sessionId=" + new String(session.array()));
|
||||||
break;
|
break;
|
||||||
case MediaDrm.EVENT_VENDOR_DEFINED:
|
case MediaDrm.EVENT_VENDOR_DEFINED:
|
||||||
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_VENDOR_DEFINED, sessionId=" + sessionId);
|
if (DEBUG) Log.d(LOGTAG, "MediaDrm.EVENT_VENDOR_DEFINED, sessionId=" + new String(session.array()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (DEBUG) Log.d(LOGTAG, "Invalid DRM event " + event);
|
if (DEBUG) Log.d(LOGTAG, "Invalid DRM event " + event);
|
||||||
@ -414,7 +406,7 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sessionExists(ByteBuffer session) {
|
protected boolean sessionExists(ByteBuffer session) {
|
||||||
if (mCryptoSessionId == null) {
|
if (mCryptoSessionId == null) {
|
||||||
if (DEBUG) Log.d(LOGTAG, "Session doesn't exist because media crypto session is not created.");
|
if (DEBUG) Log.d(LOGTAG, "Session doesn't exist because media crypto session is not created.");
|
||||||
return false;
|
return false;
|
||||||
@ -592,9 +584,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
|||||||
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
|
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
|
||||||
final byte [] cryptoSessionId = mCryptoSessionId.array();
|
final byte [] cryptoSessionId = mCryptoSessionId.array();
|
||||||
mCrypto = new MediaCrypto(mSchemeUUID, cryptoSessionId);
|
mCrypto = new MediaCrypto(mSchemeUUID, cryptoSessionId);
|
||||||
String strCryptoSessionId = new String(cryptoSessionId);
|
|
||||||
mSessionIds.add(mCryptoSessionId);
|
mSessionIds.add(mCryptoSessionId);
|
||||||
if (DEBUG) Log.d(LOGTAG, "MediaCrypto successfully created! - SId " + INVALID_SESSION_ID + ", " + strCryptoSessionId);
|
if (DEBUG) Log.d(LOGTAG, "MediaCrypto successfully created! - SId " + INVALID_SESSION_ID + ", " + new String(cryptoSessionId));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) Log.d(LOGTAG, "Cannot create MediaCrypto for unsupported scheme.");
|
if (DEBUG) Log.d(LOGTAG, "Cannot create MediaCrypto for unsupported scheme.");
|
||||||
|
@ -5,14 +5,18 @@
|
|||||||
package org.mozilla.gecko.media;
|
package org.mozilla.gecko.media;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.media.DeniedByServerException;
|
||||||
|
import android.media.NotProvisionedException;
|
||||||
|
|
||||||
import static android.os.Build.VERSION_CODES.M;
|
import static android.os.Build.VERSION_CODES.M;
|
||||||
import android.media.MediaDrm;
|
import android.media.MediaDrm;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import java.lang.IllegalStateException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GeckoMediaDrmBridgeV23 extends GeckoMediaDrmBridgeV21 {
|
public class GeckoMediaDrmBridgeV23 extends GeckoMediaDrmBridgeV21 {
|
||||||
|
|
||||||
private static final String LOGTAG = "GeckoMediaDrmBridgeV23";
|
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
GeckoMediaDrmBridgeV23(String keySystem) throws Exception {
|
GeckoMediaDrmBridgeV23(String keySystem) throws Exception {
|
||||||
@ -39,6 +43,43 @@ public class GeckoMediaDrmBridgeV23 extends GeckoMediaDrmBridgeV21 {
|
|||||||
keyStatus.getStatusCode());
|
keyStatus.getStatusCode());
|
||||||
}
|
}
|
||||||
onSessionBatchedKeyChanged(sessionId, keyInfos);
|
onSessionBatchedKeyChanged(sessionId, keyInfos);
|
||||||
|
if (DEBUG) Log.d(LOGTAG, "Key successfully added for session " + new String(sessionId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSession(int promiseId,
|
||||||
|
String sessionId,
|
||||||
|
byte[] response) {
|
||||||
|
if (DEBUG) Log.d(LOGTAG, "updateSession(), sessionId = " + sessionId);
|
||||||
|
if (mDrm == null) {
|
||||||
|
onRejectPromise(promiseId, "MediaDrm instance doesn't exist !!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer session = ByteBuffer.wrap(sessionId.getBytes());
|
||||||
|
if (!sessionExists(session)) {
|
||||||
|
onRejectPromise(promiseId, "Invalid session during updateSession.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final byte [] keySetId = mDrm.provideKeyResponse(session.array(), response);
|
||||||
|
if (DEBUG) {
|
||||||
|
HashMap<String, String> infoMap = mDrm.queryKeyStatus(session.array());
|
||||||
|
for (String strKey : infoMap.keySet()) {
|
||||||
|
String strValue = infoMap.get(strKey);
|
||||||
|
Log.d(LOGTAG, "InfoMap : key(" + strKey + ")/value(" + strValue + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSessionUpdated(promiseId, session.array());
|
||||||
|
return;
|
||||||
|
} catch (final NotProvisionedException | DeniedByServerException | IllegalStateException e) {
|
||||||
|
if (DEBUG) Log.d(LOGTAG, "Failed to provide key response:", e);
|
||||||
|
onSessionError(session.array(), "Got exception during updateSession.");
|
||||||
|
onRejectPromise(promiseId, "Got exception during updateSession.");
|
||||||
|
}
|
||||||
|
release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package org.mozilla.gecko.media;
|
package org.mozilla.gecko.media;
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
|
import android.media.MediaCrypto;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
@ -294,10 +295,10 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(MediaFormat format, Surface surface, int flags) {
|
public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags) {
|
||||||
assertCallbacks();
|
assertCallbacks();
|
||||||
|
|
||||||
mCodec.configure(format, surface, null, flags);
|
mCodec.configure(format, surface, crypto, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertCallbacks() {
|
private void assertCallbacks() {
|
||||||
@ -336,6 +337,28 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
|
|||||||
mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_OUTPUT_BUFFERS);
|
mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_OUTPUT_BUFFERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void queueSecureInputBuffer(int index,
|
||||||
|
int offset,
|
||||||
|
MediaCodec.CryptoInfo cryptoInfo,
|
||||||
|
long presentationTimeUs,
|
||||||
|
int flags) {
|
||||||
|
assertCallbacks();
|
||||||
|
|
||||||
|
mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
mCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, flags);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mCallbackSender.notifyError(ERROR_CODEC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS);
|
||||||
|
mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_OUTPUT_BUFFERS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void releaseOutputBuffer(int index, boolean render) {
|
public final void releaseOutputBuffer(int index, boolean render) {
|
||||||
assertCallbacks();
|
assertCallbacks();
|
||||||
|
@ -39,10 +39,12 @@ public final class MediaDrmProxy {
|
|||||||
@WrapForJNI
|
@WrapForJNI
|
||||||
private static final String OPUS = "audio/opus";
|
private static final String OPUS = "audio/opus";
|
||||||
|
|
||||||
|
public static ArrayList<MediaDrmProxy> sProxyList = new ArrayList<MediaDrmProxy>();
|
||||||
|
|
||||||
// A flag to avoid using the native object that has been destroyed.
|
// A flag to avoid using the native object that has been destroyed.
|
||||||
private boolean mDestroyed;
|
private boolean mDestroyed;
|
||||||
private GeckoMediaDrm mImpl;
|
private GeckoMediaDrm mImpl;
|
||||||
public static ArrayList<MediaDrmProxy> mProxyList = new ArrayList<MediaDrmProxy>();
|
private String mDrmStubId;
|
||||||
|
|
||||||
private static boolean isSystemSupported() {
|
private static boolean isSystemSupported() {
|
||||||
// Support versions >= LOLLIPOP
|
// Support versions >= LOLLIPOP
|
||||||
@ -250,19 +252,26 @@ public final class MediaDrmProxy {
|
|||||||
public static MediaDrmProxy create(String keySystem,
|
public static MediaDrmProxy create(String keySystem,
|
||||||
Callbacks nativeCallbacks,
|
Callbacks nativeCallbacks,
|
||||||
boolean isRemote) {
|
boolean isRemote) {
|
||||||
// TODO: Will implement {Local,Remote}MediaDrmBridge instantiation by
|
MediaDrmProxy proxy = new MediaDrmProxy(keySystem, nativeCallbacks, isRemote);
|
||||||
// '''isRemote''' flag in Bug 1307818.
|
|
||||||
MediaDrmProxy proxy = new MediaDrmProxy(keySystem, nativeCallbacks);
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDrmProxy(String keySystem, Callbacks nativeCallbacks) {
|
MediaDrmProxy(String keySystem, Callbacks nativeCallbacks, boolean isRemote) {
|
||||||
if (DEBUG) Log.d(LOGTAG, "Constructing MediaDrmProxy");
|
if (DEBUG) Log.d(LOGTAG, "Constructing MediaDrmProxy");
|
||||||
// TODO: Bug 1306185 will implement the LocalMediaDrmBridge as an impl
|
try {
|
||||||
// of GeckoMediaDrm for in-process decoding mode.
|
mDrmStubId = UUID.randomUUID().toString();
|
||||||
//mImpl = new LocalMediaDrmBridge(keySystem);
|
if (isRemote) {
|
||||||
mImpl.setCallbacks(new MediaDrmProxyCallbacks(this, nativeCallbacks));
|
IMediaDrmBridge remoteBridge =
|
||||||
mProxyList.add(this);
|
RemoteManager.getInstance().createRemoteMediaDrmBridge(keySystem, mDrmStubId);
|
||||||
|
mImpl = new RemoteMediaDrmBridge(remoteBridge);
|
||||||
|
} else {
|
||||||
|
mImpl = new LocalMediaDrmBridge(keySystem);
|
||||||
|
}
|
||||||
|
mImpl.setCallbacks(new MediaDrmProxyCallbacks(this, nativeCallbacks));
|
||||||
|
sProxyList.add(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOGTAG, "Constructing MediaDrmProxy ... error", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI
|
@WrapForJNI
|
||||||
@ -289,6 +298,24 @@ public final class MediaDrmProxy {
|
|||||||
mImpl.closeSession(promiseId, sessionId);
|
mImpl.closeSession(promiseId, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WrapForJNI(calledFrom = "gecko")
|
||||||
|
private String getStubId() {
|
||||||
|
return mDrmStubId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get corresponding MediaCrypto object by a generated UUID for MediaCodec.
|
||||||
|
// Will be called on MediaFormatReader's TaskQueue.
|
||||||
|
@WrapForJNI
|
||||||
|
public static MediaCrypto getMediaCrypto(String stubId) {
|
||||||
|
for (MediaDrmProxy proxy : sProxyList) {
|
||||||
|
if (proxy.getStubId().equals(stubId)) {
|
||||||
|
return proxy.getMediaCryptoFromBridge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DEBUG) Log.d(LOGTAG, " NULL crytpo ");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@WrapForJNI // Called when natvie object is destroyed.
|
@WrapForJNI // Called when natvie object is destroyed.
|
||||||
private void destroy() {
|
private void destroy() {
|
||||||
if (DEBUG) Log.d(LOGTAG, "destroy!! Native object is destroyed.");
|
if (DEBUG) Log.d(LOGTAG, "destroy!! Native object is destroyed.");
|
||||||
@ -301,7 +328,11 @@ public final class MediaDrmProxy {
|
|||||||
|
|
||||||
private void release() {
|
private void release() {
|
||||||
if (DEBUG) Log.d(LOGTAG, "release");
|
if (DEBUG) Log.d(LOGTAG, "release");
|
||||||
mProxyList.remove(this);
|
sProxyList.remove(this);
|
||||||
mImpl.release();
|
mImpl.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MediaCrypto getMediaCryptoFromBridge() {
|
||||||
|
return mImpl != null ? mImpl.getMediaCrypto() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,14 +120,15 @@ public final class RemoteManager implements IBinder.DeathRecipient {
|
|||||||
|
|
||||||
public synchronized CodecProxy createCodec(MediaFormat format,
|
public synchronized CodecProxy createCodec(MediaFormat format,
|
||||||
Surface surface,
|
Surface surface,
|
||||||
CodecProxy.Callbacks callbacks) {
|
CodecProxy.Callbacks callbacks,
|
||||||
|
String drmStubId) {
|
||||||
if (mRemote == null) {
|
if (mRemote == null) {
|
||||||
if (DEBUG) Log.d(LOGTAG, "createCodec failed due to not initialize");
|
if (DEBUG) Log.d(LOGTAG, "createCodec failed due to not initialize");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ICodec remote = mRemote.createCodec();
|
ICodec remote = mRemote.createCodec();
|
||||||
CodecProxy proxy = CodecProxy.createCodecProxy(format, surface, callbacks);
|
CodecProxy proxy = CodecProxy.createCodecProxy(format, surface, callbacks, drmStubId);
|
||||||
if (proxy.init(remote)) {
|
if (proxy.init(remote)) {
|
||||||
mProxies.add(proxy);
|
mProxies.add(proxy);
|
||||||
return proxy;
|
return proxy;
|
||||||
|
@ -892,10 +892,15 @@ var BrowserApp = {
|
|||||||
NativeWindow.contextmenus.add(
|
NativeWindow.contextmenus.add(
|
||||||
function(aTarget) {
|
function(aTarget) {
|
||||||
if (aTarget instanceof HTMLVideoElement) {
|
if (aTarget instanceof HTMLVideoElement) {
|
||||||
// If a video element is zero width or height, its essentially
|
if (aTarget.readyState == aTarget.HAVE_NOTHING) {
|
||||||
// an HTMLAudioElement.
|
// We don't know if the height/width of the video,
|
||||||
if (aTarget.videoWidth == 0 || aTarget.videoHeight == 0 )
|
// show a generic string.
|
||||||
|
return Strings.browser.GetStringFromName("contextmenu.saveMedia");
|
||||||
|
} else if (aTarget.videoWidth == 0 || aTarget.videoHeight == 0) {
|
||||||
|
// If a video element is zero width or height, its essentially
|
||||||
|
// an HTMLAudioElement.
|
||||||
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
||||||
|
}
|
||||||
return Strings.browser.GetStringFromName("contextmenu.saveVideo");
|
return Strings.browser.GetStringFromName("contextmenu.saveVideo");
|
||||||
} else if (aTarget instanceof HTMLAudioElement) {
|
} else if (aTarget instanceof HTMLAudioElement) {
|
||||||
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
||||||
@ -907,9 +912,19 @@ var BrowserApp = {
|
|||||||
UITelemetry.addEvent("save.1", "contextmenu", null, "media");
|
UITelemetry.addEvent("save.1", "contextmenu", null, "media");
|
||||||
|
|
||||||
let url = aTarget.currentSrc || aTarget.src;
|
let url = aTarget.currentSrc || aTarget.src;
|
||||||
let filePickerTitleKey = (aTarget instanceof HTMLVideoElement &&
|
|
||||||
(aTarget.videoWidth != 0 && aTarget.videoHeight != 0))
|
let filePickerTitleKey;
|
||||||
? "SaveVideoTitle" : "SaveAudioTitle";
|
if (aTarget instanceof HTMLVideoElement) {
|
||||||
|
if (aTarget.readyState == aTarget.HAVE_NOTHING) {
|
||||||
|
filePickerTitleKey = "SaveMediaTitle";
|
||||||
|
} else if (aTarget.videoWidth == 0 || aTarget.videoHeight == 0) {
|
||||||
|
filePickerTitleKey = "SaveAudioTitle";
|
||||||
|
}
|
||||||
|
filePickerTitleKey = "SaveVideoTitle";
|
||||||
|
} else {
|
||||||
|
filePickerTitleKey = "SaveAudioTitle";
|
||||||
|
}
|
||||||
|
|
||||||
// Skipped trying to pull MIME type out of cache for now
|
// Skipped trying to pull MIME type out of cache for now
|
||||||
ContentAreaUtils.internalSave(url, null, null, null, null, false,
|
ContentAreaUtils.internalSave(url, null, null, null, null, false,
|
||||||
filePickerTitleKey, null, aTarget.ownerDocument.documentURIObject,
|
filePickerTitleKey, null, aTarget.ownerDocument.documentURIObject,
|
||||||
|
@ -279,6 +279,10 @@ contextmenu.mute=Mute
|
|||||||
contextmenu.unmute=Unmute
|
contextmenu.unmute=Unmute
|
||||||
contextmenu.saveVideo=Save Video
|
contextmenu.saveVideo=Save Video
|
||||||
contextmenu.saveAudio=Save Audio
|
contextmenu.saveAudio=Save Audio
|
||||||
|
# LOCALIZATION NOTE (contextmenu.saveMedia):
|
||||||
|
# The label that will be used in the contextmenu in place of "Save Video" or "Save Audio", for
|
||||||
|
# unloaded video elements.
|
||||||
|
contextmenu.saveMedia=Save Media
|
||||||
contextmenu.addToContacts=Add to Contacts
|
contextmenu.addToContacts=Add to Contacts
|
||||||
# LOCALIZATION NOTE (contextmenu.sendToDevice):
|
# LOCALIZATION NOTE (contextmenu.sendToDevice):
|
||||||
# The label that will be used in the contextmenu and the pageaction
|
# The label that will be used in the contextmenu and the pageaction
|
||||||
|
@ -61,7 +61,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#filter-input::placeholder {
|
#filter-input::placeholder {
|
||||||
color: rgba(255,255,255,0.5);
|
color: #777777;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar input {
|
.toolbar input {
|
||||||
|
@ -1111,10 +1111,7 @@ pref("print.print_edge_right", 0);
|
|||||||
pref("print.print_edge_bottom", 0);
|
pref("print.print_edge_bottom", 0);
|
||||||
|
|
||||||
// Print via the parent process. This is only used when e10s is enabled.
|
// Print via the parent process. This is only used when e10s is enabled.
|
||||||
// For Mac, limit to Nightly.
|
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||||
#if defined(XP_WIN)
|
|
||||||
pref("print.print_via_parent", true);
|
|
||||||
#elif defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
|
|
||||||
pref("print.print_via_parent", true);
|
pref("print.print_via_parent", true);
|
||||||
#else
|
#else
|
||||||
pref("print.print_via_parent", false);
|
pref("print.print_via_parent", false);
|
||||||
|
@ -1535,10 +1535,6 @@ VARIABLES = {
|
|||||||
"""List of manifest files defining marionette-unit tests.
|
"""List of manifest files defining marionette-unit tests.
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
'MARIONETTE_UPDATE_MANIFESTS': (ManifestparserManifestList, list,
|
|
||||||
"""List of manifest files defining marionette-update tests.
|
|
||||||
"""),
|
|
||||||
|
|
||||||
'MARIONETTE_WEBAPI_MANIFESTS': (ManifestparserManifestList, list,
|
'MARIONETTE_WEBAPI_MANIFESTS': (ManifestparserManifestList, list,
|
||||||
"""List of manifest files defining marionette-webapi tests.
|
"""List of manifest files defining marionette-webapi tests.
|
||||||
"""),
|
"""),
|
||||||
|
@ -135,8 +135,6 @@ ALLOWED_XPCOM_GLUE = {
|
|||||||
('test_unlock_notify', 'storage/test'),
|
('test_unlock_notify', 'storage/test'),
|
||||||
('test_IHistory', 'toolkit/components/places/tests/cpp'),
|
('test_IHistory', 'toolkit/components/places/tests/cpp'),
|
||||||
('testcrasher', 'toolkit/crashreporter/test'),
|
('testcrasher', 'toolkit/crashreporter/test'),
|
||||||
('jsep_session_unittest', 'media/webrtc/signaling/test'),
|
|
||||||
('jsep_track_unittest', 'media/webrtc/signaling/test'),
|
|
||||||
('mediaconduit_unittests', 'media/webrtc/signaling/test'),
|
('mediaconduit_unittests', 'media/webrtc/signaling/test'),
|
||||||
('mediapipeline_unittest', 'media/webrtc/signaling/test'),
|
('mediapipeline_unittest', 'media/webrtc/signaling/test'),
|
||||||
('sdp_file_parser', 'media/webrtc/signaling/fuzztest'),
|
('sdp_file_parser', 'media/webrtc/signaling/fuzztest'),
|
||||||
|
@ -287,7 +287,6 @@ TEST_MANIFESTS = dict(
|
|||||||
# TODO(ato): make packaging work as for other test suites
|
# TODO(ato): make packaging work as for other test suites
|
||||||
MARIONETTE=('marionette', 'marionette', '.', False),
|
MARIONETTE=('marionette', 'marionette', '.', False),
|
||||||
MARIONETTE_UNIT=('marionette', 'marionette', '.', False),
|
MARIONETTE_UNIT=('marionette', 'marionette', '.', False),
|
||||||
MARIONETTE_UPDATE=('marionette', 'marionette', '.', False),
|
|
||||||
MARIONETTE_WEBAPI=('marionette', 'marionette', '.', False),
|
MARIONETTE_WEBAPI=('marionette', 'marionette', '.', False),
|
||||||
|
|
||||||
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
|
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
|
||||||
|
@ -22,6 +22,7 @@ import struct
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import buildconfig
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
# Regular expressions for unifying install.rdf
|
# Regular expressions for unifying install.rdf
|
||||||
@ -80,7 +81,8 @@ class UnifiedExecutableFile(BaseFile):
|
|||||||
os.close(fd)
|
os.close(fd)
|
||||||
tmpfiles.append(f)
|
tmpfiles.append(f)
|
||||||
e.copy(f, skip_if_older=False)
|
e.copy(f, skip_if_older=False)
|
||||||
subprocess.call(['lipo', '-create'] + tmpfiles + ['-output', dest])
|
lipo = buildconfig.substs.get('LIPO') or 'lipo'
|
||||||
|
subprocess.call([lipo, '-create'] + tmpfiles + ['-output', dest])
|
||||||
finally:
|
finally:
|
||||||
for f in tmpfiles:
|
for f in tmpfiles:
|
||||||
os.unlink(f)
|
os.unlink(f)
|
||||||
|
@ -44,3 +44,27 @@ macosx64/opt:
|
|||||||
script: "mozharness/scripts/fx_desktop_build.py"
|
script: "mozharness/scripts/fx_desktop_build.py"
|
||||||
secrets: true
|
secrets: true
|
||||||
tooltool-downloads: internal
|
tooltool-downloads: internal
|
||||||
|
|
||||||
|
macosx64-universal/opt:
|
||||||
|
description: "MacOS X Universal Cross-compile"
|
||||||
|
index:
|
||||||
|
product: firefox
|
||||||
|
job-name: macosx64-opt
|
||||||
|
treeherder:
|
||||||
|
platform: osx-10-7/opt
|
||||||
|
symbol: tc(Bu)
|
||||||
|
tier: 2
|
||||||
|
worker-type: aws-provisioner-v1/gecko-{level}-b-macosx64
|
||||||
|
worker:
|
||||||
|
implementation: docker-worker
|
||||||
|
max-run-time: 36000
|
||||||
|
run:
|
||||||
|
using: mozharness
|
||||||
|
actions: [get-secrets build generate-build-stats update]
|
||||||
|
config:
|
||||||
|
- builds/releng_base_mac_64_cross_builds.py
|
||||||
|
- balrog/production.py
|
||||||
|
script: "mozharness/scripts/fx_desktop_build.py"
|
||||||
|
secrets: true
|
||||||
|
custom-build-variant-cfg: cross-universal
|
||||||
|
tooltool-downloads: internal
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user