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>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
&aboutPrivateBrowsing.note.before;
|
||||
<strong>&aboutPrivateBrowsing.note.emphasize;</strong>
|
||||
&aboutPrivateBrowsing.note.after;
|
||||
</p>
|
||||
<p>&aboutPrivateBrowsing.note.before;<strong>&aboutPrivateBrowsing.note.emphasize;</strong>&aboutPrivateBrowsing.note.after;</p>
|
||||
</section>
|
||||
|
||||
<h2 id="tpSubHeader" class="about-subheader">
|
||||
@ -75,9 +71,7 @@
|
||||
</section>
|
||||
|
||||
<section class="section-main">
|
||||
<p class="about-info">&aboutPrivateBrowsing.learnMore2;
|
||||
<a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore2.title;</a>.
|
||||
</p>
|
||||
<p class="about-info">&aboutPrivateBrowsing.learnMore3.before;<a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore3.title;</a>&aboutPrivateBrowsing.learnMore3.after;</p>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
@ -4,7 +4,11 @@ ac_add_options --disable-install-strip
|
||||
ac_add_options --enable-verify-mar
|
||||
ac_add_options --enable-profiling
|
||||
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
|
||||
ac_add_options --with-macbundlename-prefix=Firefox
|
||||
|
@ -23,8 +23,9 @@
|
||||
<!ENTITY aboutPrivateBrowsing.note.before "Private Browsing ">
|
||||
<!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.learnMore2 "Learn more about">
|
||||
<!ENTITY aboutPrivateBrowsing.learnMore2.title "Private Browsing">
|
||||
<!ENTITY aboutPrivateBrowsing.learnMore3.before "Learn more about ">
|
||||
<!ENTITY aboutPrivateBrowsing.learnMore3.title "Private Browsing">
|
||||
<!ENTITY aboutPrivateBrowsing.learnMore3.after ".">
|
||||
|
||||
<!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.">
|
||||
|
@ -132,17 +132,13 @@ PluginContent.prototype = {
|
||||
switch (aTopic) {
|
||||
case "decoder-doctor-notification":
|
||||
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 &&
|
||||
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.sendAsyncMessage("PluginContent:ShowClickToPlayNotification",
|
||||
{ plugins: [...this.pluginData.values()],
|
||||
showNow: true,
|
||||
location: location,
|
||||
}, null, principal);
|
||||
this.updateNotificationUI(this.content.document);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -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) {
|
||||
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
||||
@ -269,7 +271,11 @@ PluginContent.prototype = {
|
||||
pluginName: pluginName,
|
||||
pluginTag: pluginTag,
|
||||
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,
|
||||
};
|
||||
},
|
||||
|
@ -83,6 +83,7 @@ AC_CHECK_PROGS(RANLIB, "${TOOLCHAIN_PREFIX}ranlib", :)
|
||||
AC_CHECK_PROGS(AR, "${TOOLCHAIN_PREFIX}ar", :)
|
||||
AC_CHECK_PROGS(AS, "${TOOLCHAIN_PREFIX}as", :)
|
||||
AC_CHECK_PROGS(LD, "${TOOLCHAIN_PREFIX}ld", :)
|
||||
AC_CHECK_PROGS(LIPO, "${TOOLCHAIN_PREFIX}lipo", :)
|
||||
AC_CHECK_PROGS(STRIP, "${TOOLCHAIN_PREFIX}strip", :)
|
||||
AC_CHECK_PROGS(WINDRES, "${TOOLCHAIN_PREFIX}windres", :)
|
||||
AC_CHECK_PROGS(OTOOL, "${TOOLCHAIN_PREFIX}otool", :)
|
||||
|
@ -4,13 +4,16 @@
|
||||
|
||||
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 x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION
|
||||
ac_add_app_options i386 --with-unify-dist=../x86_64/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
|
||||
|
||||
@ -35,12 +38,12 @@ if test "$MOZ_BUILD_APP" = "i386" -o "$MOZ_BUILD_APP" = "x86_64"; then
|
||||
CXX="$CXX -arch $TARGET_CPU"
|
||||
|
||||
# These must be set for cross builds, and don't hurt straight builds.
|
||||
RANLIB=ranlib
|
||||
AR=ar
|
||||
RANLIB="${TOOLCHAIN_PREFIX}ranlib"
|
||||
AR="${TOOLCHAIN_PREFIX}ar"
|
||||
AS=$CC
|
||||
LD=ld
|
||||
STRIP="strip"
|
||||
OTOOL="otool"
|
||||
OTOOL="${TOOLCHAIN_PREFIX}otool"
|
||||
|
||||
# Each per-CPU build should be entirely oblivious to the fact that a
|
||||
# universal binary will be produced. The exception is packager.mk, which
|
||||
|
@ -726,13 +726,14 @@ gDevTools.getToolDefinitionArray()
|
||||
// and the new ones.
|
||||
gDevTools.on("tool-registered", function (ev, toolId) {
|
||||
let toolDefinition = gDevTools._tools.get(toolId);
|
||||
// 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) {
|
||||
if (typeof toolId != "string") {
|
||||
toolId = toolId.id;
|
||||
}
|
||||
gDevToolsBrowser._removeToolFromWindows(toolId);
|
||||
});
|
||||
|
||||
|
@ -140,12 +140,16 @@ DevTools.prototype = {
|
||||
tool = this._tools.get(tool);
|
||||
}
|
||||
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;
|
||||
}
|
||||
this._tools.delete(toolId);
|
||||
|
||||
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_tool_ready.js]
|
||||
[browser_toolbox_tool_remote_reopen.js]
|
||||
[browser_toolbox_tools_per_toolbox_registration.js]
|
||||
[browser_toolbox_transport_events.js]
|
||||
[browser_toolbox_view_source_01.js]
|
||||
[browser_toolbox_view_source_02.js]
|
||||
|
@ -71,9 +71,8 @@ function testUnregister()
|
||||
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");
|
||||
|
||||
ok(!gDevTools.getToolDefinitionMap().has(toolId), "tool removed from map");
|
||||
|
@ -21,6 +21,7 @@ add_task(function* () {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
toolbox = yield gDevTools.showToolbox(target);
|
||||
doc = toolbox.doc;
|
||||
yield registerNewPerToolboxTool();
|
||||
yield testSelectTool();
|
||||
yield testOptionsShortcut();
|
||||
yield testOptions();
|
||||
@ -46,6 +47,31 @@ function registerNewTool() {
|
||||
"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() {
|
||||
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])");
|
||||
let enabledTools = [...toolNodes].filter(node => node.checked);
|
||||
|
||||
let toggleableTools = gDevTools.getDefaultTools().filter(tool => {
|
||||
let toggleableTools = gDevTools.getDefaultTools()
|
||||
.filter(tool => {
|
||||
return tool.visibilityswitch;
|
||||
}).concat(gDevTools.getAdditionalTools());
|
||||
})
|
||||
.concat(gDevTools.getAdditionalTools())
|
||||
.concat(toolbox.getAdditionalTools());
|
||||
|
||||
|
||||
for (let node of toolNodes) {
|
||||
let id = node.getAttribute("id");
|
||||
@ -235,7 +265,7 @@ function* toggleTool(node) {
|
||||
}
|
||||
|
||||
function checkUnregistered(toolId, deferred, event, data) {
|
||||
if (data.id == toolId) {
|
||||
if (data == toolId) {
|
||||
ok(true, "Correct tool removed");
|
||||
// checking tab on the toolbox
|
||||
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");
|
||||
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 toolDefinition = gDevTools._tools.get(id);
|
||||
let toolDefinition = gDevTools._tools.get(id) || toolbox.getToolDefinition(id);
|
||||
// Set the kill switch pref boolean to true
|
||||
Services.prefs.setBoolPref(toolDefinition.visibilityswitch, this.checked);
|
||||
if (this.checked) {
|
||||
gDevTools.emit("tool-registered", id);
|
||||
} else {
|
||||
gDevTools.emit("tool-unregistered", toolDefinition);
|
||||
}
|
||||
gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", id);
|
||||
};
|
||||
|
||||
let createToolCheckbox = tool => {
|
||||
@ -243,6 +243,13 @@ OptionsPanel.prototype = {
|
||||
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) {
|
||||
additionalToolsBox.style.display = "none";
|
||||
}
|
||||
|
@ -895,6 +895,7 @@ Toolbox.prototype = {
|
||||
* Add tabs to the toolbox UI for registered tools
|
||||
*/
|
||||
_buildTabs: function () {
|
||||
// Build tabs for global registered tools.
|
||||
for (let definition of gDevTools.getToolDefinitionArray()) {
|
||||
this._buildTabForTool(definition);
|
||||
}
|
||||
@ -1252,6 +1253,81 @@ Toolbox.prototype = {
|
||||
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.
|
||||
*
|
||||
@ -1280,7 +1356,9 @@ Toolbox.prototype = {
|
||||
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) {
|
||||
deferred.reject(new Error("no such tool id " + id));
|
||||
return deferred.promise;
|
||||
@ -1907,41 +1985,47 @@ Toolbox.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Return if the tool is available as a tab (i.e. if it's checked
|
||||
* in the options panel). This is different from Toolbox.getPanel -
|
||||
* a tool could be registered but not yet opened in which case
|
||||
* isToolRegistered would return true but getPanel would return false.
|
||||
* Test the availability of a tool (both globally registered tools and
|
||||
* additional tools registered to this toolbox) by tool id.
|
||||
*
|
||||
* @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) {
|
||||
return gDevTools.getToolDefinitionMap().has(toolId);
|
||||
return !!this.getToolDefinition(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-registered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-registered")
|
||||
* Return the tool definition registered globally or additional tools registered
|
||||
* to this toolbox.
|
||||
*
|
||||
* @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) {
|
||||
let tool = gDevTools.getToolDefinition(toolId);
|
||||
this._buildTabForTool(tool);
|
||||
// Emit the event so tools can listen to it from the toolbox level
|
||||
// instead of gDevTools
|
||||
this.emit("tool-registered", toolId);
|
||||
getToolDefinition: function (toolId) {
|
||||
return gDevTools.getToolDefinition(toolId) ||
|
||||
this.additionalToolDefinitions.get(toolId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the tool-unregistered event.
|
||||
* @param {string} event
|
||||
* Name of the event ("tool-unregistered")
|
||||
* @param {string|object} toolId
|
||||
* Definition or id of the tool that was unregistered. Passing the
|
||||
* tool id should be avoided as it is a temporary measure.
|
||||
* Internal helper that removes a loaded tool from the toolbox,
|
||||
* it removes a loaded tool panel and tab from the toolbox without removing
|
||||
* its definition, so that it can still be listed in options and re-added later.
|
||||
*
|
||||
* @param {string} toolId
|
||||
* Id of the tool to be removed.
|
||||
*/
|
||||
_toolUnregistered: function (event, toolId) {
|
||||
unloadTool: function (toolId) {
|
||||
if (typeof toolId != "string") {
|
||||
toolId = toolId.id;
|
||||
throw new Error("Unexpected non-string toolId received.");
|
||||
}
|
||||
|
||||
if (this._toolPanels.has(toolId)) {
|
||||
@ -1980,6 +2064,38 @@ Toolbox.prototype = {
|
||||
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
|
||||
// instead of gDevTools
|
||||
this.emit("tool-unregistered", toolId);
|
||||
|
@ -4,45 +4,47 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test for as-authored styles.
|
||||
// Test for as-authored color styles.
|
||||
|
||||
function* createTestContent(style) {
|
||||
let html = `<style type="text/css">
|
||||
${style}
|
||||
</style>
|
||||
<div id="testid" class="testclass">Styled Node</div>`;
|
||||
let tab = yield addTab("data:text/html;charset=utf-8," +
|
||||
encodeURIComponent(html));
|
||||
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
return {view, tab};
|
||||
}
|
||||
/**
|
||||
* Array of test color objects:
|
||||
* {String} name: name of the used & expected color format.
|
||||
* {String} id: id of the element that will be created to test this color.
|
||||
* {String} color: initial value of the color property applied to the test element.
|
||||
* {String} result: expected value of the color property after edition.
|
||||
*/
|
||||
const colors = [
|
||||
{name: "hex", id: "test1", color: "#f0c", result: "#0f0"},
|
||||
{name: "rgb", id: "test2", color: "rgb(0,128,250)", result: "rgb(0, 255, 0)"},
|
||||
// Test case preservation.
|
||||
{name: "hex", id: "test3", color: "#F0C", result: "#0F0"},
|
||||
];
|
||||
|
||||
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");
|
||||
|
||||
for (let color of colors) {
|
||||
let {view, tab} = yield createTestContent("#testid {" +
|
||||
" color: " + color.text + ";" +
|
||||
"} ");
|
||||
let html = "";
|
||||
for (let {color, id} of colors) {
|
||||
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 swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
|
||||
let selector = "#" + color.id;
|
||||
yield selectNode(selector, inspector);
|
||||
|
||||
let swatch = getRuleViewProperty(view, "element", "color").valueSpan
|
||||
.querySelector(".ruleview-colorswatch");
|
||||
let onColorPickerReady = cPicker.once("ready");
|
||||
swatch.click();
|
||||
yield onColorPickerReady;
|
||||
|
||||
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
||||
selector: "#testid",
|
||||
selector,
|
||||
name: "color",
|
||||
value: "rgb(0, 255, 0)"
|
||||
});
|
||||
@ -55,11 +57,11 @@ add_task(function* () {
|
||||
yield onHidden;
|
||||
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);
|
||||
}
|
||||
|
||||
let target = TargetFactory.forTab(tab);
|
||||
yield gDevTools.closeToolbox(target);
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
});
|
||||
|
@ -4,11 +4,13 @@
|
||||
/* globals window, dumpn, gNetwork, $, EVENTS, NetMonitorView */
|
||||
"use strict";
|
||||
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {writeHeaderText, getKeyWithEvent} = require("./request-utils");
|
||||
|
||||
loader.lazyRequireGetter(this, "NetworkHelper",
|
||||
"devtools/shared/webconsole/network-helper");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const {
|
||||
writeHeaderText,
|
||||
getKeyWithEvent,
|
||||
getUrlQuery,
|
||||
parseQueryString,
|
||||
} = require("./request-utils");
|
||||
|
||||
/**
|
||||
* Functions handling the custom request view.
|
||||
@ -112,8 +114,7 @@ CustomRequestView.prototype = {
|
||||
* The URL to extract query string from.
|
||||
*/
|
||||
updateCustomQuery: function (url) {
|
||||
let paramsArray = NetworkHelper.parseQueryString(
|
||||
NetworkHelper.nsIURL(url).query);
|
||||
const paramsArray = parseQueryString(getUrlQuery(url));
|
||||
|
||||
if (!paramsArray) {
|
||||
$("#custom-query").hidden = true;
|
||||
@ -135,7 +136,7 @@ CustomRequestView.prototype = {
|
||||
let queryString = writeQueryString(params);
|
||||
|
||||
let url = $("#custom-url-value").value;
|
||||
let oldQuery = NetworkHelper.nsIURL(url).query;
|
||||
let oldQuery = getUrlQuery(url);
|
||||
let path = url.replace(oldQuery, queryString);
|
||||
|
||||
$("#custom-url-value").value = path;
|
||||
|
@ -8,9 +8,11 @@ const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const Services = require("Services");
|
||||
const appInfo = Services.appinfo;
|
||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||
const { getFormDataSections } = require("devtools/client/netmonitor/request-utils");
|
||||
|
||||
loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
|
||||
const {
|
||||
getFormDataSections,
|
||||
getUrlQuery,
|
||||
parseQueryString,
|
||||
} = require("devtools/client/netmonitor/request-utils");
|
||||
|
||||
loader.lazyGetter(this, "L10N", () => {
|
||||
return new LocalizationHelper("devtools/client/locales/har.properties");
|
||||
@ -170,8 +172,7 @@ HarBuilder.prototype = {
|
||||
request.headers = this.appendHeadersPostData(request.headers, file);
|
||||
request.cookies = this.buildCookies(file.requestCookies);
|
||||
|
||||
request.queryString = NetworkHelper.parseQueryString(
|
||||
NetworkHelper.nsIURL(file.url).query) || [];
|
||||
request.queryString = parseQueryString(getUrlQuery(file.url)) || [];
|
||||
|
||||
request.postData = this.buildPostData(file);
|
||||
|
||||
@ -280,7 +281,7 @@ HarBuilder.prototype = {
|
||||
this._options.getString
|
||||
).then(formDataSections => {
|
||||
formDataSections.forEach(section => {
|
||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
||||
let paramsArray = parseQueryString(section);
|
||||
if (paramsArray) {
|
||||
postData.params = [...postData.params, ...paramsArray];
|
||||
}
|
||||
|
@ -56,14 +56,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Chart",
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
||||
"@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.
|
||||
*/
|
||||
|
@ -8,10 +8,6 @@
|
||||
/* exported $, $all */
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function () {
|
||||
return require("devtools/shared/webconsole/network-helper");
|
||||
});
|
||||
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
const {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
|
||||
/* 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 {ViewHelpers, Heritage} = require("devtools/client/shared/widgets/view-helpers");
|
||||
const {Filters} = require("./filter-predicates");
|
||||
const {getFormDataSections,
|
||||
const {
|
||||
formDataURI,
|
||||
getUriHostPort} = require("./request-utils");
|
||||
decodeUnicodeUrl,
|
||||
getFormDataSections,
|
||||
getUrlBaseName,
|
||||
getUrlQuery,
|
||||
getUrlHost,
|
||||
parseQueryString,
|
||||
} = require("./request-utils");
|
||||
const {L10N} = require("./l10n");
|
||||
const {RequestsMenuView} = require("./requests-menu-view");
|
||||
const {CustomRequestView} = require("./custom-request-view");
|
||||
@ -552,7 +554,7 @@ NetworkDetailsView.prototype = {
|
||||
*/
|
||||
_setSummary: function (data) {
|
||||
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("tooltiptext", unicodeUrl);
|
||||
$("#headers-summary-url").removeAttribute("hidden");
|
||||
@ -743,7 +745,7 @@ NetworkDetailsView.prototype = {
|
||||
* The request's url.
|
||||
*/
|
||||
_setRequestGetParams: function (url) {
|
||||
let query = NetworkHelper.nsIURL(url).query;
|
||||
let query = getUrlQuery(url);
|
||||
if (query) {
|
||||
this._addParams(this._paramsQueryString, query);
|
||||
}
|
||||
@ -825,7 +827,7 @@ NetworkDetailsView.prototype = {
|
||||
* A query string of params (e.g. "?foo=bar&baz=42").
|
||||
*/
|
||||
_addParams: function (name, queryString) {
|
||||
let paramsArray = NetworkHelper.parseQueryString(queryString);
|
||||
let paramsArray = parseQueryString(queryString);
|
||||
if (!paramsArray) {
|
||||
return;
|
||||
}
|
||||
@ -918,7 +920,7 @@ NetworkDetailsView.prototype = {
|
||||
// Immediately display additional information about the image:
|
||||
// file name, mime type and encoding.
|
||||
$("#response-content-image-name-value").setAttribute("value",
|
||||
NetworkHelper.nsIURL(url).fileName);
|
||||
getUrlBaseName(url));
|
||||
$("#response-content-image-mime-value").setAttribute("value", mimeType);
|
||||
|
||||
// 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);
|
||||
|
||||
// Host header
|
||||
let domain = getUriHostPort(url);
|
||||
let domain = getUrlHost(url);
|
||||
let hostHeader = L10N.getFormatStr("netmonitor.security.hostHeader",
|
||||
domain);
|
||||
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 MenuItem = require("devtools/client/framework/menu-item");
|
||||
const { L10N } = require("./l10n");
|
||||
const { formDataURI, getFormDataSections } = require("./request-utils");
|
||||
const {
|
||||
formDataURI,
|
||||
getFormDataSections,
|
||||
getUrlQuery,
|
||||
parseQueryString,
|
||||
} = require("./request-utils");
|
||||
|
||||
loader.lazyRequireGetter(this, "HarExporter",
|
||||
"devtools/client/netmonitor/har/har-exporter", true);
|
||||
@ -21,9 +26,6 @@ loader.lazyRequireGetter(this, "HarExporter",
|
||||
loader.lazyServiceGetter(this, "clipboardHelper",
|
||||
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
||||
|
||||
loader.lazyRequireGetter(this, "NetworkHelper",
|
||||
"devtools/shared/webconsole/network-helper");
|
||||
|
||||
function RequestListContextMenu() {}
|
||||
|
||||
RequestListContextMenu.prototype = {
|
||||
@ -56,8 +58,7 @@ RequestListContextMenu.prototype = {
|
||||
id: "request-menu-context-copy-url-params",
|
||||
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
||||
visible: !!(selectedItem &&
|
||||
NetworkHelper.nsIURL(selectedItem.attachment.url).query),
|
||||
visible: !!(selectedItem && getUrlQuery(selectedItem.attachment.url)),
|
||||
click: () => this.copyUrlParams(),
|
||||
}));
|
||||
|
||||
@ -203,7 +204,7 @@ RequestListContextMenu.prototype = {
|
||||
*/
|
||||
copyUrlParams() {
|
||||
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");
|
||||
clipboardHelper.copyString(string);
|
||||
},
|
||||
@ -224,7 +225,7 @@ RequestListContextMenu.prototype = {
|
||||
|
||||
let params = [];
|
||||
formDataSections.forEach(section => {
|
||||
let paramsArray = NetworkHelper.parseQueryString(section);
|
||||
let paramsArray = parseQueryString(section);
|
||||
if (paramsArray) {
|
||||
params = [...params, ...paramsArray];
|
||||
}
|
||||
|
@ -1,26 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
const { Ci } = require("chrome");
|
||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||
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
|
||||
* an event listener directly and is executed only when data-key is
|
||||
* present in event.target.
|
||||
*
|
||||
* @param function callback
|
||||
* Function to execute execute when data-key
|
||||
* @param {function} callback - function to execute execute when data-key
|
||||
* is present in event.target.
|
||||
* @param bool onlySpaceOrReturn
|
||||
* Flag to indicate if callback should only be called
|
||||
when the space or return button is pressed
|
||||
* @return function
|
||||
* Wrapped function with the target data-key as the first argument
|
||||
* @param {bool} onlySpaceOrReturn - flag to indicate if callback should only
|
||||
* be called when the space or return button
|
||||
* is pressed
|
||||
* @return {function} 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) {
|
||||
let key = event.target.getAttribute("data-key");
|
||||
let filterKeyboardEvent = !onlySpaceOrReturn ||
|
||||
@ -31,24 +29,19 @@ exports.getKeyWithEvent = function (callback, onlySpaceOrReturn) {
|
||||
callback.call(null, key);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
*
|
||||
* @param object headers
|
||||
* The "requestHeaders".
|
||||
* @param object uploadHeaders
|
||||
* The "requestHeadersFromUploadStream".
|
||||
* @param object postData
|
||||
* 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.
|
||||
* @param {object} headers - the "requestHeaders".
|
||||
* @param {object} uploadHeaders - the "requestHeadersFromUploadStream".
|
||||
* @param {object} postData - the "requestPostData".
|
||||
* @param {function} getString - callback to retrieve a string from a LongStringGrip.
|
||||
* @return {array} a promise list 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) {
|
||||
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.
|
||||
*
|
||||
* @param {String} mimeType the mime type
|
||||
* @param {String} encoding the encoding to use; if not set, the
|
||||
* @param {string} mimeType - mime type
|
||||
* @param {string} encoding - encoding to use; if not set, the
|
||||
* text will be base64-encoded.
|
||||
* @param {String} text the text of the URI.
|
||||
* @return {String} a data: URI
|
||||
* @param {string} text - text of the URI.
|
||||
* @return {string} a data URI
|
||||
*/
|
||||
exports.formDataURI = function (mimeType, encoding, text) {
|
||||
function formDataURI(mimeType, encoding, text) {
|
||||
if (!encoding) {
|
||||
encoding = "base64";
|
||||
text = btoa(text);
|
||||
}
|
||||
return "data:" + mimeType + ";" + encoding + "," + text;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out a list of headers into a chunk of text
|
||||
*
|
||||
* @param array headers
|
||||
* Array of headers info {name, value}
|
||||
* @return string text
|
||||
* List of headers in text format
|
||||
* @param {array} headers - array of headers info { name, value }
|
||||
* @return {string} list of headers in text format
|
||||
*/
|
||||
exports.writeHeaderText = function (headers) {
|
||||
function writeHeaderText(headers) {
|
||||
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.
|
||||
*
|
||||
* @param string mimeType
|
||||
* @return string
|
||||
* @param {string} mimeType - mime type
|
||||
* @return {string} abbreviated mime type
|
||||
*/
|
||||
exports.getAbbreviatedMimeType = function (mimeType) {
|
||||
function getAbbreviatedMimeType(mimeType) {
|
||||
if (!mimeType) {
|
||||
return "";
|
||||
}
|
||||
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
|
||||
* @return string
|
||||
* @param {string} url - url string
|
||||
* @return {string} unicode basename of a url
|
||||
*/
|
||||
exports.getUriNameWithQuery = function (url) {
|
||||
if (!(url instanceof Ci.nsIURL)) {
|
||||
url = NetworkHelper.nsIURL(url);
|
||||
function getUrlBaseName(url) {
|
||||
const pathname = (new URL(url)).pathname;
|
||||
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(
|
||||
unescape(url.fileName || url.filePath || "/"));
|
||||
let query = NetworkHelper.convertToUnicode(unescape(url.query));
|
||||
|
||||
return name + (query ? "?" + query : "");
|
||||
};
|
||||
|
||||
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+$/, "");
|
||||
};
|
||||
return query.replace(/^[?&]/, "").split("&").map(e => {
|
||||
let param = e.split("=");
|
||||
return {
|
||||
name: param[0] ? decodeUnicodeUrl(param[0]) : "",
|
||||
value: param[1] ? decodeUnicodeUrl(param[1]) : "",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a nsIContentPolicy constant to a display string
|
||||
@ -180,6 +232,22 @@ const LOAD_CAUSE_STRINGS = {
|
||||
[Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest"
|
||||
};
|
||||
|
||||
exports.loadCauseString = function (causeType) {
|
||||
function loadCauseString(causeType) {
|
||||
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 {formDataURI,
|
||||
writeHeaderText,
|
||||
decodeUnicodeUrl,
|
||||
getKeyWithEvent,
|
||||
getAbbreviatedMimeType,
|
||||
getUriNameWithQuery,
|
||||
getUriHostPort,
|
||||
getUriHost,
|
||||
getUrlBaseNameWithQuery,
|
||||
getUrlHost,
|
||||
getUrlHostName,
|
||||
loadCauseString} = require("./request-utils");
|
||||
const Actions = require("./actions/index");
|
||||
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 EPSILON = 0.001;
|
||||
// ms
|
||||
@ -925,17 +923,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
break;
|
||||
}
|
||||
case "url": {
|
||||
let uri;
|
||||
try {
|
||||
uri = NetworkHelper.nsIURL(value);
|
||||
} catch (e) {
|
||||
// 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 nameWithQuery = getUrlBaseNameWithQuery(value);
|
||||
let hostPort = getUrlHost(value);
|
||||
let host = getUrlHostName(value);
|
||||
let unicodeUrl = decodeUnicodeUrl(value);
|
||||
|
||||
let file = $(".requests-menu-file", target);
|
||||
file.setAttribute("value", nameWithQuery);
|
||||
|
@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
const { getAbbreviatedMimeType,
|
||||
getUriNameWithQuery,
|
||||
getUriHostPort,
|
||||
getUrlBaseNameWithQuery,
|
||||
getUrlHost,
|
||||
loadCauseString } = require("./request-utils");
|
||||
|
||||
/**
|
||||
@ -36,8 +36,8 @@ function method(first, second) {
|
||||
}
|
||||
|
||||
function file(first, second) {
|
||||
let firstUrl = getUriNameWithQuery(first.url).toLowerCase();
|
||||
let secondUrl = getUriNameWithQuery(second.url).toLowerCase();
|
||||
let firstUrl = getUrlBaseNameWithQuery(first.url).toLowerCase();
|
||||
let secondUrl = getUrlBaseNameWithQuery(second.url).toLowerCase();
|
||||
if (firstUrl == secondUrl) {
|
||||
return first.startedMillis - second.startedMillis;
|
||||
}
|
||||
@ -45,8 +45,8 @@ function file(first, second) {
|
||||
}
|
||||
|
||||
function domain(first, second) {
|
||||
let firstDomain = getUriHostPort(first.url).toLowerCase();
|
||||
let secondDomain = getUriHostPort(second.url).toLowerCase();
|
||||
let firstDomain = getUrlHost(first.url).toLowerCase();
|
||||
let secondDomain = getUrlHost(second.url).toLowerCase();
|
||||
if (firstDomain == secondDomain) {
|
||||
return first.startedMillis - second.startedMillis;
|
||||
}
|
||||
|
@ -9,8 +9,13 @@ Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
||||
this);
|
||||
|
||||
var NetworkHelper = require("devtools/shared/webconsole/network-helper");
|
||||
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 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;
|
||||
let { attachment, target } = aRequestItem;
|
||||
|
||||
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
||||
let unicodeUrl = NetworkHelper.convertToUnicode(unescape(aUrl));
|
||||
let name = NetworkHelper.convertToUnicode(unescape(uri.fileName || uri.filePath || "/"));
|
||||
let query = NetworkHelper.convertToUnicode(unescape(uri.query));
|
||||
let hostPort = uri.hostPort;
|
||||
let unicodeUrl = decodeUnicodeUrl(aUrl);
|
||||
let name = getUrlBaseName(aUrl);
|
||||
let query = getUrlQuery(aUrl);
|
||||
let hostPort = getUrlHost(aUrl);
|
||||
let remoteAddress = attachment.remoteAddress;
|
||||
|
||||
if (fuzzyUrl) {
|
||||
|
@ -1740,6 +1740,7 @@ WebConsoleActor.prototype =
|
||||
delete result.ID;
|
||||
delete result.innerID;
|
||||
delete result.consoleID;
|
||||
delete result.originAttributes;
|
||||
|
||||
result.arguments = Array.map(aMessage.arguments || [], (aObj) => {
|
||||
let dbgObj = this.makeDebuggeeValue(aObj, aUseObjectGlobal);
|
||||
|
@ -127,6 +127,12 @@ ConsoleAPIStorageService.prototype = {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// truncate
|
||||
|
@ -407,7 +407,8 @@ EventTargetChainItem::HandleEventTargetChain(
|
||||
}
|
||||
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
|
||||
// STOP_DISPATCH flag since this resets for each event group.
|
||||
aVisitor.mEvent->mFlags.mPropagationStopped = false;
|
||||
|
@ -118,10 +118,8 @@ support-files =
|
||||
support-files = pointerevent_setpointercapture_to_same_element_twice-manual.html
|
||||
[test_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]
|
||||
support-files = pointerevent_suppress_compat_events_on_drag_mouse.html
|
||||
disabled = should be investigated
|
||||
[test_touch_action.html]
|
||||
support-files =
|
||||
../../../../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
|
||||
[test_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]
|
||||
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));
|
||||
},
|
||||
|
||||
getStreamById: function(id) {
|
||||
throw new this._win.DOMException("getStreamById not yet implemented",
|
||||
"NotSupportedError");
|
||||
},
|
||||
|
||||
addTrack: function(track, stream) {
|
||||
if (stream.currentTime === undefined) {
|
||||
throw new this._win.DOMException("invalid stream.", "InvalidParameterError");
|
||||
|
@ -372,6 +372,13 @@ MediaDrmCDMProxy::IsOnOwnerThread()
|
||||
}
|
||||
#endif
|
||||
|
||||
const nsString&
|
||||
MediaDrmCDMProxy::GetMediaDrmStubId() const
|
||||
{
|
||||
MOZ_ASSERT(mCDM);
|
||||
return mCDM->GetMediaDrmStubId();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDrmCDMProxy::OnCDMCreated(uint32_t aPromiseId)
|
||||
{
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <jni.h>
|
||||
#include "mozilla/jni/Types.h"
|
||||
#include "GeneratedJNINatives.h"
|
||||
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/CDMCaps.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
@ -118,6 +117,8 @@ public:
|
||||
bool IsOnOwnerThread() override;
|
||||
#endif
|
||||
|
||||
const nsString& GetMediaDrmStubId() const;
|
||||
|
||||
private:
|
||||
virtual ~MediaDrmCDMProxy();
|
||||
|
||||
|
@ -204,6 +204,9 @@ MediaDrmProxySupport::MediaDrmProxySupport(const nsAString& aKeySystem)
|
||||
MediaDrmProxy::Create(mKeySystem,
|
||||
mJavaCallbacks,
|
||||
MediaPrefs::PDMAndroidRemoteCodecEnabled());
|
||||
|
||||
MOZ_ASSERT(mBridgeProxy, "mBridgeProxy should not be null");
|
||||
mMediaDrmStubId = mBridgeProxy->GetStubId()->ToString();
|
||||
}
|
||||
|
||||
MediaDrmProxySupport::~MediaDrmProxySupport()
|
||||
|
@ -54,13 +54,15 @@ public:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
const nsString& GetMediaDrmStubId() const { return mMediaDrmStubId; }
|
||||
|
||||
private:
|
||||
const nsString mKeySystem;
|
||||
java::MediaDrmProxy::GlobalRef mBridgeProxy;
|
||||
java::MediaDrmProxy::NativeMediaDrmProxyCallbacks::GlobalRef mJavaCallbacks;
|
||||
DecryptorProxyCallback* mCallback;
|
||||
bool mDestroyed;
|
||||
|
||||
nsString mMediaDrmStubId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include "../AudioPacketizer.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;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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.
|
||||
}
|
||||
|
||||
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++) {
|
||||
ASSERT_TRUE(aBuffer[i] == 0) <<
|
||||
@ -65,9 +66,8 @@ TEST(AudioPacketizer, Test)
|
||||
{
|
||||
AudioPacketizer<int16_t, int16_t> ap(441, channels);
|
||||
for (int16_t i = 0; i < 10; i++) {
|
||||
int16_t* out = ap.Output();
|
||||
Zero(out, 441);
|
||||
delete[] out;
|
||||
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||
Zero(std::move(out), 441);
|
||||
}
|
||||
}
|
||||
// Simple test, with input/output buffer size aligned on the packet size,
|
||||
@ -80,9 +80,8 @@ TEST(AudioPacketizer, Test)
|
||||
int16_t prevEnd = seqEnd;
|
||||
seqEnd = Sequence(b.Get(), channels * 441, prevEnd);
|
||||
ap.Input(b.Get(), 441);
|
||||
int16_t* out = ap.Output();
|
||||
IsSequence(out, 441 * channels, prevEnd);
|
||||
delete[] out;
|
||||
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||
IsSequence(std::move(out), 441 * channels, prevEnd);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
ap.Input(b.Get(), 441);
|
||||
ap.Input(b1.Get(), 441);
|
||||
int16_t* out = ap.Output();
|
||||
int16_t* out2 = ap.Output();
|
||||
IsSequence(out, 441 * channels, prevEnd0);
|
||||
IsSequence(out2, 441 * channels, prevEnd1);
|
||||
delete[] out;
|
||||
delete[] out2;
|
||||
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||
std::unique_ptr<int16_t[]> out2(ap.Output());
|
||||
IsSequence(std::move(out), 441 * channels, prevEnd0);
|
||||
IsSequence(std::move(out2), 441 * channels, prevEnd1);
|
||||
}
|
||||
}
|
||||
// Input/output buffer size not aligned on the packet size,
|
||||
@ -120,14 +117,12 @@ TEST(AudioPacketizer, Test)
|
||||
prevSeq = Sequence(b1.Get(), 480 * channels, prevSeq);
|
||||
ap.Input(b.Get(), 480);
|
||||
ap.Input(b1.Get(), 480);
|
||||
int16_t* out = ap.Output();
|
||||
int16_t* out2 = ap.Output();
|
||||
IsSequence(out, 441 * channels, prevEnd);
|
||||
std::unique_ptr<int16_t[]> out(ap.Output());
|
||||
std::unique_ptr<int16_t[]> out2(ap.Output());
|
||||
IsSequence(std::move(out), 441 * channels, prevEnd);
|
||||
prevEnd += 441 * channels;
|
||||
IsSequence(out2, 441 * channels, prevEnd);
|
||||
IsSequence(std::move(out2), 441 * channels, prevEnd);
|
||||
prevEnd += 441 * channels;
|
||||
delete[] out;
|
||||
delete[] out2;
|
||||
}
|
||||
printf("Available: %d\n", ap.PacketsAvailable());
|
||||
}
|
||||
@ -151,7 +146,7 @@ TEST(AudioPacketizer, Test)
|
||||
}
|
||||
ap.Input(b.Get(), 128);
|
||||
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 (int32_t c = 0; c < channels; c++) {
|
||||
ASSERT_TRUE(packet[k * channels + c] ==
|
||||
@ -159,7 +154,6 @@ TEST(AudioPacketizer, Test)
|
||||
}
|
||||
outPhase++;
|
||||
}
|
||||
delete [] packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,6 +469,14 @@ PDMFactory::GetDecoder(const TrackInfo& aTrackInfo,
|
||||
void
|
||||
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();
|
||||
mEMEPDM = new EMEDecoderModule(aProxy, m);
|
||||
}
|
||||
|
@ -119,6 +119,11 @@ GetCryptoInfoFromSample(const MediaRawData* aSample)
|
||||
return cryptoInfo;
|
||||
}
|
||||
|
||||
AndroidDecoderModule::AndroidDecoderModule(CDMProxy* aProxy)
|
||||
{
|
||||
mProxy = static_cast<MediaDrmCDMProxy*>(aProxy);
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const
|
||||
@ -174,16 +179,24 @@ AndroidDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
config.mDisplay.height,
|
||||
&format), nullptr);
|
||||
|
||||
nsString drmStubId;
|
||||
if (mProxy) {
|
||||
drmStubId = mProxy->GetMediaDrmStubId();
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
||||
RemoteDataDecoder::CreateVideoDecoder(config,
|
||||
format,
|
||||
aParams.mCallback,
|
||||
aParams.mImageContainer) :
|
||||
aParams.mImageContainer,
|
||||
drmStubId) :
|
||||
MediaCodecDataDecoder::CreateVideoDecoder(config,
|
||||
format,
|
||||
aParams.mCallback,
|
||||
aParams.mImageContainer);
|
||||
|
||||
aParams.mImageContainer,
|
||||
drmStubId,
|
||||
mProxy,
|
||||
aParams.mTaskQueue);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
@ -204,10 +217,18 @@ AndroidDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
|
||||
config.mChannels,
|
||||
&format), nullptr);
|
||||
|
||||
nsString drmStubId;
|
||||
if (mProxy) {
|
||||
drmStubId = mProxy->GetMediaDrmStubId();
|
||||
}
|
||||
RefPtr<MediaDataDecoder> decoder = MediaPrefs::PDMAndroidRemoteCodecEnabled() ?
|
||||
RemoteDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback) :
|
||||
MediaCodecDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback);
|
||||
|
||||
RemoteDataDecoder::CreateAudioDecoder(config, format, aParams.mCallback, drmStubId) :
|
||||
MediaCodecDataDecoder::CreateAudioDecoder(config,
|
||||
format,
|
||||
aParams.mCallback,
|
||||
drmStubId,
|
||||
mProxy,
|
||||
aParams.mTaskQueue);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define AndroidDecoderModule_h_
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/MediaDrmCDMProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -17,7 +18,7 @@ public:
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const CreateDecoderParams& aParams) override;
|
||||
|
||||
AndroidDecoderModule() {}
|
||||
AndroidDecoderModule(CDMProxy* aProxy = nullptr);
|
||||
virtual ~AndroidDecoderModule() {}
|
||||
|
||||
bool SupportsMimeType(const nsACString& aMimeType,
|
||||
@ -25,6 +26,9 @@ public:
|
||||
|
||||
ConversionRequired
|
||||
DecoderNeedsConversion(const TrackInfo& aConfig) const override;
|
||||
|
||||
private:
|
||||
RefPtr<MediaDrmCDMProxy> mProxy;
|
||||
};
|
||||
|
||||
extern LazyLogModule sAndroidDecoderModuleLog;
|
||||
|
@ -56,9 +56,10 @@ public:
|
||||
VideoDataDecoder(const VideoInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
layers::ImageContainer* aImageContainer,
|
||||
const nsString& aDrmStubId)
|
||||
: MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
||||
aFormat, aCallback)
|
||||
aFormat, aCallback, aDrmStubId)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mConfig(aConfig)
|
||||
{
|
||||
@ -81,7 +82,6 @@ public:
|
||||
if (NS_FAILED(InitDecoder(mSurfaceTexture->JavaSurface()))) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
|
||||
return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
|
||||
}
|
||||
|
||||
@ -127,15 +127,59 @@ protected:
|
||||
layers::ImageContainer* mImageContainer;
|
||||
const VideoInfo& mConfig;
|
||||
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
|
||||
{
|
||||
public:
|
||||
AudioDataDecoder(const AudioInfo& aConfig, MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId)
|
||||
: MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
||||
aFormat, aCallback)
|
||||
aFormat, aCallback, aDrmStubId)
|
||||
{
|
||||
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*
|
||||
MediaCodecDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
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*
|
||||
MediaCodecDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
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,
|
||||
const nsACString& aMimeType,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId)
|
||||
: mType(aType)
|
||||
, mMimeType(aMimeType)
|
||||
, mFormat(aFormat)
|
||||
@ -239,8 +345,8 @@ MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
||||
, mOutputBuffers(nullptr)
|
||||
, mMonitor("MediaCodecDataDecoder::mMonitor")
|
||||
, mState(ModuleState::kDecoding)
|
||||
, mDrmStubId(aDrmStubId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MediaCodecDataDecoder::~MediaCodecDataDecoder()
|
||||
@ -273,8 +379,11 @@ MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
|
||||
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;
|
||||
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 = ResetInputBuffers(), rv);
|
||||
|
@ -23,12 +23,18 @@ class MediaCodecDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId,
|
||||
CDMProxy* aProxy,
|
||||
TaskQueue* aTaskQueue);
|
||||
|
||||
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
layers::ImageContainer* aImageContainer,
|
||||
const nsString& aDrmStubId,
|
||||
CDMProxy* aProxy,
|
||||
TaskQueue* aTaskQueue);
|
||||
|
||||
virtual ~MediaCodecDataDecoder();
|
||||
|
||||
@ -58,7 +64,8 @@ protected:
|
||||
MediaCodecDataDecoder(MediaData::Type aType,
|
||||
const nsACString& aMimeType,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId);
|
||||
|
||||
static const char* ModuleStateStr(ModuleState aState);
|
||||
|
||||
@ -119,6 +126,8 @@ protected:
|
||||
SampleQueue mQueue;
|
||||
// Durations are stored in microseconds.
|
||||
std::deque<media::TimeUnit> mDurations;
|
||||
|
||||
nsString mDrmStubId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -185,9 +185,10 @@ public:
|
||||
RemoteVideoDecoder(const VideoInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
layers::ImageContainer* aImageContainer,
|
||||
const nsString& aDrmStubId)
|
||||
: RemoteDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
|
||||
aFormat, aCallback)
|
||||
aFormat, aCallback, aDrmStubId)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mConfig(aConfig)
|
||||
{
|
||||
@ -213,7 +214,10 @@ public:
|
||||
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
||||
|
||||
mJavaDecoder = CodecProxy::Create(mFormat, mSurfaceTexture->JavaSurface(), mJavaCallbacks);
|
||||
mJavaDecoder = CodecProxy::Create(mFormat,
|
||||
mSurfaceTexture->JavaSurface(),
|
||||
mJavaCallbacks,
|
||||
mDrmStubId);
|
||||
if (mJavaDecoder == nullptr) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
@ -282,9 +286,10 @@ class RemoteAudioDecoder final : public RemoteDataDecoder
|
||||
public:
|
||||
RemoteAudioDecoder(const AudioInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId)
|
||||
: RemoteDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
|
||||
aFormat, aCallback)
|
||||
aFormat, aCallback, aDrmStubId)
|
||||
, mConfig(aConfig)
|
||||
{
|
||||
JNIEnv* const env = jni::GetEnvForThread();
|
||||
@ -311,7 +316,7 @@ public:
|
||||
JavaCallbacksSupport::AttachNative(mJavaCallbacks,
|
||||
mozilla::MakeUnique<CallbacksSupport>(this, mCallback));
|
||||
|
||||
mJavaDecoder = CodecProxy::Create(mFormat, nullptr, mJavaCallbacks);
|
||||
mJavaDecoder = CodecProxy::Create(mFormat, nullptr, mJavaCallbacks, mDrmStubId);
|
||||
if (mJavaDecoder == nullptr) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
@ -410,28 +415,32 @@ private:
|
||||
MediaDataDecoder*
|
||||
RemoteDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId)
|
||||
{
|
||||
return new RemoteAudioDecoder(aConfig, aFormat, aCallback);
|
||||
return new RemoteAudioDecoder(aConfig, aFormat, aCallback, aDrmStubId);
|
||||
}
|
||||
|
||||
MediaDataDecoder*
|
||||
RemoteDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
|
||||
MediaFormat::Param aFormat,
|
||||
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,
|
||||
const nsACString& aMimeType,
|
||||
MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId)
|
||||
: mType(aType)
|
||||
, mMimeType(aMimeType)
|
||||
, mFormat(aFormat)
|
||||
, mCallback(aCallback)
|
||||
, mDrmStubId(aDrmStubId)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,14 @@ class RemoteDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
static MediaDataDecoder* CreateAudioDecoder(const AudioInfo& aConfig,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId);
|
||||
|
||||
static MediaDataDecoder* CreateVideoDecoder(const VideoInfo& aConfig,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
layers::ImageContainer* aImageContainer,
|
||||
const nsString& aDrmStubId);
|
||||
|
||||
virtual ~RemoteDataDecoder() {}
|
||||
|
||||
@ -44,7 +46,8 @@ protected:
|
||||
RemoteDataDecoder(MediaData::Type aType,
|
||||
const nsACString& aMimeType,
|
||||
java::sdk::MediaFormat::Param aFormat,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
const nsString& aDrmStubId);
|
||||
|
||||
MediaData::Type mType;
|
||||
|
||||
@ -55,6 +58,7 @@ protected:
|
||||
|
||||
java::CodecProxy::GlobalRef mJavaDecoder;
|
||||
java::CodecProxy::NativeCallbacks::GlobalRef mJavaCallbacks;
|
||||
nsString mDrmStubId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -222,7 +222,7 @@ public:
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
const T& ReturnValue() const {
|
||||
T ReturnValue() const {
|
||||
if (mSuccess) {
|
||||
return mSuccessValue;
|
||||
} else {
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
}
|
||||
aValues.ComputeLengthAndData();
|
||||
|
||||
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve,
|
||||
aStartTime, 0.0f, 0.0f, aDuration, aValues.Data(),
|
||||
aValues.Length());
|
||||
@ -82,6 +83,7 @@ public:
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return this;
|
||||
}
|
||||
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetValueAtTime,
|
||||
aStartTime, aValue);
|
||||
|
||||
@ -95,6 +97,7 @@ public:
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return this;
|
||||
}
|
||||
aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime());
|
||||
EventInsertionHelper(aRv, AudioTimelineEvent::LinearRamp, aEndTime, aValue);
|
||||
return this;
|
||||
}
|
||||
@ -106,6 +109,7 @@ public:
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return this;
|
||||
}
|
||||
aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime());
|
||||
EventInsertionHelper(aRv, AudioTimelineEvent::ExponentialRamp,
|
||||
aEndTime, aValue);
|
||||
return this;
|
||||
@ -119,6 +123,7 @@ public:
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return this;
|
||||
}
|
||||
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||
EventInsertionHelper(aRv, AudioTimelineEvent::SetTarget,
|
||||
aStartTime, aTarget,
|
||||
aTimeConstant);
|
||||
@ -133,6 +138,8 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime());
|
||||
|
||||
// Remove some events on the main thread copy.
|
||||
AudioEventTimeline::CancelScheduledValues(aStartTime);
|
||||
|
||||
|
@ -120,8 +120,6 @@ interface RTCPeerConnection : EventTarget {
|
||||
sequence<MediaStream> getLocalStreams ();
|
||||
[UnsafeInPrerendering, Deprecated="RTCPeerConnectionGetStreams"]
|
||||
sequence<MediaStream> getRemoteStreams ();
|
||||
[UnsafeInPrerendering]
|
||||
MediaStream? getStreamById (DOMString streamId);
|
||||
void addStream (MediaStream stream);
|
||||
|
||||
// replaces addStream; fails if already added
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "GPUProcessManager.h"
|
||||
#include "GPUProcessHost.h"
|
||||
#include "GPUProcessListener.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/layers/APZCTreeManager.h"
|
||||
|
@ -3,6 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Instruments.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
@ -42,7 +43,7 @@ template<typename T>
|
||||
class AutoReleased
|
||||
{
|
||||
public:
|
||||
AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
|
||||
MOZ_IMPLICIT AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
|
||||
{
|
||||
}
|
||||
~AutoReleased()
|
||||
|
@ -507,7 +507,7 @@ class CodeOffsetJump
|
||||
return jumpTableIndex_;
|
||||
}
|
||||
#else
|
||||
CodeOffsetJump(size_t offset) : offset_(offset) {}
|
||||
explicit CodeOffsetJump(size_t offset) : offset_(offset) {}
|
||||
#endif
|
||||
|
||||
CodeOffsetJump() {
|
||||
|
@ -71,7 +71,7 @@ class RelocationIterator
|
||||
uint32_t offset_;
|
||||
|
||||
public:
|
||||
RelocationIterator(CompactBufferReader& reader)
|
||||
explicit RelocationIterator(CompactBufferReader& reader)
|
||||
: reader_(reader)
|
||||
{ }
|
||||
|
||||
|
@ -160,14 +160,14 @@ static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
|
||||
|
||||
struct ImmTag : public Imm32
|
||||
{
|
||||
ImmTag(JSValueTag mask)
|
||||
explicit ImmTag(JSValueTag mask)
|
||||
: Imm32(int32_t(mask))
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ImmType : public ImmTag
|
||||
{
|
||||
ImmType(JSValueType type)
|
||||
explicit ImmType(JSValueType type)
|
||||
: ImmTag(JSVAL_TYPE_TO_TAG(type))
|
||||
{ }
|
||||
};
|
||||
|
@ -736,7 +736,7 @@ class OutOfLineTruncate : public OutOfLineCodeBase<CodeGeneratorX86>
|
||||
LTruncateDToInt32* ins_;
|
||||
|
||||
public:
|
||||
OutOfLineTruncate(LTruncateDToInt32* ins)
|
||||
explicit OutOfLineTruncate(LTruncateDToInt32* ins)
|
||||
: ins_(ins)
|
||||
{ }
|
||||
|
||||
@ -753,7 +753,7 @@ class OutOfLineTruncateFloat32 : public OutOfLineCodeBase<CodeGeneratorX86>
|
||||
LTruncateFToInt32* ins_;
|
||||
|
||||
public:
|
||||
OutOfLineTruncateFloat32(LTruncateFToInt32* ins)
|
||||
explicit OutOfLineTruncateFloat32(LTruncateFToInt32* ins)
|
||||
: ins_(ins)
|
||||
{ }
|
||||
|
||||
|
@ -254,7 +254,7 @@ class BaseCompiler
|
||||
# ifdef DEBUG
|
||||
BaseCompiler& bc;
|
||||
public:
|
||||
ScratchI32(BaseCompiler& bc) : bc(bc) {
|
||||
explicit ScratchI32(BaseCompiler& bc) : bc(bc) {
|
||||
MOZ_ASSERT(!bc.scratchRegisterTaken());
|
||||
bc.setScratchRegisterTaken(true);
|
||||
}
|
||||
@ -264,7 +264,7 @@ class BaseCompiler
|
||||
}
|
||||
# else
|
||||
public:
|
||||
ScratchI32(BaseCompiler& bc) {}
|
||||
explicit ScratchI32(BaseCompiler& bc) {}
|
||||
# endif
|
||||
operator Register() const {
|
||||
# ifdef JS_CODEGEN_X86
|
||||
|
@ -1567,32 +1567,18 @@ struct MaskLayerUserData : public LayerUserData
|
||||
struct CSSMaskLayerUserData : public LayerUserData
|
||||
{
|
||||
CSSMaskLayerUserData()
|
||||
: mImageLayers(nsStyleImageLayers::LayerType::Mask)
|
||||
: mFrame(nullptr)
|
||||
{ }
|
||||
|
||||
CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntRect& aBounds)
|
||||
: mImageLayers(aFrame->StyleSVGReset()->mMask),
|
||||
mContentRect(aFrame->GetContentRectRelativeToSelf()),
|
||||
mPaddingRect(aFrame->GetPaddingRectRelativeToSelf()),
|
||||
mBorderRect(aFrame->GetRectRelativeToSelf()),
|
||||
mMarginRect(aFrame->GetMarginRectRelativeToSelf()),
|
||||
mBounds(aBounds)
|
||||
{
|
||||
Hash(aFrame);
|
||||
}
|
||||
CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntSize& aMaskSize)
|
||||
: mFrame(aFrame),
|
||||
mMaskSize(aMaskSize)
|
||||
{ }
|
||||
|
||||
CSSMaskLayerUserData& operator=(const CSSMaskLayerUserData& aOther)
|
||||
{
|
||||
mImageLayers = aOther.mImageLayers;
|
||||
|
||||
mContentRect = aOther.mContentRect;
|
||||
mPaddingRect = aOther.mPaddingRect;
|
||||
mBorderRect = aOther.mBorderRect;
|
||||
mMarginRect = aOther.mMarginRect;
|
||||
|
||||
mBounds = aOther.mBounds;
|
||||
|
||||
mHash = aOther.mHash;
|
||||
mFrame = aOther.mFrame;
|
||||
mMaskSize = aOther.mMaskSize;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -1600,22 +1586,16 @@ struct CSSMaskLayerUserData : public LayerUserData
|
||||
bool
|
||||
operator==(const CSSMaskLayerUserData& aOther) const
|
||||
{
|
||||
if (mHash != aOther.mHash) {
|
||||
if (mFrame != aOther.mFrame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mImageLayers.mLayers != aOther.mImageLayers.mLayers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mContentRect.IsEqualEdges(aOther.mContentRect) ||
|
||||
!mPaddingRect.IsEqualEdges(aOther.mPaddingRect) ||
|
||||
!mBorderRect.IsEqualEdges(aOther.mBorderRect) ||
|
||||
!mMarginRect.IsEqualEdges(aOther.mMarginRect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBounds.IsEqualEdges(aOther.mBounds)) {
|
||||
// Even if the frame is valid, check the size of the display item's
|
||||
// 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
|
||||
// space.
|
||||
if (mMaskSize != aOther.mMaskSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1623,36 +1603,8 @@ struct CSSMaskLayerUserData : public LayerUserData
|
||||
}
|
||||
|
||||
private:
|
||||
void Hash(nsIFrame* aFrame)
|
||||
{
|
||||
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;
|
||||
nsIFrame* mFrame;
|
||||
nsIntSize mMaskSize;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3915,8 +3867,9 @@ ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
|
||||
bool snap;
|
||||
nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
|
||||
nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
|
||||
CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect);
|
||||
if (*oldUserData == newUserData) {
|
||||
CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect.Size());
|
||||
nsRect dirtyRect;
|
||||
if (!aMaskItem->IsInvalid(dirtyRect) && *oldUserData == newUserData) {
|
||||
aLayer->SetMaskLayer(maskLayer);
|
||||
return;
|
||||
}
|
||||
|
@ -7140,10 +7140,13 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
||||
nsSVGUtils::MaskUsage maskUsage;
|
||||
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
||||
|
||||
if (!maskUsage.shouldGenerateMaskLayer ||
|
||||
maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
||||
maskUsage.shouldApplyBasicShape ||
|
||||
maskUsage.shouldGenerateClipMaskLayer) {
|
||||
if (!maskUsage.shouldGenerateMaskLayer &&
|
||||
!maskUsage.shouldGenerateClipMaskLayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
||||
maskUsage.shouldApplyBasicShape) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7151,20 +7154,6 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1277,11 +1277,13 @@ public:
|
||||
uint16_t mPointerType;
|
||||
bool mActiveState;
|
||||
bool mPrimaryState;
|
||||
bool mPreventMouseEventByContent;
|
||||
explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
|
||||
bool aPrimaryState)
|
||||
: mPointerType(aPointerType)
|
||||
, mActiveState(aActiveState)
|
||||
, mPrimaryState(aPrimaryState)
|
||||
, mPreventMouseEventByContent(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -6834,6 +6834,82 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
||||
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
|
||||
DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
||||
nsIFrame* aFrame,
|
||||
@ -6880,8 +6956,10 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
||||
mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
|
||||
0.0f;
|
||||
event.convertToPointer = mouseEvent->convertToPointer = false;
|
||||
PreHandlePointerEventsPreventDefault(&event, aEvent);
|
||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
||||
aTargetContent);
|
||||
PostHandlePointerEventsPreventDefault(&event, aEvent);
|
||||
} else if (aEvent->mClass == eTouchEventClass) {
|
||||
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
|
||||
// loop over all touches and dispatch pointer events on each touch
|
||||
@ -6926,8 +7004,10 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
|
||||
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
|
||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
event.convertToPointer = touch->convertToPointer = false;
|
||||
PreHandlePointerEventsPreventDefault(&event, aEvent);
|
||||
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
|
||||
aTargetContent);
|
||||
PostHandlePointerEventsPreventDefault(&event, aEvent);
|
||||
}
|
||||
}
|
||||
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-text.html about:blank
|
||||
== 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_array_type;
|
||||
*
|
||||
* typedef ... coeff_type;
|
||||
*
|
||||
* typedef ... result_type;
|
||||
*
|
||||
* // GetUnit(avalue) must return the correct nsCSSUnit for any
|
||||
@ -40,17 +42,17 @@ namespace css {
|
||||
*
|
||||
* result_type
|
||||
* MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
* float aValue1, result_type aValue2);
|
||||
* coeff_type aValue1, result_type aValue2);
|
||||
*
|
||||
* result_type
|
||||
* MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
* result_type aValue1, float aValue2);
|
||||
* result_type aValue1, coeff_type aValue2);
|
||||
*
|
||||
* result_type
|
||||
* ComputeLeafValue(const input_type& aValue);
|
||||
*
|
||||
* float
|
||||
* ComputeNumber(const input_type& aValue);
|
||||
* coeff_type
|
||||
* ComputeCoefficient(const coeff_type& aValue);
|
||||
*
|
||||
* The CalcOps methods might compute the calc() expression down to a
|
||||
* number, reduce some parts of it to a number but replicate other
|
||||
@ -59,18 +61,21 @@ namespace css {
|
||||
* values).
|
||||
*
|
||||
* 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).
|
||||
* (The CalcOps in the CSS parser that reduces purely numeric
|
||||
* expressions in turn calls ComputeCalc on numbers; other ops can
|
||||
* presume that expressions in the number positions have already been
|
||||
* normalized to a single numeric value and derive from
|
||||
* NumbersAlreadyNormalizedCalcOps.)
|
||||
* presume that expressions in the coefficient positions have already been
|
||||
* normalized to a single numeric value and derive from, if their coefficient
|
||||
* 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:
|
||||
* MergeAdditive for Plus and Minus
|
||||
* MergeMultiplicativeL for Times_L (number * value)
|
||||
* MergeMultiplicativeR for Times_R (value * number) and Divided
|
||||
* MergeMultiplicativeL for Times_L (coeff * value)
|
||||
* MergeMultiplicativeR for Times_R (value * coeff) and Divided
|
||||
*/
|
||||
template <class CalcOps>
|
||||
static typename CalcOps::result_type
|
||||
@ -93,7 +98,7 @@ ComputeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
||||
case eCSSUnit_Calc_Times_L: {
|
||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||
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);
|
||||
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();
|
||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||
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);
|
||||
}
|
||||
default: {
|
||||
@ -135,6 +140,7 @@ struct CSSValueInputCalcOps
|
||||
struct BasicCoordCalcOps
|
||||
{
|
||||
typedef nscoord result_type;
|
||||
typedef float coeff_type;
|
||||
|
||||
result_type
|
||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||
@ -150,7 +156,7 @@ struct BasicCoordCalcOps
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
float aValue1, result_type aValue2)
|
||||
coeff_type aValue1, result_type aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||
"unexpected unit");
|
||||
@ -159,7 +165,7 @@ struct BasicCoordCalcOps
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, float aValue2)
|
||||
result_type aValue1, coeff_type aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_R ||
|
||||
aCalcFunction == eCSSUnit_Calc_Divided,
|
||||
@ -174,6 +180,7 @@ struct BasicCoordCalcOps
|
||||
struct BasicFloatCalcOps
|
||||
{
|
||||
typedef float result_type;
|
||||
typedef float coeff_type;
|
||||
|
||||
result_type
|
||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||
@ -189,7 +196,7 @@ struct BasicFloatCalcOps
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
float aValue1, result_type aValue2)
|
||||
coeff_type aValue1, result_type aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||
"unexpected unit");
|
||||
@ -198,7 +205,7 @@ struct BasicFloatCalcOps
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, float aValue2)
|
||||
result_type aValue1, coeff_type aValue2)
|
||||
{
|
||||
if (aCalcFunction == eCSSUnit_Calc_Times_R) {
|
||||
return aValue1 * aValue2;
|
||||
@ -209,13 +216,55 @@ struct BasicFloatCalcOps
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A ComputeNumber implementation for callers that can assume numbers
|
||||
* are already normalized (i.e., anything past the parser).
|
||||
*/
|
||||
struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
|
||||
struct BasicIntegerCalcOps
|
||||
{
|
||||
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");
|
||||
return aValue.GetFloatValue();
|
||||
@ -240,7 +289,11 @@ struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
|
||||
*
|
||||
* void Append(const char* aString);
|
||||
* 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
|
||||
* 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("(");
|
||||
}
|
||||
if (unit == eCSSUnit_Calc_Times_L) {
|
||||
aOps.AppendNumber(array->Item(0));
|
||||
aOps.AppendCoefficient(array->Item(0));
|
||||
} else {
|
||||
SerializeCalcInternal(array->Item(0), aOps);
|
||||
}
|
||||
@ -344,7 +397,7 @@ SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
||||
if (unit == eCSSUnit_Calc_Times_L) {
|
||||
SerializeCalcInternal(array->Item(1), aOps);
|
||||
} else {
|
||||
aOps.AppendNumber(array->Item(1));
|
||||
aOps.AppendCoefficient(array->Item(1));
|
||||
}
|
||||
if (needParens) {
|
||||
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 mozilla
|
||||
|
@ -8148,10 +8148,14 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
|
||||
}
|
||||
if ((aVariantMask & VARIANT_CALC) &&
|
||||
IsCSSTokenCalcFunction(*tk)) {
|
||||
// calc() currently allows only lengths and percents and number inside it.
|
||||
// And note that in current implementation, number cannot be mixed with
|
||||
// length and percent.
|
||||
if (!ParseCalc(aValue, aVariantMask & VARIANT_LPN)) {
|
||||
// calc() currently allows only lengths, percents, numbers, and integers.
|
||||
//
|
||||
// Note that VARIANT_NUMBER can be mixed with VARIANT_LENGTH and
|
||||
// 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::Ok;
|
||||
@ -13638,6 +13642,9 @@ CSSParserImpl::ParseCalc(nsCSSValue &aValue, uint32_t aVariantMask)
|
||||
// This can be done without lookahead when we assume that the property
|
||||
// values cannot themselves be numbers.
|
||||
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;
|
||||
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
|
||||
// <number-multiplicative-expression> production.
|
||||
// * If aVariantMask does not contain VARIANT_NUMBER, this function
|
||||
@ -13748,9 +13740,18 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
||||
nsCSSValue *storage = &aValue;
|
||||
for (;;) {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
if (!ParseCalcTerm(*storage, variantMask))
|
||||
@ -13764,7 +13765,7 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
||||
if (variantMask & VARIANT_NUMBER) {
|
||||
// Simplify the value immediately so we can check for division by
|
||||
// zero.
|
||||
ReduceNumberCalcOps ops;
|
||||
mozilla::css::ReduceNumberCalcOps ops;
|
||||
float number = mozilla::css::ComputeCalc(*storage, ops);
|
||||
if (number == 0.0 && afterDivision)
|
||||
return false;
|
||||
@ -13778,11 +13779,17 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
||||
MOZ_ASSERT(storage == &aValue.GetArrayValue()->Item(1),
|
||||
"unexpected relationship to current storage");
|
||||
nsCSSValue &leftValue = aValue.GetArrayValue()->Item(0);
|
||||
ReduceNumberCalcOps ops;
|
||||
if (variantMask & VARIANT_INTEGER) {
|
||||
mozilla::css::ReduceIntegerCalcOps ops;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hadWS = RequireWhitespace();
|
||||
if (!GetToken(false)) {
|
||||
@ -13794,6 +13801,19 @@ CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
|
||||
unit = gotValue ? eCSSUnit_Calc_Times_R : eCSSUnit_Calc_Times_L;
|
||||
afterDivision = false;
|
||||
} 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;
|
||||
afterDivision = true;
|
||||
} else {
|
||||
@ -13853,8 +13873,16 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, uint32_t& aVariantMask)
|
||||
}
|
||||
// ... or just a value
|
||||
UngetToken();
|
||||
if (aVariantMask & VARIANT_INTEGER) {
|
||||
// Integers aren't mixed with anything else (see the assert at the
|
||||
// top of CSSParserImpl::ParseCalc).
|
||||
if (ParseVariant(aValue, aVariantMask, nullptr) != CSSParseResult::Ok) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
|
||||
// always gets picked up
|
||||
// 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;
|
||||
@ -13863,6 +13891,7 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, uint32_t& aVariantMask)
|
||||
if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If we did the value parsing, we need to adjust aVariantMask to
|
||||
// reflect which option we took (see above).
|
||||
if (aVariantMask & VARIANT_NUMBER) {
|
||||
|
@ -953,7 +953,7 @@ struct CSSValueSerializeCalcOps {
|
||||
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");
|
||||
aValue.AppendToString(mProperty, mResult, mValueSerialization);
|
||||
|
@ -327,8 +327,13 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||
RuleNodeCacheConditions& aConditions);
|
||||
|
||||
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.
|
||||
const nscoord mFontSize;
|
||||
const nsStyleFont* const mStyleFont;
|
||||
@ -667,7 +672,7 @@ nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
||||
true, false, conditions);
|
||||
}
|
||||
|
||||
struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
|
||||
struct LengthPercentPairCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
|
||||
{
|
||||
typedef nsRuleNode::ComputedCalc result_type;
|
||||
|
||||
@ -3318,8 +3323,13 @@ nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize,
|
||||
}
|
||||
|
||||
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.
|
||||
const nscoord mParentSize;
|
||||
const nsStyleFont* const mParentFont;
|
||||
@ -4449,7 +4459,7 @@ struct LineHeightCalcObj
|
||||
bool mIsNumber;
|
||||
};
|
||||
|
||||
struct SetLineHeightCalcOps : public css::NumbersAlreadyNormalizedOps
|
||||
struct SetLineHeightCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
|
||||
{
|
||||
typedef LineHeightCalcObj result_type;
|
||||
nsStyleContext* const mStyleContext;
|
||||
|
@ -478,9 +478,8 @@ PaintMaskSurface(const PaintFramesParams& aParams,
|
||||
gfxContextMatrixAutoSaveRestore matRestore(maskContext);
|
||||
|
||||
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,
|
||||
drawRect.TopLeft(),
|
||||
Point(0, 0),
|
||||
DrawOptions(1.0, compositionOp));
|
||||
}
|
||||
} else {
|
||||
@ -704,7 +703,8 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
|
||||
nsSVGUtils::MaskUsage maskUsage;
|
||||
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
|
||||
maskUsage);
|
||||
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
|
||||
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer ||
|
||||
maskUsage.shouldGenerateClipMaskLayer);
|
||||
|
||||
nsIFrame* frame = aParams.frame;
|
||||
if (!ValidateSVGFrame(frame)) {
|
||||
@ -716,25 +716,77 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
|
||||
}
|
||||
|
||||
gfxContext& ctx = aParams.ctx;
|
||||
|
||||
gfxContextMatrixAutoSaveRestore matSR(&ctx);
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
||||
bool opacityApplied = !HasNonSVGMask(maskFrames);
|
||||
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint offsetToUserSpace;
|
||||
gfxContextMatrixAutoSaveRestore matSR;
|
||||
DrawTarget* target = ctx.GetDrawTarget();
|
||||
|
||||
// Paint mask onto ctx.
|
||||
if (maskUsage.shouldGenerateMaskLayer) {
|
||||
matSR.SetContext(&ctx);
|
||||
|
||||
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, false);
|
||||
|
||||
return PaintMaskSurface(aParams, ctx.GetDrawTarget(),
|
||||
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
|
||||
@ -828,15 +880,15 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
||||
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, false);
|
||||
Matrix clippedMaskTransform;
|
||||
Matrix clipMaskTransform;
|
||||
RefPtr<SourceSurface> clipMaskSurface =
|
||||
clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
|
||||
&clippedMaskTransform, maskSurface,
|
||||
&clipMaskTransform, maskSurface,
|
||||
maskTransform, &result);
|
||||
|
||||
if (clipMaskSurface) {
|
||||
maskSurface = clipMaskSurface;
|
||||
maskTransform = clippedMaskTransform;
|
||||
maskTransform = clipMaskTransform;
|
||||
} else {
|
||||
// Either entire surface is clipped out, or gfx buffer allocation
|
||||
// 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'].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
|
||||
#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/SipccSdpParser.h"
|
||||
@ -30,19 +25,17 @@
|
||||
#include "signaling/src/jsep/JsepSessionImpl.h"
|
||||
#include "signaling/src/jsep/JsepTrack.h"
|
||||
|
||||
#include "mtransport_test_utils.h"
|
||||
|
||||
#include "FakeIPC.h"
|
||||
#include "FakeIPC.cpp"
|
||||
|
||||
#include "TestHarness.h"
|
||||
|
||||
namespace mozilla {
|
||||
static std::string kAEqualsCandidate("a=candidate:");
|
||||
const static size_t kNumCandidatesPerComponent = 3;
|
||||
|
||||
class JsepSessionTestBase : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase() {
|
||||
NSS_NoDB_Init(nullptr);
|
||||
NSS_SetDomesticPolicy();
|
||||
}
|
||||
};
|
||||
|
||||
class FakeUuidGenerator : public mozilla::JsepUuidGenerator
|
||||
@ -4220,16 +4213,3 @@ TEST_F(JsepSessionTest, TestNonDefaultProtocol)
|
||||
}
|
||||
|
||||
} // 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
|
||||
#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/sdp/SipccSdp.h"
|
||||
#include "signaling/src/sdp/SdpHelper.h"
|
||||
|
||||
#include "mtransport_test_utils.h"
|
||||
|
||||
#include "FakeIPC.h"
|
||||
#include "FakeIPC.cpp"
|
||||
|
||||
#include "TestHarness.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class JsepTrackTest : public ::testing::Test
|
||||
@ -1256,14 +1243,3 @@ TEST_F(JsepTrackTest, NonDefaultOpusParameters)
|
||||
}
|
||||
|
||||
} // 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 += [
|
||||
'jsep_session_unittest.cpp',
|
||||
'jsep_track_unittest.cpp',
|
||||
'sdp_unittests.cpp',
|
||||
]
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
# 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':
|
||||
GeckoCppUnitTests([
|
||||
'jsep_session_unittest',
|
||||
'jsep_track_unittest',
|
||||
'mediaconduit_unittests',
|
||||
'mediapipeline_unittest',
|
||||
'signaling_unittests',
|
||||
|
@ -13,7 +13,7 @@ import org.mozilla.gecko.media.Sample;
|
||||
|
||||
interface ICodec {
|
||||
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 stop();
|
||||
oneway void flush();
|
||||
|
@ -200,7 +200,7 @@ public class HomeAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
// Override top_sites with ActivityStream panel when enabled
|
||||
// PanelType.toString() returns the panel id
|
||||
if (type.toString() == "top_sites" &&
|
||||
if ("top_sites".equals(type.toString()) &&
|
||||
ActivityStream.isEnabled(context) &&
|
||||
ActivityStream.isHomePanel()) {
|
||||
return ActivityStreamHomeFragment.class.getName();
|
||||
|
@ -126,10 +126,11 @@ public class JavaAddonManagerV1 implements NativeEventListener {
|
||||
if (dispatcher == null) {
|
||||
Log.w(LOGTAG, "Attempting to unload addon with unknown associated dispatcher; ignoring.");
|
||||
callback.sendSuccess(false);
|
||||
}
|
||||
} else {
|
||||
dispatcher.unregisterAllEventListeners();
|
||||
callback.sendSuccess(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -5,6 +5,8 @@
|
||||
package org.mozilla.gecko.media;
|
||||
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.media.MediaCodec.CryptoInfo;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Handler;
|
||||
import android.view.Surface;
|
||||
@ -22,7 +24,7 @@ public interface AsyncCodec {
|
||||
}
|
||||
|
||||
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 stop();
|
||||
public abstract void flush();
|
||||
@ -30,5 +32,6 @@ public interface AsyncCodec {
|
||||
public abstract ByteBuffer getInputBuffer(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 queueSecureInputBuffer(int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
|
||||
public abstract void releaseOutputBuffer(int index, boolean render);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.media;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@ -167,6 +168,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
Sample sample = mInputSamples.poll();
|
||||
long pts = sample.info.presentationTimeUs;
|
||||
int flags = sample.info.flags;
|
||||
MediaCodec.CryptoInfo cryptoInfo = sample.cryptoInfo;
|
||||
if (!sample.isEOS() && sample.buffer != null) {
|
||||
len = sample.info.size;
|
||||
ByteBuffer buf = mCodec.getInputBuffer(index);
|
||||
@ -180,9 +182,14 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
}
|
||||
mSamplePool.recycleInput(sample);
|
||||
}
|
||||
|
||||
if (cryptoInfo != null) {
|
||||
mCodec.queueSecureInputBuffer(index, 0, cryptoInfo, pts, flags);
|
||||
} else {
|
||||
mCodec.queueInputBuffer(index, 0, len, pts, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void reset() {
|
||||
mInputSamples.clear();
|
||||
@ -214,7 +221,10 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
}
|
||||
|
||||
@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) {
|
||||
Log.e(LOGTAG, "FAIL: callbacks must be set before calling configure()");
|
||||
return false;
|
||||
@ -236,8 +246,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
try {
|
||||
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.configure(fmt, surface, flags);
|
||||
codec.configure(fmt, surface, crypto, flags);
|
||||
mCodec = codec;
|
||||
mInputProcessor = new InputProcessor();
|
||||
mSamplePool = new SamplePool(codecName);
|
||||
|
@ -28,6 +28,7 @@ public final class CodecProxy {
|
||||
private FormatParam mFormat;
|
||||
private Surface mOutputSurface;
|
||||
private CallbacksForwarder mCallbacks;
|
||||
private String mRemoteDrmStubId;
|
||||
|
||||
public interface Callbacks {
|
||||
void onInputExhausted();
|
||||
@ -82,24 +83,31 @@ public final class CodecProxy {
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
public static CodecProxy create(MediaFormat format, Surface surface, Callbacks callbacks) {
|
||||
return RemoteManager.getInstance().createCodec(format, surface, callbacks);
|
||||
public static CodecProxy create(MediaFormat format,
|
||||
Surface surface,
|
||||
Callbacks callbacks,
|
||||
String drmStubId) {
|
||||
return RemoteManager.getInstance().createCodec(format, surface, callbacks, drmStubId);
|
||||
}
|
||||
|
||||
public static CodecProxy createCodecProxy(MediaFormat format, Surface surface, Callbacks callbacks) {
|
||||
return new CodecProxy(format, surface, callbacks);
|
||||
public static CodecProxy createCodecProxy(MediaFormat format,
|
||||
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);
|
||||
mOutputSurface = surface;
|
||||
mRemoteDrmStubId = drmStubId;
|
||||
mCallbacks = new CallbacksForwarder(callbacks);
|
||||
}
|
||||
|
||||
boolean init(ICodec remote) {
|
||||
try {
|
||||
remote.setCallbacks(mCallbacks);
|
||||
remote.configure(mFormat, mOutputSurface, 0);
|
||||
remote.configure(mFormat, mOutputSurface, 0, mRemoteDrmStubId);
|
||||
remote.start();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
@ -128,7 +136,6 @@ public final class CodecProxy {
|
||||
Log.e(LOGTAG, "cannot send input to an ended codec");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
||||
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.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.media.DeniedByServerException;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaCryptoException;
|
||||
import android.media.MediaDrm;
|
||||
import android.media.MediaDrmException;
|
||||
import android.media.NotProvisionedException;
|
||||
import android.util.Log;
|
||||
|
||||
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 WIDEVINE_KEY_SYSTEM = "com.widevine.alpha";
|
||||
private static final boolean DEBUG = false;
|
||||
@ -98,7 +100,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
}
|
||||
|
||||
GeckoMediaDrmBridgeV21(String keySystem) throws Exception {
|
||||
if (DEBUG) Log.d(LOGTAG, "GeckoMediaDrmBridgeV21()");
|
||||
LOGTAG = getClass().getSimpleName();
|
||||
if (DEBUG) Log.d(LOGTAG, "GeckoMediaDrmBridgeV21 ctor");
|
||||
|
||||
mProvisioningPromiseId = 0;
|
||||
mSessionIds = new HashSet<ByteBuffer>();
|
||||
@ -142,7 +145,6 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
}
|
||||
|
||||
ByteBuffer sessionId = null;
|
||||
String strSessionId = null;
|
||||
try {
|
||||
boolean hasMediaCrypto = ensureMediaCryptoCreated();
|
||||
if (!hasMediaCrypto) {
|
||||
@ -170,9 +172,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
LICENSE_REQUEST_INITIAL,
|
||||
request.getData());
|
||||
mSessionMIMETypes.put(sessionId, initDataType);
|
||||
strSessionId = new String(sessionId.array());
|
||||
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) {
|
||||
if (DEBUG) Log.d(LOGTAG, "Device not provisioned:" + e.getMessage());
|
||||
if (sessionId != null) {
|
||||
@ -218,18 +219,10 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
if (DEBUG) Log.d(LOGTAG, "Key successfully added for session " + sessionId);
|
||||
onSessionUpdated(promiseId, session.array());
|
||||
return;
|
||||
} catch (android.media.NotProvisionedException e) {
|
||||
if (DEBUG) Log.d(LOGTAG, "Failed to provide key response:" + e.getMessage());
|
||||
onSessionError(session.array(), "Got NotProvisionedException.");
|
||||
onRejectPromise(promiseId, "Not provisioned 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.");
|
||||
} 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;
|
||||
@ -371,7 +364,6 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
}
|
||||
// On L, these events are treated as exceptions and handled correspondingly.
|
||||
// Leaving this code block for logging message.
|
||||
String sessionId = new String(session.array());
|
||||
switch (event) {
|
||||
case 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.
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
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 (DEBUG) Log.d(LOGTAG, "Session doesn't exist because media crypto session is not created.");
|
||||
return false;
|
||||
@ -592,9 +584,8 @@ public class GeckoMediaDrmBridgeV21 implements GeckoMediaDrm {
|
||||
if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
|
||||
final byte [] cryptoSessionId = mCryptoSessionId.array();
|
||||
mCrypto = new MediaCrypto(mSchemeUUID, cryptoSessionId);
|
||||
String strCryptoSessionId = new String(cryptoSessionId);
|
||||
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;
|
||||
} else {
|
||||
if (DEBUG) Log.d(LOGTAG, "Cannot create MediaCrypto for unsupported scheme.");
|
||||
|
@ -5,14 +5,18 @@
|
||||
package org.mozilla.gecko.media;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.DeniedByServerException;
|
||||
import android.media.NotProvisionedException;
|
||||
|
||||
import static android.os.Build.VERSION_CODES.M;
|
||||
import android.media.MediaDrm;
|
||||
import android.util.Log;
|
||||
import java.lang.IllegalStateException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class GeckoMediaDrmBridgeV23 extends GeckoMediaDrmBridgeV21 {
|
||||
|
||||
private static final String LOGTAG = "GeckoMediaDrmBridgeV23";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
GeckoMediaDrmBridgeV23(String keySystem) throws Exception {
|
||||
@ -39,6 +43,43 @@ public class GeckoMediaDrmBridgeV23 extends GeckoMediaDrmBridgeV21 {
|
||||
keyStatus.getStatusCode());
|
||||
}
|
||||
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;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
@ -294,10 +295,10 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(MediaFormat format, Surface surface, int flags) {
|
||||
public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags) {
|
||||
assertCallbacks();
|
||||
|
||||
mCodec.configure(format, surface, null, flags);
|
||||
mCodec.configure(format, surface, crypto, flags);
|
||||
}
|
||||
|
||||
private void assertCallbacks() {
|
||||
@ -336,6 +337,28 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
|
||||
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
|
||||
public final void releaseOutputBuffer(int index, boolean render) {
|
||||
assertCallbacks();
|
||||
|
@ -39,10 +39,12 @@ public final class MediaDrmProxy {
|
||||
@WrapForJNI
|
||||
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.
|
||||
private boolean mDestroyed;
|
||||
private GeckoMediaDrm mImpl;
|
||||
public static ArrayList<MediaDrmProxy> mProxyList = new ArrayList<MediaDrmProxy>();
|
||||
private String mDrmStubId;
|
||||
|
||||
private static boolean isSystemSupported() {
|
||||
// Support versions >= LOLLIPOP
|
||||
@ -250,19 +252,26 @@ public final class MediaDrmProxy {
|
||||
public static MediaDrmProxy create(String keySystem,
|
||||
Callbacks nativeCallbacks,
|
||||
boolean isRemote) {
|
||||
// TODO: Will implement {Local,Remote}MediaDrmBridge instantiation by
|
||||
// '''isRemote''' flag in Bug 1307818.
|
||||
MediaDrmProxy proxy = new MediaDrmProxy(keySystem, nativeCallbacks);
|
||||
MediaDrmProxy proxy = new MediaDrmProxy(keySystem, nativeCallbacks, isRemote);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
MediaDrmProxy(String keySystem, Callbacks nativeCallbacks) {
|
||||
MediaDrmProxy(String keySystem, Callbacks nativeCallbacks, boolean isRemote) {
|
||||
if (DEBUG) Log.d(LOGTAG, "Constructing MediaDrmProxy");
|
||||
// TODO: Bug 1306185 will implement the LocalMediaDrmBridge as an impl
|
||||
// of GeckoMediaDrm for in-process decoding mode.
|
||||
//mImpl = new LocalMediaDrmBridge(keySystem);
|
||||
try {
|
||||
mDrmStubId = UUID.randomUUID().toString();
|
||||
if (isRemote) {
|
||||
IMediaDrmBridge remoteBridge =
|
||||
RemoteManager.getInstance().createRemoteMediaDrmBridge(keySystem, mDrmStubId);
|
||||
mImpl = new RemoteMediaDrmBridge(remoteBridge);
|
||||
} else {
|
||||
mImpl = new LocalMediaDrmBridge(keySystem);
|
||||
}
|
||||
mImpl.setCallbacks(new MediaDrmProxyCallbacks(this, nativeCallbacks));
|
||||
mProxyList.add(this);
|
||||
sProxyList.add(this);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Constructing MediaDrmProxy ... error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
@ -289,6 +298,24 @@ public final class MediaDrmProxy {
|
||||
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.
|
||||
private void destroy() {
|
||||
if (DEBUG) Log.d(LOGTAG, "destroy!! Native object is destroyed.");
|
||||
@ -301,7 +328,11 @@ public final class MediaDrmProxy {
|
||||
|
||||
private void release() {
|
||||
if (DEBUG) Log.d(LOGTAG, "release");
|
||||
mProxyList.remove(this);
|
||||
sProxyList.remove(this);
|
||||
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,
|
||||
Surface surface,
|
||||
CodecProxy.Callbacks callbacks) {
|
||||
CodecProxy.Callbacks callbacks,
|
||||
String drmStubId) {
|
||||
if (mRemote == null) {
|
||||
if (DEBUG) Log.d(LOGTAG, "createCodec failed due to not initialize");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
ICodec remote = mRemote.createCodec();
|
||||
CodecProxy proxy = CodecProxy.createCodecProxy(format, surface, callbacks);
|
||||
CodecProxy proxy = CodecProxy.createCodecProxy(format, surface, callbacks, drmStubId);
|
||||
if (proxy.init(remote)) {
|
||||
mProxies.add(proxy);
|
||||
return proxy;
|
||||
|
@ -892,10 +892,15 @@ var BrowserApp = {
|
||||
NativeWindow.contextmenus.add(
|
||||
function(aTarget) {
|
||||
if (aTarget instanceof HTMLVideoElement) {
|
||||
if (aTarget.readyState == aTarget.HAVE_NOTHING) {
|
||||
// We don't know if the height/width of the video,
|
||||
// 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.
|
||||
if (aTarget.videoWidth == 0 || aTarget.videoHeight == 0 )
|
||||
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
||||
}
|
||||
return Strings.browser.GetStringFromName("contextmenu.saveVideo");
|
||||
} else if (aTarget instanceof HTMLAudioElement) {
|
||||
return Strings.browser.GetStringFromName("contextmenu.saveAudio");
|
||||
@ -907,9 +912,19 @@ var BrowserApp = {
|
||||
UITelemetry.addEvent("save.1", "contextmenu", null, "media");
|
||||
|
||||
let url = aTarget.currentSrc || aTarget.src;
|
||||
let filePickerTitleKey = (aTarget instanceof HTMLVideoElement &&
|
||||
(aTarget.videoWidth != 0 && aTarget.videoHeight != 0))
|
||||
? "SaveVideoTitle" : "SaveAudioTitle";
|
||||
|
||||
let filePickerTitleKey;
|
||||
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
|
||||
ContentAreaUtils.internalSave(url, null, null, null, null, false,
|
||||
filePickerTitleKey, null, aTarget.ownerDocument.documentURIObject,
|
||||
|
@ -279,6 +279,10 @@ contextmenu.mute=Mute
|
||||
contextmenu.unmute=Unmute
|
||||
contextmenu.saveVideo=Save Video
|
||||
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
|
||||
# LOCALIZATION NOTE (contextmenu.sendToDevice):
|
||||
# The label that will be used in the contextmenu and the pageaction
|
||||
|
@ -61,7 +61,7 @@ body {
|
||||
}
|
||||
|
||||
#filter-input::placeholder {
|
||||
color: rgba(255,255,255,0.5);
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
.toolbar input {
|
||||
|
@ -1111,10 +1111,7 @@ pref("print.print_edge_right", 0);
|
||||
pref("print.print_edge_bottom", 0);
|
||||
|
||||
// Print via the parent process. This is only used when e10s is enabled.
|
||||
// For Mac, limit to Nightly.
|
||||
#if defined(XP_WIN)
|
||||
pref("print.print_via_parent", true);
|
||||
#elif defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
pref("print.print_via_parent", true);
|
||||
#else
|
||||
pref("print.print_via_parent", false);
|
||||
|
@ -1535,10 +1535,6 @@ VARIABLES = {
|
||||
"""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,
|
||||
"""List of manifest files defining marionette-webapi tests.
|
||||
"""),
|
||||
|
@ -135,8 +135,6 @@ ALLOWED_XPCOM_GLUE = {
|
||||
('test_unlock_notify', 'storage/test'),
|
||||
('test_IHistory', 'toolkit/components/places/tests/cpp'),
|
||||
('testcrasher', 'toolkit/crashreporter/test'),
|
||||
('jsep_session_unittest', 'media/webrtc/signaling/test'),
|
||||
('jsep_track_unittest', 'media/webrtc/signaling/test'),
|
||||
('mediaconduit_unittests', 'media/webrtc/signaling/test'),
|
||||
('mediapipeline_unittest', 'media/webrtc/signaling/test'),
|
||||
('sdp_file_parser', 'media/webrtc/signaling/fuzztest'),
|
||||
|
@ -287,7 +287,6 @@ TEST_MANIFESTS = dict(
|
||||
# TODO(ato): make packaging work as for other test suites
|
||||
MARIONETTE=('marionette', 'marionette', '.', False),
|
||||
MARIONETTE_UNIT=('marionette', 'marionette', '.', False),
|
||||
MARIONETTE_UPDATE=('marionette', 'marionette', '.', False),
|
||||
MARIONETTE_WEBAPI=('marionette', 'marionette', '.', False),
|
||||
|
||||
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
|
||||
|
@ -22,6 +22,7 @@ import struct
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import buildconfig
|
||||
from collections import OrderedDict
|
||||
|
||||
# Regular expressions for unifying install.rdf
|
||||
@ -80,7 +81,8 @@ class UnifiedExecutableFile(BaseFile):
|
||||
os.close(fd)
|
||||
tmpfiles.append(f)
|
||||
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:
|
||||
for f in tmpfiles:
|
||||
os.unlink(f)
|
||||
|
@ -44,3 +44,27 @@ macosx64/opt:
|
||||
script: "mozharness/scripts/fx_desktop_build.py"
|
||||
secrets: true
|
||||
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