зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
a09b58856d
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1472845813000">
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1474644720000">
|
||||
<emItems>
|
||||
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
|
@ -12,12 +12,6 @@
|
|||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i1229" id="/^(.*@(unblocker\.yt|sparpilot\.com))|axtara@axtara\.com$/">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
|
@ -158,6 +152,12 @@
|
|||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i1229" id="/^(.*@(unblocker\.yt|sparpilot\.com))|(axtara@axtara\.com)$/">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||
</versionRange>
|
||||
<prefs>
|
||||
</prefs>
|
||||
</emItem>
|
||||
<emItem blockID="i5" id="support@daemon-tools.cc">
|
||||
<versionRange minVersion=" " maxVersion="1.0.0.5">
|
||||
|
@ -3612,6 +3612,18 @@
|
|||
<match name="filename" exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="21.0.0.242" maxVersion="22.0.0.192" severity="0" vulnerabilitystatus="1"></versionRange>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
</pluginItem>
|
||||
<pluginItem os="Linux" blockID="p1272">
|
||||
<match name="filename" exp="libflashplayer\.so" /> <versionRange minVersion="11.2.202.626" maxVersion="11.2.202.632" severity="0" vulnerabilitystatus="1"></versionRange>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1273">
|
||||
<match name="filename" exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="18.0.0.360" maxVersion="18.0.0.366" severity="0" vulnerabilitystatus="1"></versionRange>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1274">
|
||||
<match name="filename" exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" /> <versionRange minVersion="22.0.0.192" maxVersion="22.0.0.211" severity="0" vulnerabilitystatus="1"></versionRange>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
</pluginItem>
|
||||
</pluginItems>
|
||||
|
||||
<gfxItems>
|
||||
|
|
|
@ -1361,7 +1361,11 @@ pref("media.gmp.trial-create.enabled", true);
|
|||
|
||||
#ifdef MOZ_ADOBE_EME
|
||||
pref("media.gmp-eme-adobe.visible", true);
|
||||
pref("media.gmp-eme-adobe.enabled", true);
|
||||
// When Adobe EME is enabled in the build system, we don't actually enable
|
||||
// the plugin by default, so that it doesn't download and install by default.
|
||||
// When Adobe EME is first used, Firefox will prompt the user to enable it,
|
||||
// and then download the CDM.
|
||||
pref("media.gmp-eme-adobe.enabled", false);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDEVINE_EME
|
||||
|
|
|
@ -345,13 +345,6 @@ var gFxAccounts = {
|
|||
},
|
||||
|
||||
openAccountsPage: function (action, urlParams={}) {
|
||||
// An entrypoint param is used for server-side metrics. If the current tab
|
||||
// is UITour, assume that it initiated the call to this method and override
|
||||
// the entrypoint accordingly.
|
||||
if (UITour.tourBrowsersByWindow.get(window) &&
|
||||
UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
|
||||
urlParams.entrypoint = "uitour";
|
||||
}
|
||||
let params = new URLSearchParams();
|
||||
if (action) {
|
||||
params.set("action", action);
|
||||
|
|
|
@ -290,11 +290,6 @@ var gSyncUI = {
|
|||
|
||||
openSetup: function SUI_openSetup(wizardType, entryPoint = "syncbutton") {
|
||||
if (this.weaveService.fxAccountsEnabled) {
|
||||
// If the user is also in an uitour, set the entrypoint to `uitour`
|
||||
if (UITour.tourBrowsersByWindow.get(window) &&
|
||||
UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
|
||||
entryPoint = "uitour";
|
||||
}
|
||||
this.openPrefs(entryPoint);
|
||||
} else {
|
||||
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
|
||||
|
|
|
@ -119,9 +119,6 @@ function* asyncCleanup() {
|
|||
// When Sync is not setup.
|
||||
add_task(() => openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "synced-tabs"));
|
||||
add_task(asyncCleanup);
|
||||
// Test that uitour is in progress, the entrypoint is `uitour` and not `menupanel`
|
||||
add_task(() => openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "uitour"));
|
||||
add_task(asyncCleanup);
|
||||
|
||||
// When Sync is configured in a "needs reauthentication" state.
|
||||
add_task(function* () {
|
||||
|
|
|
@ -13,4 +13,5 @@ EXTRA_COMPONENTS += [
|
|||
DIRS += ['schemas']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
{
|
||||
"namespace": "commands",
|
||||
"description": "Use the commands API to add keyboard shortcuts that trigger actions in your extension, for example, an action to open the browser action or send a command to the xtension.",
|
||||
"permissions": ["manifest:commands"],
|
||||
"types": [
|
||||
{
|
||||
"id": "Command",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js
|
||||
tags = webextensions
|
||||
|
||||
[test_ext_all_apis.html]
|
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
/* exported expectedContentApisTargetSpecific, expectedBackgroundApisTargetSpecific */
|
||||
let expectedContentApisTargetSpecific = [
|
||||
];
|
||||
|
||||
let expectedBackgroundApisTargetSpecific = [
|
||||
"tabs.MutedInfoReason",
|
||||
"tabs.TAB_ID_NONE",
|
||||
"tabs.TabStatus",
|
||||
"tabs.WindowType",
|
||||
"tabs.ZoomSettingsMode",
|
||||
"tabs.ZoomSettingsScope",
|
||||
"tabs.connect",
|
||||
"tabs.create",
|
||||
"tabs.detectLanguage",
|
||||
"tabs.duplicate",
|
||||
"tabs.executeScript",
|
||||
"tabs.get",
|
||||
"tabs.getCurrent",
|
||||
"tabs.getZoom",
|
||||
"tabs.getZoomSettings",
|
||||
"tabs.highlight",
|
||||
"tabs.insertCSS",
|
||||
"tabs.move",
|
||||
"tabs.onActivated",
|
||||
"tabs.onAttached",
|
||||
"tabs.onCreated",
|
||||
"tabs.onDetached",
|
||||
"tabs.onHighlighted",
|
||||
"tabs.onMoved",
|
||||
"tabs.onRemoved",
|
||||
"tabs.onReplaced",
|
||||
"tabs.onUpdated",
|
||||
"tabs.onZoomChange",
|
||||
"tabs.query",
|
||||
"tabs.reload",
|
||||
"tabs.remove",
|
||||
"tabs.removeCSS",
|
||||
"tabs.sendMessage",
|
||||
"tabs.setZoom",
|
||||
"tabs.setZoomSettings",
|
||||
"tabs.update",
|
||||
"windows.CreateType",
|
||||
"windows.WINDOW_ID_CURRENT",
|
||||
"windows.WINDOW_ID_NONE",
|
||||
"windows.WindowState",
|
||||
"windows.WindowType",
|
||||
"windows.create",
|
||||
"windows.get",
|
||||
"windows.getAll",
|
||||
"windows.getCurrent",
|
||||
"windows.getLastFocused",
|
||||
"windows.onCreated",
|
||||
"windows.onFocusChanged",
|
||||
"windows.onRemoved",
|
||||
"windows.remove",
|
||||
"windows.update",
|
||||
];
|
||||
</script>
|
||||
<script src="test_ext_all_apis.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -132,8 +132,7 @@
|
|||
</columns>
|
||||
<rows>
|
||||
<row align="center">
|
||||
<label accesskey="&syncDeviceName.accesskey;"
|
||||
control="syncComputerName">
|
||||
<label control="syncComputerName">
|
||||
&syncDeviceName.label;
|
||||
</label>
|
||||
<textbox id="syncComputerName"/>
|
||||
|
@ -185,9 +184,9 @@
|
|||
</vbox>
|
||||
<vbox flex="1">
|
||||
<label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="noFxaSignUp" label="&signedOut.accountBox.create;"></button>
|
||||
<button id="noFxaSignIn" label="&signedOut.accountBox.signin;"></button>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="noFxaSignUp" label="&signedOut.accountBox.create;" accesskey="&signedOut.accountBox.create.accesskey;"></button>
|
||||
<button id="noFxaSignIn" label="&signedOut.accountBox.signin;" accesskey="&signedOut.accountBox.signin.accesskey;"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -230,11 +229,12 @@
|
|||
<vbox flex="1" pack="center">
|
||||
<label id="fxaDisplayName" hidden="true"/>
|
||||
<label id="fxaEmailAddress1"/>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;"/>
|
||||
<label id="verifiedManage" class="text-link"
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;" accesskey="&disconnect.label.accesskey;"/>
|
||||
<html:a id="verifiedManage" target="_blank"
|
||||
accesskey="&verifiedManage.label.accesskey;"
|
||||
onkeypress="gSyncPane.openManageFirefoxAccount(event);"><!--
|
||||
-->&verifiedManage.label;</label>
|
||||
-->&verifiedManage.label;</html:a>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -253,9 +253,9 @@
|
|||
&signedInUnverified.aftername.label;
|
||||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="verifyFxaAccount">&verify.label;</button>
|
||||
<button id="unverifiedUnlinkFxaAccount">&forget.label;</button>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="verifyFxaAccount" accesskey="&verify.label.accesskey;">&verify.label;</button>
|
||||
<button id="unverifiedUnlinkFxaAccount" accesskey="&forget.label.accesskey;">&forget.label;</button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -274,9 +274,9 @@
|
|||
&signedInLoginFailure.aftername.label;
|
||||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons" align="center">
|
||||
<button id="rejectReSignIn">&signIn.label;</button>
|
||||
<button id="rejectUnlinkFxaAccount">&forget.label;</button>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="rejectReSignIn" accessky="&signIn.label.accesskey;">&signIn.label;</button>
|
||||
<button id="rejectUnlinkFxaAccount" accesskey="&rejectUnlinkFxaAccount.forget.label.accesskey;">&forget.label;</button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -317,8 +317,7 @@
|
|||
</hbox>
|
||||
<groupbox>
|
||||
<caption>
|
||||
<label accesskey="&syncDeviceName.accesskey;"
|
||||
control="fxaSyncComputerName">
|
||||
<label control="fxaSyncComputerName">
|
||||
&fxaSyncDeviceName.label;
|
||||
</label>
|
||||
</caption>
|
||||
|
@ -326,12 +325,15 @@
|
|||
<textbox id="fxaSyncComputerName" disabled="true"/>
|
||||
<hbox>
|
||||
<button id="fxaChangeDeviceName"
|
||||
label="&changeSyncDeviceName.label;"/>
|
||||
label="&changeSyncDeviceName.label;"
|
||||
accesskey="&changeSyncDeviceName.label.accesskey;"/>
|
||||
<button id="fxaCancelChangeDeviceName"
|
||||
label="&cancelChangeSyncDeviceName.label;"
|
||||
accesskey="&cancelChangeSyncDeviceName.label.accesskey;"
|
||||
hidden="true"/>
|
||||
<button id="fxaSaveChangeDeviceName"
|
||||
label="&saveChangeSyncDeviceName.label;"
|
||||
accesskey="&saveChangeSyncDeviceName.label.accesskey;"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
|
|
@ -38,11 +38,13 @@
|
|||
|
||||
<!-- Device Settings -->
|
||||
<!ENTITY syncDeviceName.label "Device Name:">
|
||||
<!ENTITY syncDeviceName.accesskey "c">
|
||||
<!ENTITY fxaSyncDeviceName.label "Device Name">
|
||||
<!ENTITY changeSyncDeviceName.label "Change Device Name…">
|
||||
<!ENTITY changeSyncDeviceName.label.accesskey "h">
|
||||
<!ENTITY cancelChangeSyncDeviceName.label "Cancel">
|
||||
<!ENTITY cancelChangeSyncDeviceName.label.accesskey "n">
|
||||
<!ENTITY saveChangeSyncDeviceName.label "Save">
|
||||
<!ENTITY saveChangeSyncDeviceName.label.accesskey "v">
|
||||
<!ENTITY unlinkDevice.label "Unlink This Device">
|
||||
|
||||
<!-- Footer stuff -->
|
||||
|
@ -71,11 +73,17 @@ both, to better adapt this sentence to their language.
|
|||
|
||||
<!ENTITY notSignedIn.label "You are not signed in.">
|
||||
<!ENTITY signIn.label "Sign in">
|
||||
<!ENTITY signIn.label.accesskey "g">
|
||||
<!ENTITY profilePicture.tooltip "Change profile picture">
|
||||
<!ENTITY verifiedManage.label "Manage Account">
|
||||
<!ENTITY verifiedManage.label.accesskey "o">
|
||||
<!ENTITY disconnect.label "Disconnect…">
|
||||
<!ENTITY disconnect.label.accesskey "D">
|
||||
<!ENTITY verify.label "Verify Email">
|
||||
<!ENTITY verify.label.accesskey "V">
|
||||
<!ENTITY forget.label "Forget this Email">
|
||||
<!ENTITY forget.label.accesskey "F">
|
||||
<!ENTITY rejectUnlinkFxaAccount.forget.label.accesskey "e">
|
||||
|
||||
<!ENTITY welcome.description "Access your tabs, bookmarks, passwords and more wherever you use &brandShortName;.">
|
||||
<!ENTITY welcome.signIn.label "Sign In">
|
||||
|
@ -87,7 +95,9 @@ both, to better adapt this sentence to their language.
|
|||
<!ENTITY signedOut.description "Synchronize your bookmarks, history, tabs, passwords, add-ons, and preferences across all your devices.">
|
||||
<!ENTITY signedOut.accountBox.title "Connect with a &syncBrand.fxAccount.label;">
|
||||
<!ENTITY signedOut.accountBox.create "Create Account">
|
||||
<!ENTITY signedOut.accountBox.create.accesskey "C">
|
||||
<!ENTITY signedOut.accountBox.signin "Sign In">
|
||||
<!ENTITY signedOut.accountBox.signin.accesskey "I">
|
||||
|
||||
<!ENTITY signedIn.engines.label "Sync across all devices">
|
||||
|
||||
|
|
|
@ -353,6 +353,10 @@ this.UnsubmittedCrashHandler = {
|
|||
Services.prefs.getBranch("browser.crashReports.unsubmittedCheck.");
|
||||
},
|
||||
|
||||
get enabled() {
|
||||
return this.prefs.getBoolPref("enabled");
|
||||
},
|
||||
|
||||
// showingNotification is set to true once a notification
|
||||
// is successfully shown, and then set back to false if
|
||||
// the notification is dismissed by an action by the user.
|
||||
|
@ -371,9 +375,12 @@ this.UnsubmittedCrashHandler = {
|
|||
|
||||
this.initialized = true;
|
||||
|
||||
let shouldCheck = this.prefs.getBoolPref("enabled");
|
||||
|
||||
if (shouldCheck) {
|
||||
// UnsubmittedCrashHandler can be initialized but still be disabled.
|
||||
// This is intentional, as this makes simulating UnsubmittedCrashHandler's
|
||||
// reactions to browser startup and shutdown easier in test automation.
|
||||
//
|
||||
// UnsubmittedCrashHandler, when initialized but not enabled, is inert.
|
||||
if (this.enabled) {
|
||||
if (this.prefs.prefHasUserValue("suppressUntilDate")) {
|
||||
if (this.prefs.getCharPref("suppressUntilDate") > this.dateString()) {
|
||||
// We'll be suppressing any notifications until after suppressedDate,
|
||||
|
@ -400,6 +407,10 @@ this.UnsubmittedCrashHandler = {
|
|||
|
||||
this.initialized = false;
|
||||
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.suppressed) {
|
||||
this.suppressed = false;
|
||||
// No need to do any more clean-up, since we were suppressed.
|
||||
|
|
|
@ -198,11 +198,20 @@ add_task(function* setup() {
|
|||
let oldServerURL = env.get("MOZ_CRASHREPORTER_URL");
|
||||
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
||||
|
||||
// nsBrowserGlue starts up UnsubmittedCrashHandler automatically
|
||||
// so at this point, it is initialized. It's possible that it
|
||||
// was initialized, but is preffed off, so it's inert, so we
|
||||
// shut it down, make sure it's preffed on, and then restart it.
|
||||
// Note that making the component initialize even when it's
|
||||
// disabled is an intentional choice, as this allows for easier
|
||||
// simulation of startup and shutdown.
|
||||
UnsubmittedCrashHandler.uninit();
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.crashReports.unsubmittedCheck.enabled", true],
|
||||
],
|
||||
});
|
||||
UnsubmittedCrashHandler.init();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gNotificationBox = null;
|
||||
|
|
|
@ -409,8 +409,12 @@ function prompt(aBrowser, aRequest) {
|
|||
if ((!audioDevices.length || micPerm) && (!videoDevices.length || camPerm)) {
|
||||
// All permissions we were about to request are already persistently set.
|
||||
let allowedDevices = [];
|
||||
if (videoDevices.length && camPerm == perms.ALLOW_ACTION)
|
||||
if (videoDevices.length && camPerm == perms.ALLOW_ACTION) {
|
||||
allowedDevices.push(videoDevices[0].deviceIndex);
|
||||
let perms = Services.perms;
|
||||
perms.add(uri, "MediaManagerVideo", perms.ALLOW_ACTION,
|
||||
perms.EXPIRE_SESSION);
|
||||
}
|
||||
if (audioDevices.length && micPerm == perms.ALLOW_ACTION)
|
||||
allowedDevices.push(audioDevices[0].deviceIndex);
|
||||
|
||||
|
|
|
@ -497,6 +497,8 @@ description > html|a {
|
|||
.fxaAccountBoxButtons {
|
||||
margin-bottom: 0 !important;
|
||||
margin-top: 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fxaAccountBoxButtons > * {
|
||||
|
|
|
@ -33,7 +33,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
classpath 'com.android.tools.build:gradle:2.1.3'
|
||||
classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.4') {
|
||||
// Without these, we get errors linting.
|
||||
exclude module: 'guava'
|
||||
|
|
|
@ -423,6 +423,16 @@ InspectorPanel.prototype = {
|
|||
return this._InspectorTabPanel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the inspector should use the landscape mode.
|
||||
*
|
||||
* @return {Boolean} true if the inspector should be in landscape mode.
|
||||
*/
|
||||
useLandscapeMode: function () {
|
||||
let { clientWidth } = this.panelDoc.getElementById("inspector-splitter-box");
|
||||
return clientWidth > PORTRAIT_MODE_WIDTH;
|
||||
},
|
||||
|
||||
/**
|
||||
* Build Splitter located between the main and side area of
|
||||
* the Inspector panel.
|
||||
|
@ -445,7 +455,8 @@ InspectorPanel.prototype = {
|
|||
}),
|
||||
endPanel: this.InspectorTabPanel({
|
||||
id: "inspector-sidebar-container"
|
||||
})
|
||||
}),
|
||||
vert: this.useLandscapeMode(),
|
||||
});
|
||||
|
||||
this._splitter = this.ReactDOM.render(splitter,
|
||||
|
@ -473,9 +484,8 @@ InspectorPanel.prototype = {
|
|||
* to `horizontal` to support portrait view.
|
||||
*/
|
||||
onPanelWindowResize: function () {
|
||||
let box = this.panelDoc.getElementById("inspector-splitter-box");
|
||||
this._splitter.setState({
|
||||
vert: (box.clientWidth > PORTRAIT_MODE_WIDTH)
|
||||
vert: this.useLandscapeMode(),
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -18,216 +18,214 @@
|
|||
<?xml-stylesheet href="resource://devtools/client/inspector/components/inspector-tab-panel.css" type="text/css"?>
|
||||
<?xml-stylesheet href="resource://devtools/client/shared/components/splitter/split-box.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://devtools/content/shared/theme-switching.js"></script>
|
||||
</head>
|
||||
<body class="theme-body devtools-monospace" role="application">
|
||||
<html:div class="inspector-responsive-container theme-body inspector">
|
||||
<div class="inspector-responsive-container theme-body inspector">
|
||||
|
||||
<!-- Main Panel Content -->
|
||||
<html:div id="inspector-main-content" class="devtools-main-content">
|
||||
<html:div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
|
||||
<div id="inspector-main-content" class="devtools-main-content">
|
||||
<div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
|
||||
data-localization-bundle="devtools/locale/inspector.properties">
|
||||
<html:button id="inspector-element-add-button" class="devtools-button"
|
||||
<button id="inspector-element-add-button" class="devtools-button"
|
||||
data-localization="title=inspectorAddNode.label"/>
|
||||
<html:div class="devtools-toolbar-spacer" />
|
||||
<html:span id="inspector-searchlabel" />
|
||||
<html:div id="inspector-search" class="devtools-searchbox has-clear-btn">
|
||||
<html:input id="inspector-searchbox" class="devtools-searchinput"
|
||||
<div class="devtools-toolbar-spacer" />
|
||||
<span id="inspector-searchlabel" />
|
||||
<div id="inspector-search" class="devtools-searchbox has-clear-btn">
|
||||
<input id="inspector-searchbox" class="devtools-searchinput"
|
||||
type="search"
|
||||
data-localization="placeholder=inspectorSearchHTML.label3"/>
|
||||
<html:button id="inspector-searchinput-clear" class="devtools-searchinput-clear" tabindex="-1"></html:button>
|
||||
</html:div>
|
||||
<html:button id="inspector-eyedropper-toggle"
|
||||
<button id="inspector-searchinput-clear" class="devtools-searchinput-clear" tabindex="-1"></button>
|
||||
</div>
|
||||
<button id="inspector-eyedropper-toggle"
|
||||
data-localization="title=inspector.eyedropper.label"
|
||||
class="devtools-button command-button-invertable" />
|
||||
<html:div id="inspector-sidebar-toggle-box" />
|
||||
</html:div>
|
||||
<html:div id="markup-box" />
|
||||
<html:div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
|
||||
<html:div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
|
||||
<div id="inspector-sidebar-toggle-box" />
|
||||
</div>
|
||||
<div id="markup-box" />
|
||||
<div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
|
||||
<div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
|
||||
role="group" data-localization="aria-label=inspector.breadcrumbs.label" tabindex="0" />
|
||||
</html:div>
|
||||
</html:div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Splitter -->
|
||||
<html:div
|
||||
<div
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="inspector-splitter-box">
|
||||
</html:div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Container -->
|
||||
<html:div id="inspector-sidebar-container">
|
||||
<html:div
|
||||
<div id="inspector-sidebar-container">
|
||||
<div
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="inspector-sidebar"
|
||||
hidden="true" />
|
||||
</html:div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar panel definitions -->
|
||||
<html:div id="tabpanels" style="visibility:collapse">
|
||||
<html:div id="sidebar-panel-ruleview" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
<div id="tabpanels" style="visibility:collapse">
|
||||
<div id="sidebar-panel-ruleview" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
data-localization-bundle="devtools/locale/inspector.properties">
|
||||
<html:div id="ruleview-toolbar-container" class="devtools-toolbar">
|
||||
<html:div id="ruleview-toolbar">
|
||||
<html:div class="devtools-searchbox has-clear-btn">
|
||||
<html:input id="ruleview-searchbox"
|
||||
<div id="ruleview-toolbar-container" class="devtools-toolbar">
|
||||
<div id="ruleview-toolbar">
|
||||
<div class="devtools-searchbox has-clear-btn">
|
||||
<input id="ruleview-searchbox"
|
||||
class="devtools-filterinput devtools-rule-searchbox"
|
||||
type="search"
|
||||
data-localization="placeholder=inspector.filterStyles.placeholder"/>
|
||||
<html:button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
|
||||
</html:div>
|
||||
<html:div id="ruleview-command-toolbar">
|
||||
<html:button id="ruleview-add-rule-button" data-localization="title=inspector.addRule.tooltip" class="devtools-button"></html:button>
|
||||
<html:button id="pseudo-class-panel-toggle" data-localization="title=inspector.togglePseudo.tooltip" class="devtools-button"></html:button>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<html:div id="pseudo-class-panel" hidden="true">
|
||||
<html:label><html:input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</html:label>
|
||||
<html:label><html:input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</html:label>
|
||||
<html:label><html:input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</html:label>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></button>
|
||||
</div>
|
||||
<div id="ruleview-command-toolbar">
|
||||
<button id="ruleview-add-rule-button" data-localization="title=inspector.addRule.tooltip" class="devtools-button"></button>
|
||||
<button id="pseudo-class-panel-toggle" data-localization="title=inspector.togglePseudo.tooltip" class="devtools-button"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pseudo-class-panel" hidden="true">
|
||||
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</label>
|
||||
<label><input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</label>
|
||||
<label><input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:div id="ruleview-container" class="ruleview">
|
||||
<html:div id="ruleview-container-focusable" tabindex="-1">
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div id="ruleview-container" class="ruleview">
|
||||
<div id="ruleview-container-focusable" tabindex="-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:div id="sidebar-panel-computedview" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
<div id="sidebar-panel-computedview" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
data-localization-bundle="devtools/locale/inspector.properties">
|
||||
<html:div id="computedview-toolbar" class="devtools-toolbar">
|
||||
<html:div class="devtools-searchbox has-clear-btn">
|
||||
<html:input id="computedview-searchbox"
|
||||
<div id="computedview-toolbar" class="devtools-toolbar">
|
||||
<div class="devtools-searchbox has-clear-btn">
|
||||
<input id="computedview-searchbox"
|
||||
class="devtools-filterinput devtools-rule-searchbox"
|
||||
type="search"
|
||||
data-localization="placeholder=inspector.filterStyles.placeholder"/>
|
||||
<html:button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
|
||||
</html:div>
|
||||
<html:input id="browser-style-checkbox"
|
||||
<button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></button>
|
||||
</div>
|
||||
<input id="browser-style-checkbox"
|
||||
type="checkbox"
|
||||
class="includebrowserstyles"/>
|
||||
<html:label id="browser-style-checkbox-label" for="browser-style-checkbox"
|
||||
<label id="browser-style-checkbox-label" for="browser-style-checkbox"
|
||||
data-localization="content=inspector.browserStyles.label"/>
|
||||
</html:div>
|
||||
</div>
|
||||
|
||||
<html:div id="computedview-container">
|
||||
<html:div id="computedview-container-focusable" tabindex="-1">
|
||||
<html:div id="boxmodel-wrapper" tabindex="0"
|
||||
<div id="computedview-container">
|
||||
<div id="computedview-container-focusable" tabindex="-1">
|
||||
<div id="boxmodel-wrapper" tabindex="0"
|
||||
data-localization-bundle="devtools/locale/boxmodel.properties">
|
||||
<html:div id="boxmodel-header">
|
||||
<html:div id="boxmodel-expander" class="expander theme-twisty expandable" open=""></html:div>
|
||||
<html:span data-localization="content=boxmodel.title"/>
|
||||
</html:div>
|
||||
<div id="boxmodel-header">
|
||||
<div id="boxmodel-expander" class="expander theme-twisty expandable" open=""></div>
|
||||
<span data-localization="content=boxmodel.title"/>
|
||||
</div>
|
||||
|
||||
<html:div id="boxmodel-container">
|
||||
<html:div id="boxmodel-main">
|
||||
<html:span class="boxmodel-legend" data-box="margin" data-localization="content=boxmodel.margin;title=boxmodel.margin"/>
|
||||
<html:div id="boxmodel-margins" data-box="margin" data-localization="title=boxmodel.margin">
|
||||
<html:span class="boxmodel-legend" data-box="border" data-localization="content=boxmodel.border;title=boxmodel.border"/>
|
||||
<html:div id="boxmodel-borders" data-box="border" data-localization="title=boxmodel.border">
|
||||
<html:span class="boxmodel-legend" data-box="padding" data-localization="content=boxmodel.padding;title=boxmodel.padding"/>
|
||||
<html:div id="boxmodel-padding" data-box="padding" data-localization="title=boxmodel.padding">
|
||||
<html:div id="boxmodel-content" data-box="content" data-localization="title=boxmodel.content">
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div id="boxmodel-container">
|
||||
<div id="boxmodel-main">
|
||||
<span class="boxmodel-legend" data-box="margin" data-localization="content=boxmodel.margin;title=boxmodel.margin"/>
|
||||
<div id="boxmodel-margins" data-box="margin" data-localization="title=boxmodel.margin">
|
||||
<span class="boxmodel-legend" data-box="border" data-localization="content=boxmodel.border;title=boxmodel.border"/>
|
||||
<div id="boxmodel-borders" data-box="border" data-localization="title=boxmodel.border">
|
||||
<span class="boxmodel-legend" data-box="padding" data-localization="content=boxmodel.padding;title=boxmodel.padding"/>
|
||||
<div id="boxmodel-padding" data-box="padding" data-localization="title=boxmodel.padding">
|
||||
<div id="boxmodel-content" data-box="content" data-localization="title=boxmodel.content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:p class="boxmodel-margin boxmodel-top"><html:span data-box="margin" class="boxmodel-editable" title="margin-top"></html:span></html:p>
|
||||
<html:p class="boxmodel-margin boxmodel-right"><html:span data-box="margin" class="boxmodel-editable" title="margin-right"></html:span></html:p>
|
||||
<html:p class="boxmodel-margin boxmodel-bottom"><html:span data-box="margin" class="boxmodel-editable" title="margin-bottom"></html:span></html:p>
|
||||
<html:p class="boxmodel-margin boxmodel-left"><html:span data-box="margin" class="boxmodel-editable" title="margin-left"></html:span></html:p>
|
||||
<p class="boxmodel-margin boxmodel-top"><span data-box="margin" class="boxmodel-editable" title="margin-top"></span></p>
|
||||
<p class="boxmodel-margin boxmodel-right"><span data-box="margin" class="boxmodel-editable" title="margin-right"></span></p>
|
||||
<p class="boxmodel-margin boxmodel-bottom"><span data-box="margin" class="boxmodel-editable" title="margin-bottom"></span></p>
|
||||
<p class="boxmodel-margin boxmodel-left"><span data-box="margin" class="boxmodel-editable" title="margin-left"></span></p>
|
||||
|
||||
<html:p class="boxmodel-border boxmodel-top"><html:span data-box="border" class="boxmodel-editable" title="border-top"></html:span></html:p>
|
||||
<html:p class="boxmodel-border boxmodel-right"><html:span data-box="border" class="boxmodel-editable" title="border-right"></html:span></html:p>
|
||||
<html:p class="boxmodel-border boxmodel-bottom"><html:span data-box="border" class="boxmodel-editable" title="border-bottom"></html:span></html:p>
|
||||
<html:p class="boxmodel-border boxmodel-left"><html:span data-box="border" class="boxmodel-editable" title="border-left"></html:span></html:p>
|
||||
<p class="boxmodel-border boxmodel-top"><span data-box="border" class="boxmodel-editable" title="border-top"></span></p>
|
||||
<p class="boxmodel-border boxmodel-right"><span data-box="border" class="boxmodel-editable" title="border-right"></span></p>
|
||||
<p class="boxmodel-border boxmodel-bottom"><span data-box="border" class="boxmodel-editable" title="border-bottom"></span></p>
|
||||
<p class="boxmodel-border boxmodel-left"><span data-box="border" class="boxmodel-editable" title="border-left"></span></p>
|
||||
|
||||
<html:p class="boxmodel-padding boxmodel-top"><html:span data-box="padding" class="boxmodel-editable" title="padding-top"></html:span></html:p>
|
||||
<html:p class="boxmodel-padding boxmodel-right"><html:span data-box="padding" class="boxmodel-editable" title="padding-right"></html:span></html:p>
|
||||
<html:p class="boxmodel-padding boxmodel-bottom"><html:span data-box="padding" class="boxmodel-editable" title="padding-bottom"></html:span></html:p>
|
||||
<html:p class="boxmodel-padding boxmodel-left"><html:span data-box="padding" class="boxmodel-editable" title="padding-left"></html:span></html:p>
|
||||
<p class="boxmodel-padding boxmodel-top"><span data-box="padding" class="boxmodel-editable" title="padding-top"></span></p>
|
||||
<p class="boxmodel-padding boxmodel-right"><span data-box="padding" class="boxmodel-editable" title="padding-right"></span></p>
|
||||
<p class="boxmodel-padding boxmodel-bottom"><span data-box="padding" class="boxmodel-editable" title="padding-bottom"></span></p>
|
||||
<p class="boxmodel-padding boxmodel-left"><span data-box="padding" class="boxmodel-editable" title="padding-left"></span></p>
|
||||
|
||||
<html:p class="boxmodel-size">
|
||||
<html:span data-box="content" data-localization="title=boxmodel.content"></html:span>
|
||||
</html:p>
|
||||
</html:div>
|
||||
<p class="boxmodel-size">
|
||||
<span data-box="content" data-localization="title=boxmodel.content"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<html:div id="boxmodel-info">
|
||||
<html:span id="boxmodel-element-size"></html:span>
|
||||
<html:section id="boxmodel-position-group">
|
||||
<html:button class="devtools-button" id="layout-geometry-editor"
|
||||
data-localization="title=boxmodel.geometryButton.tooltip"></html:button>
|
||||
<html:span id="boxmodel-element-position"></html:span>
|
||||
</html:section>
|
||||
</html:div>
|
||||
<div id="boxmodel-info">
|
||||
<span id="boxmodel-element-size"></span>
|
||||
<section id="boxmodel-position-group">
|
||||
<button class="devtools-button" id="layout-geometry-editor"
|
||||
data-localization="title=boxmodel.geometryButton.tooltip"></button>
|
||||
<span id="boxmodel-element-position"></span>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<html:div style="display: none">
|
||||
<html:p id="boxmodel-dummy"></html:p>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div style="display: none">
|
||||
<p id="boxmodel-dummy"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:div id="propertyContainer" class="theme-separator" tabindex="0">
|
||||
</html:div>
|
||||
<div id="propertyContainer" class="theme-separator" tabindex="0">
|
||||
</div>
|
||||
|
||||
<html:div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"/>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:div id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
<div id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar inspector-tabpanel"
|
||||
data-localization-bundle="devtools/locale/font-inspector.properties">
|
||||
<html:div class="devtools-toolbar">
|
||||
<html:div class="devtools-searchbox">
|
||||
<html:input id="font-preview-text-input" class="devtools-textinput" type="search"
|
||||
<div class="devtools-toolbar">
|
||||
<div class="devtools-searchbox">
|
||||
<input id="font-preview-text-input" class="devtools-textinput" type="search"
|
||||
data-localization="placeholder=fontinspector.previewText"/>
|
||||
</html:div>
|
||||
<html:label id="font-showall" class="theme-link"
|
||||
</div>
|
||||
<label id="font-showall" class="theme-link"
|
||||
data-localization="content=fontinspector.seeAll;
|
||||
title=fontinspector.seeAll.tooltip"/>
|
||||
</html:div>
|
||||
</div>
|
||||
|
||||
<html:div id="font-container">
|
||||
<html:ul id="all-fonts"></html:ul>
|
||||
</html:div>
|
||||
<div id="font-container">
|
||||
<ul id="all-fonts"></ul>
|
||||
</div>
|
||||
|
||||
<html:div id="font-template">
|
||||
<html:section class="font">
|
||||
<html:div class="font-preview-container">
|
||||
<html:img class="font-preview"></html:img>
|
||||
</html:div>
|
||||
<html:div class="font-info">
|
||||
<html:h1 class="font-name"></html:h1>
|
||||
<html:span class="font-is-local" data-localization="content=fontinspector.system"/>
|
||||
<html:span class="font-is-remote" data-localization="content=fontinspector.remote"/>
|
||||
<html:p class="font-format-url">
|
||||
<html:input readonly="readonly" class="font-url"></html:input>
|
||||
<html:span class="font-format"></html:span>
|
||||
</html:p>
|
||||
<html:p class="font-css">
|
||||
<html:span data-localization="content=fontinspector.usedAs"/> "<html:span class="font-css-name"></html:span>"
|
||||
</html:p>
|
||||
<html:pre class="font-css-code"></html:pre>
|
||||
</html:div>
|
||||
</html:section>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div id="font-template">
|
||||
<section class="font">
|
||||
<div class="font-preview-container">
|
||||
<img class="font-preview"></img>
|
||||
</div>
|
||||
<div class="font-info">
|
||||
<h1 class="font-name"></h1>
|
||||
<span class="font-is-local" data-localization="content=fontinspector.system"/>
|
||||
<span class="font-is-remote" data-localization="content=fontinspector.remote"/>
|
||||
<p class="font-format-url">
|
||||
<input readonly="readonly" class="font-url"></input>
|
||||
<span class="font-format"></span>
|
||||
</p>
|
||||
<p class="font-css">
|
||||
<span data-localization="content=fontinspector.usedAs"/> "<span class="font-css-name"></span>"
|
||||
</p>
|
||||
<pre class="font-css-code"></pre>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<html:div id="sidebar-panel-animationinspector" class="devtools-monospace theme-sidebar inspector-tabpanel">
|
||||
<html:iframe class="devtools-inspector-tab-frame" />
|
||||
</html:div>
|
||||
</html:div>
|
||||
<div id="sidebar-panel-animationinspector" class="devtools-monospace theme-sidebar inspector-tabpanel">
|
||||
<iframe class="devtools-inspector-tab-frame" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html:div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -226,11 +226,7 @@ MarkupView.prototype = {
|
|||
|
||||
let container = target.container;
|
||||
if (this._hoveredNode !== container.node) {
|
||||
if (container.node.nodeType !== nodeConstants.TEXT_NODE) {
|
||||
this._showBoxModel(container.node);
|
||||
} else {
|
||||
this._hideBoxModel();
|
||||
}
|
||||
this._showBoxModel(container.node);
|
||||
}
|
||||
this._showContainerAsHovered(container.node);
|
||||
|
||||
|
|
|
@ -134,6 +134,7 @@ subsuite = clipboard
|
|||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard
|
||||
[browser_inspector_picker-stop-on-destroy.js]
|
||||
[browser_inspector_picker-stop-on-tool-change.js]
|
||||
[browser_inspector_portrait_mode.js]
|
||||
[browser_inspector_pseudoclass-lock.js]
|
||||
[browser_inspector_pseudoclass-menu.js]
|
||||
[browser_inspector_reload-01.js]
|
||||
|
|
|
@ -51,8 +51,13 @@ add_task(function* () {
|
|||
yield hoverElement("#id4");
|
||||
yield assertHighlighterHidden();
|
||||
|
||||
info("Hovering over a text node and waiting for highlighter to appear.");
|
||||
yield hoverTextNode("Visible text node");
|
||||
yield assertHighlighterShownOnTextNode("body", 14);
|
||||
|
||||
function hoverContainer(container) {
|
||||
let promise = inspector.toolbox.once("node-highlight");
|
||||
|
||||
EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
|
||||
markupView.doc.defaultView);
|
||||
|
||||
|
@ -60,7 +65,7 @@ add_task(function* () {
|
|||
}
|
||||
|
||||
function* hoverElement(selector) {
|
||||
info("Hovering node " + selector + " in the markup view");
|
||||
info(`Hovering node ${selector} in the markup view`);
|
||||
let container = yield getContainerForSelector(selector, inspector);
|
||||
return hoverContainer(container);
|
||||
}
|
||||
|
@ -75,11 +80,25 @@ add_task(function* () {
|
|||
return null;
|
||||
}
|
||||
|
||||
function hoverTextNode(text) {
|
||||
info(`Hovering the text node "${text}" in the markup view`);
|
||||
let container = [...markupView._containers].filter(([nodeFront]) => {
|
||||
return nodeFront.nodeType === Ci.nsIDOMNode.TEXT_NODE &&
|
||||
nodeFront._form.nodeValue.trim() === text.trim();
|
||||
})[0][1];
|
||||
return hoverContainer(container);
|
||||
}
|
||||
|
||||
function* assertHighlighterShownOn(selector) {
|
||||
ok((yield testActor.assertHighlightedNode(selector)),
|
||||
"Highlighter is shown on the right node: " + selector);
|
||||
}
|
||||
|
||||
function* assertHighlighterShownOnTextNode(parentSelector, childNodeIndex) {
|
||||
ok((yield testActor.assertHighlightedTextNode(parentSelector, childNodeIndex)),
|
||||
"Highlighter is shown on the right text node");
|
||||
}
|
||||
|
||||
function* assertHighlighterHidden() {
|
||||
let isVisible = yield testActor.isHighlighting();
|
||||
ok(!isVisible, "Highlighter is hidden");
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the inspector splitter is properly initialized in horizontal mode if the
|
||||
// inspector starts in portrait mode.
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, toolbox } = yield openInspectorForURL(
|
||||
"data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>", "window");
|
||||
|
||||
let hostWindow = toolbox._host._window;
|
||||
let originalWidth = hostWindow.outerWidth;
|
||||
let originalHeight = hostWindow.outerHeight;
|
||||
|
||||
let splitter = inspector.panelDoc.querySelector(".inspector-sidebar-splitter");
|
||||
|
||||
// If the inspector is not already in landscape mode.
|
||||
if (!splitter.classList.contains("vert")) {
|
||||
info("Resize toolbox window to force inspector to landscape mode");
|
||||
let onClassnameMutation = waitForClassMutation(splitter);
|
||||
hostWindow.resizeTo(800, 500);
|
||||
yield onClassnameMutation;
|
||||
|
||||
ok(splitter.classList.contains("vert"), "Splitter is in vertical mode");
|
||||
}
|
||||
|
||||
info("Resize toolbox window to force inspector to portrait mode");
|
||||
let onClassnameMutation = waitForClassMutation(splitter);
|
||||
hostWindow.resizeTo(500, 500);
|
||||
yield onClassnameMutation;
|
||||
|
||||
ok(splitter.classList.contains("horz"), "Splitter is in horizontal mode");
|
||||
|
||||
info("Close the inspector");
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
yield gDevTools.closeToolbox(target);
|
||||
|
||||
info("Reopen inspector");
|
||||
({ inspector, toolbox } = yield openInspector("window"));
|
||||
|
||||
// Devtools window should still be 500px * 500px, inspector should still be in portrait.
|
||||
splitter = inspector.panelDoc.querySelector(".inspector-sidebar-splitter");
|
||||
ok(splitter.classList.contains("horz"), "Splitter is in horizontal mode");
|
||||
|
||||
info("Restore original window size");
|
||||
toolbox._host._window.resizeTo(originalWidth, originalHeight);
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper waiting for a class attribute mutation on the provided target. Returns a
|
||||
* promise.
|
||||
*
|
||||
* @param {Node} target
|
||||
* Node to observe
|
||||
* @return {Promise} promise that will resolve upon receiving a mutation for the class
|
||||
* attribute on the target.
|
||||
*/
|
||||
function waitForClassMutation(target) {
|
||||
return new Promise(resolve => {
|
||||
let observer = new MutationObserver((mutations) => {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName === "class") {
|
||||
observer.disconnect();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(target, { attributes: true });
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
// Restore the host type for other tests.
|
||||
Services.prefs.clearUserPref("devtools.toolbox.host");
|
||||
});
|
|
@ -14,5 +14,6 @@
|
|||
</script>
|
||||
<div id="id3">Visible div 3</div>
|
||||
<div id="id4" style="display:none;">Invisible div node</div>
|
||||
Visible text node
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
.theme-firebug .toolbar {
|
||||
border-bottom: 1px solid rgb(170, 188, 207);
|
||||
background-color: rgb(219, 234, 249) !important;
|
||||
background-color: var(--theme-tab-toolbar-background) !important;
|
||||
background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,6 @@
|
|||
/* Firebug Theme */
|
||||
|
||||
.theme-firebug .tabs .tabs-navigation {
|
||||
background-color: rgb(219, 234, 249);
|
||||
background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
|
||||
padding-top: 3px;
|
||||
padding-left: 3px;
|
||||
|
|
|
@ -260,6 +260,15 @@ var testSpec = protocol.generateActorSpec({
|
|||
value: RetVal("json")
|
||||
}
|
||||
},
|
||||
getTextNodeRect: {
|
||||
request: {
|
||||
parentSelector: Arg(0, "string"),
|
||||
childNodeIndex: Arg(1, "number")
|
||||
},
|
||||
response: {
|
||||
value: RetVal("json")
|
||||
}
|
||||
},
|
||||
getNodeInfo: {
|
||||
request: {
|
||||
selector: Arg(0, "string")
|
||||
|
@ -717,6 +726,12 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
|
|||
return getRect(this.content, node, this.content);
|
||||
}),
|
||||
|
||||
getTextNodeRect: Task.async(function* (parentSelector, childNodeIndex) {
|
||||
let parentNode = this._querySelector(parentSelector);
|
||||
let node = parentNode.childNodes[childNodeIndex];
|
||||
return getAdjustedQuads(this.content, node)[0].bounds;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get information about a DOM element, identified by a selector.
|
||||
* @param {String} selector The CSS selector to get the node (can be an array
|
||||
|
@ -891,75 +906,59 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
|
|||
return ret;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Check that the box-model highlighter is currently highlighting the node matching the
|
||||
* given selector.
|
||||
* @param {String} selector
|
||||
* @return {Boolean}
|
||||
*/
|
||||
assertHighlightedNode: Task.async(function* (selector) {
|
||||
// Taken and tweaked from:
|
||||
// https://github.com/iominh/point-in-polygon-extended/blob/master/src/index.js#L30-L85
|
||||
function isLeft(p0, p1, p2) {
|
||||
let l = ((p1[0] - p0[0]) * (p2[1] - p0[1])) -
|
||||
((p2[0] - p0[0]) * (p1[1] - p0[1]));
|
||||
return l;
|
||||
}
|
||||
function isInside(point, polygon) {
|
||||
if (polygon.length === 0) {
|
||||
return false;
|
||||
}
|
||||
let rect = yield this.getNodeRect(selector);
|
||||
return yield this.isNodeRectHighlighted(rect);
|
||||
}),
|
||||
|
||||
var n = polygon.length;
|
||||
var newPoints = polygon.slice(0);
|
||||
newPoints.push(polygon[0]);
|
||||
var wn = 0; // wn counter
|
||||
|
||||
// loop through all edges of the polygon
|
||||
for (var i = 0; i < n; i++) {
|
||||
// Accept points on the edges
|
||||
let r = isLeft(newPoints[i], newPoints[i + 1], point);
|
||||
if (r === 0) {
|
||||
return true;
|
||||
}
|
||||
if (newPoints[i][1] <= point[1]) {
|
||||
if (newPoints[i + 1][1] > point[1] && r > 0) {
|
||||
wn++;
|
||||
}
|
||||
} else {
|
||||
if (newPoints[i + 1][1] <= point[1] && r < 0) {
|
||||
wn--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wn === 0) {
|
||||
dumpn(JSON.stringify(point) + " is outside of " + JSON.stringify(polygon));
|
||||
}
|
||||
// the point is outside only when this winding number wn===0, otherwise it's inside
|
||||
return wn !== 0;
|
||||
}
|
||||
/**
|
||||
* Check that the box-model highlighter is currently highlighting the text node that can
|
||||
* be found at a given index within the list of childNodes of a parent element matching
|
||||
* the given selector.
|
||||
* @param {String} parentSelector
|
||||
* @param {Number} childNodeIndex
|
||||
* @return {Boolean}
|
||||
*/
|
||||
assertHighlightedTextNode: Task.async(function* (parentSelector, childNodeIndex) {
|
||||
let rect = yield this.getTextNodeRect(parentSelector, childNodeIndex);
|
||||
return yield this.isNodeRectHighlighted(rect);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Check that the box-model highlighter is currently highlighting the given rect.
|
||||
* @param {Object} rect
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isNodeRectHighlighted: Task.async(function* ({ left, top, width, height }) {
|
||||
let {visible, border} = yield this._getBoxModelStatus();
|
||||
let points = border.points;
|
||||
if (visible) {
|
||||
// Check that the node is within the box model
|
||||
let { left, top, width, height } = yield this.getNodeRect(selector);
|
||||
let right = left + width;
|
||||
let bottom = top + height;
|
||||
|
||||
// Converts points dictionnary into an array
|
||||
let list = [];
|
||||
for (var i = 1; i <= 4; i++) {
|
||||
let p = points["p" + i];
|
||||
list.push([p.x, p.y]);
|
||||
}
|
||||
points = list;
|
||||
|
||||
// Check that each point of the node is within the box model
|
||||
if (!isInside([left, top], points) ||
|
||||
!isInside([right, top], points) ||
|
||||
!isInside([right, bottom], points) ||
|
||||
!isInside([left, bottom], points)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (!visible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the node is within the box model
|
||||
let right = left + width;
|
||||
let bottom = top + height;
|
||||
|
||||
// Converts points dictionnary into an array
|
||||
let list = [];
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
let p = points["p" + i];
|
||||
list.push([p.x, p.y]);
|
||||
}
|
||||
points = list;
|
||||
|
||||
// Check that each point of the node is within the box model
|
||||
return isInside([left, top], points) &&
|
||||
isInside([right, top], points) &&
|
||||
isInside([right, bottom], points) &&
|
||||
isInside([left, bottom], points);
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -1086,3 +1085,49 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
|
|||
return {d, points};
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Check whether a point is included in a polygon.
|
||||
* Taken and tweaked from:
|
||||
* https://github.com/iominh/point-in-polygon-extended/blob/master/src/index.js#L30-L85
|
||||
* @param {Array} point [x,y] coordinates
|
||||
* @param {Array} polygon An array of [x,y] points
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isInside(point, polygon) {
|
||||
if (polygon.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const n = polygon.length;
|
||||
const newPoints = polygon.slice(0);
|
||||
newPoints.push(polygon[0]);
|
||||
let wn = 0;
|
||||
|
||||
// loop through all edges of the polygon
|
||||
for (let i = 0; i < n; i++) {
|
||||
// Accept points on the edges
|
||||
let r = isLeft(newPoints[i], newPoints[i + 1], point);
|
||||
if (r === 0) {
|
||||
return true;
|
||||
}
|
||||
if (newPoints[i][1] <= point[1]) {
|
||||
if (newPoints[i + 1][1] > point[1] && r > 0) {
|
||||
wn++;
|
||||
}
|
||||
} else if (newPoints[i + 1][1] <= point[1] && r < 0) {
|
||||
wn--;
|
||||
}
|
||||
}
|
||||
if (wn === 0) {
|
||||
dumpn(JSON.stringify(point) + " is outside of " + JSON.stringify(polygon));
|
||||
}
|
||||
// the point is outside only when this winding number wn===0, otherwise it's inside
|
||||
return wn !== 0;
|
||||
}
|
||||
|
||||
function isLeft(p0, p1, p2) {
|
||||
let l = ((p1[0] - p0[0]) * (p2[1] - p0[1])) -
|
||||
((p2[0] - p0[0]) * (p1[1] - p0[1]));
|
||||
return l;
|
||||
}
|
||||
|
|
|
@ -454,6 +454,25 @@ const TEST_DATA = [
|
|||
index: 0, enabled: false},
|
||||
expected: "/*! content: '*\\/'; */"
|
||||
},
|
||||
|
||||
{
|
||||
desc: "delete disabled property",
|
||||
input: "\n a:b;\n /* color:#f0c; */\n e:f;",
|
||||
instruction: {type: "remove", name: "color", index: 1},
|
||||
expected: "\n a:b;\n e:f;",
|
||||
},
|
||||
{
|
||||
desc: "delete heuristic-disabled property",
|
||||
input: "\n a:b;\n /*! c:d; */\n e:f;",
|
||||
instruction: {type: "remove", name: "c", index: 1},
|
||||
expected: "\n a:b;\n e:f;",
|
||||
},
|
||||
{
|
||||
desc: "delete disabled property leaving other disabled property",
|
||||
input: "\n a:b;\n /* color:#f0c; background-color: seagreen; */\n e:f;",
|
||||
instruction: {type: "remove", name: "color", index: 1},
|
||||
expected: "\n a:b;\n /* background-color: seagreen; */\n e:f;",
|
||||
},
|
||||
];
|
||||
|
||||
function rewriteDeclarations(inputString, instruction, defaultIndentation) {
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
}
|
||||
|
||||
.theme-firebug .devtools-sidebar-tabs tabs {
|
||||
background-color: rgb(219, 234, 249) !important;
|
||||
background-color: var(--theme-tab-toolbar-background) !important;
|
||||
background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@
|
|||
.theme-firebug toolbar,
|
||||
.theme-firebug .devtools-toolbar {
|
||||
border-bottom: 1px solid rgb(170, 188, 207) !important;
|
||||
background-color: rgb(219, 234, 249) !important;
|
||||
background-color: var(--theme-tab-toolbar-background) !important;
|
||||
background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
|
||||
padding-inline-end: 4px;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ window {
|
|||
#inspector-splitter-box {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* Minimum width for the Inspector main (uncontrolled) area. */
|
||||
|
@ -197,7 +198,8 @@ iframe {
|
|||
|
||||
#markup-box {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
#markup-box > iframe {
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
--theme-sidebar-background: #fcfcfc;
|
||||
--theme-contrast-background: #e6b064;
|
||||
|
||||
--theme-tab-toolbar-background: #ebeced;
|
||||
--theme-tab-toolbar-background: #d8eaf9;
|
||||
--theme-toolbar-background: #f0f1f2;
|
||||
--theme-selection-background: #3399ff;
|
||||
--theme-selection-background-semitransparent: rgba(128,128,128,0.2);
|
||||
|
|
|
@ -103,6 +103,21 @@ const FilterBar = createClass({
|
|||
label: "Debug",
|
||||
filterKey: MESSAGE_LEVEL.DEBUG,
|
||||
dispatch
|
||||
}),
|
||||
dom.span({
|
||||
className: "devtools-separator",
|
||||
}),
|
||||
FilterButton({
|
||||
active: filter.netxhr,
|
||||
label: "XHR",
|
||||
filterKey: "netxhr",
|
||||
dispatch
|
||||
}),
|
||||
FilterButton({
|
||||
active: filter.network,
|
||||
label: "Requests",
|
||||
filterKey: "network",
|
||||
dispatch
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -13,6 +13,8 @@ const FilterState = Immutable.Record({
|
|||
error: true,
|
||||
info: true,
|
||||
log: true,
|
||||
network: true,
|
||||
netxhr: true,
|
||||
text: "",
|
||||
warn: true,
|
||||
});
|
||||
|
|
|
@ -9,7 +9,8 @@ const { l10n } = require("devtools/client/webconsole/new-console-output/utils/me
|
|||
const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
|
||||
const { getLogLimit } = require("devtools/client/webconsole/new-console-output/selectors/prefs");
|
||||
const {
|
||||
MESSAGE_TYPE
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_SOURCE
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
|
||||
function getAllMessages(state) {
|
||||
|
@ -19,7 +20,10 @@ function getAllMessages(state) {
|
|||
|
||||
return prune(
|
||||
search(
|
||||
filterLevel(messages, filters),
|
||||
filterNetwork(
|
||||
filterLevel(messages, filters),
|
||||
filters
|
||||
),
|
||||
filters.text
|
||||
),
|
||||
logLimit
|
||||
|
@ -37,6 +41,17 @@ function filterLevel(messages, filters) {
|
|||
});
|
||||
}
|
||||
|
||||
function filterNetwork(messages, filters) {
|
||||
return messages.filter((message) => {
|
||||
return (
|
||||
message.source !== MESSAGE_SOURCE.NETWORK
|
||||
|| (filters.get("network") === true && message.isXHR === false)
|
||||
|| (filters.get("netxhr") === true && message.isXHR === true)
|
||||
|| [MESSAGE_TYPE.COMMAND, MESSAGE_TYPE.RESULT].includes(message.type)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function search(messages, text = "") {
|
||||
if (text === "") {
|
||||
return messages;
|
||||
|
|
|
@ -20,6 +20,8 @@ function configureStore() {
|
|||
warn: Services.prefs.getBoolPref("devtools.webconsole.filter.warn"),
|
||||
info: Services.prefs.getBoolPref("devtools.webconsole.filter.info"),
|
||||
log: Services.prefs.getBoolPref("devtools.webconsole.filter.log"),
|
||||
network: Services.prefs.getBoolPref("devtools.webconsole.filter.network"),
|
||||
netxhr: Services.prefs.getBoolPref("devtools.webconsole.filter.netxhr"),
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ const { getAllFilters } = require("devtools/client/webconsole/new-console-output
|
|||
const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
|
||||
const { MESSAGE_LEVEL } = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
|
||||
const { stubPreparedMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
|
||||
|
||||
describe("Filtering", () => {
|
||||
let store;
|
||||
|
@ -58,6 +59,30 @@ describe("Filtering", () => {
|
|||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages - 1);
|
||||
});
|
||||
|
||||
it("filters xhr messages", () => {
|
||||
let message = stubPreparedMessages.get("XHR GET request");
|
||||
store.dispatch(messageAdd(message));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages + 1);
|
||||
|
||||
store.dispatch(actions.filterToggle("netxhr"));
|
||||
messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
});
|
||||
|
||||
it("filters network messages", () => {
|
||||
let message = stubPreparedMessages.get("GET request");
|
||||
store.dispatch(messageAdd(message));
|
||||
|
||||
let messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages + 1);
|
||||
|
||||
store.dispatch(actions.filterToggle("network"));
|
||||
messages = getAllMessages(store.getState());
|
||||
expect(messages.size).toEqual(numMessages);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Text filter", () => {
|
||||
|
@ -137,13 +162,17 @@ describe("Clear filters", () => {
|
|||
|
||||
// Setup test case
|
||||
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
|
||||
store.dispatch(actions.filterToggle("netxhr"));
|
||||
store.dispatch(actions.filterTextSet("foobar"));
|
||||
|
||||
let filters = getAllFilters(store.getState());
|
||||
expect(filters.toJS()).toEqual({
|
||||
"debug": true,
|
||||
"error": false,
|
||||
"info": true,
|
||||
"log": true,
|
||||
"network": true,
|
||||
"netxhr": false,
|
||||
"warn": true,
|
||||
"text": "foobar"
|
||||
});
|
||||
|
@ -156,6 +185,8 @@ describe("Clear filters", () => {
|
|||
"error": true,
|
||||
"info": true,
|
||||
"log": true,
|
||||
"network": true,
|
||||
"netxhr": true,
|
||||
"warn": true,
|
||||
"text": ""
|
||||
});
|
||||
|
|
|
@ -3298,6 +3298,9 @@ WebConsoleConnectionProxy.prototype = {
|
|||
messages.sort((a, b) => a.timeStamp - b.timeStamp);
|
||||
|
||||
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
|
||||
// Filter out CSS page errors.
|
||||
messages = messages.filter(message => !(message._type == "PageError"
|
||||
&& Utils.categoryForScriptError(message) === CATEGORY_CSS));
|
||||
for (let packet of messages) {
|
||||
this.dispatchMessageAdd(packet);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ const protocol = require("devtools/shared/protocol");
|
|||
const Services = require("Services");
|
||||
const { isWindowIncluded } = require("devtools/shared/layout/utils");
|
||||
const { highlighterSpec, customHighlighterSpec } = require("devtools/shared/specs/highlighters");
|
||||
const { isXUL, isNodeValid } = require("./highlighters/utils/markup");
|
||||
const { isXUL } = require("./highlighters/utils/markup");
|
||||
const { SimpleOutlineHighlighter } = require("./highlighters/simple-outline");
|
||||
|
||||
const HIGHLIGHTER_PICKED_TIMER = 1000;
|
||||
|
@ -182,9 +182,7 @@ var HighlighterActor = exports.HighlighterActor = protocol.ActorClassWithSpec(hi
|
|||
* all options may be supported by all types of highlighters.
|
||||
*/
|
||||
showBoxModel: function (node, options = {}) {
|
||||
if (node && isNodeValid(node.rawNode)) {
|
||||
this._highlighter.show(node.rawNode, options);
|
||||
} else {
|
||||
if (!node || !this._highlighter.show(node.rawNode, options)) {
|
||||
this._highlighter.hide();
|
||||
}
|
||||
},
|
||||
|
@ -468,7 +466,7 @@ var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClas
|
|||
* (FF41+)
|
||||
*/
|
||||
show: function (node, options) {
|
||||
if (!node || !isNodeValid(node.rawNode) || !this._highlighter) {
|
||||
if (!node || !this._highlighter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ AutoRefreshHighlighter.prototype = {
|
|||
let isSameNode = node === this.currentNode;
|
||||
let isSameOptions = this._isSameOptions(options);
|
||||
|
||||
if (!isNodeValid(node) || (isSameNode && isSameOptions)) {
|
||||
if (!this._isNodeValid(node) || (isSameNode && isSameOptions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ AutoRefreshHighlighter.prototype = {
|
|||
* Hide the highlighter
|
||||
*/
|
||||
hide: function () {
|
||||
if (!isNodeValid(this.currentNode)) {
|
||||
if (!this._isNodeValid(this.currentNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,17 @@ AutoRefreshHighlighter.prototype = {
|
|||
this.emit("hidden");
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the current node is valid for this highlighter type.
|
||||
* This is implemented by default to check if the node is an element node. Highlighter
|
||||
* sub-classes should override this method if they want to highlight other node types.
|
||||
* @param {DOMNode} node
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_isNodeValid: function (node) {
|
||||
return isNodeValid(node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Are the provided options the same as the currently stored options?
|
||||
* Returns false if there are no options stored currently.
|
||||
|
@ -151,7 +162,7 @@ AutoRefreshHighlighter.prototype = {
|
|||
* Update the highlighter if the node has moved since the last update.
|
||||
*/
|
||||
update: function () {
|
||||
if (!isNodeValid(this.currentNode) || !this._hasMoved()) {
|
||||
if (!this._isNodeValid(this.currentNode) || !this._hasMoved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,17 @@
|
|||
const { extend } = require("sdk/core/heritage");
|
||||
const { AutoRefreshHighlighter } = require("./auto-refresh");
|
||||
const {
|
||||
CanvasFrameAnonymousContentHelper, moveInfobar,
|
||||
getBindingElementAndPseudo, hasPseudoClassLock, getComputedStyle,
|
||||
createSVGNode, createNode, isNodeValid } = require("./utils/markup");
|
||||
CanvasFrameAnonymousContentHelper,
|
||||
createNode,
|
||||
createSVGNode,
|
||||
getBindingElementAndPseudo,
|
||||
hasPseudoClassLock,
|
||||
isNodeValid,
|
||||
moveInfobar,
|
||||
} = require("./utils/markup");
|
||||
const { setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
|
||||
const inspector = require("devtools/server/actors/inspector");
|
||||
const nodeConstants = require("devtools/shared/dom-node-constants");
|
||||
|
||||
// Note that the order of items in this array is important because it is used
|
||||
// for drawing the BoxModelHighlighter's path elements correctly.
|
||||
|
@ -94,8 +100,6 @@ function BoxModelHighlighter(highlighterEnv) {
|
|||
* regionFill property: `highlighter.regionFill.margin = "red";
|
||||
*/
|
||||
this.regionFill = {};
|
||||
|
||||
this._currentNode = null;
|
||||
}
|
||||
|
||||
BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
|
@ -103,15 +107,6 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
|
||||
ID_CLASS_PREFIX: "box-model-",
|
||||
|
||||
get currentNode() {
|
||||
return this._currentNode;
|
||||
},
|
||||
|
||||
set currentNode(node) {
|
||||
this._currentNode = node;
|
||||
this._computedStyle = null;
|
||||
},
|
||||
|
||||
_buildMarkup: function () {
|
||||
let doc = this.win.document;
|
||||
|
||||
|
@ -258,16 +253,23 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
*/
|
||||
destroy: function () {
|
||||
AutoRefreshHighlighter.prototype.destroy.call(this);
|
||||
|
||||
this.markup.destroy();
|
||||
|
||||
this._currentNode = null;
|
||||
},
|
||||
|
||||
getElement: function (id) {
|
||||
return this.markup.getElement(this.ID_CLASS_PREFIX + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Override the AutoRefreshHighlighter's _isNodeValid method to also return true for
|
||||
* text nodes since these can also be highlighted.
|
||||
* @param {DOMNode} node
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_isNodeValid: function (node) {
|
||||
return node && (isNodeValid(node) || isNodeValid(node, nodeConstants.TEXT_NODE));
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the highlighter on a given node
|
||||
*/
|
||||
|
@ -311,7 +313,9 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
setIgnoreLayoutChanges(true);
|
||||
|
||||
if (this._updateBoxModel()) {
|
||||
if (!this.options.hideInfoBar) {
|
||||
// Show the infobar only if configured to do so and the node is an element.
|
||||
if (!this.options.hideInfoBar &&
|
||||
this.currentNode.nodeType === this.currentNode.ELEMENT_NODE) {
|
||||
this._showInfobar();
|
||||
} else {
|
||||
this._hideInfobar();
|
||||
|
@ -519,20 +523,15 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
return path;
|
||||
},
|
||||
|
||||
/**
|
||||
* Can the current node be highlighted? Does it have quads.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_nodeNeedsHighlighting: function () {
|
||||
let hasNoQuads = !this.currentQuads.margin.length &&
|
||||
!this.currentQuads.border.length &&
|
||||
!this.currentQuads.padding.length &&
|
||||
!this.currentQuads.content.length;
|
||||
if (!isNodeValid(this.currentNode) || hasNoQuads) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this._computedStyle) {
|
||||
this._computedStyle = getComputedStyle(this.currentNode);
|
||||
}
|
||||
|
||||
return this._computedStyle.getPropertyValue("display") !== "none";
|
||||
return this.currentQuads.margin.length ||
|
||||
this.currentQuads.border.length ||
|
||||
this.currentQuads.padding.length ||
|
||||
this.currentQuads.content.length;
|
||||
},
|
||||
|
||||
_getOuterBounds: function () {
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
|
||||
const { extend } = require("sdk/core/heritage");
|
||||
const { AutoRefreshHighlighter } = require("./auto-refresh");
|
||||
const {
|
||||
CanvasFrameAnonymousContentHelper, getCSSStyleRules, getComputedStyle,
|
||||
createSVGNode, createNode } = require("./utils/markup");
|
||||
|
||||
const { setIgnoreLayoutChanges,
|
||||
getAdjustedQuads } = require("devtools/shared/layout/utils");
|
||||
const { CanvasFrameAnonymousContentHelper, getCSSStyleRules, getComputedStyle,
|
||||
createSVGNode, createNode } = require("./utils/markup");
|
||||
const { setIgnoreLayoutChanges, getAdjustedQuads } = require("devtools/shared/layout/utils");
|
||||
|
||||
const GEOMETRY_LABEL_SIZE = 6;
|
||||
|
||||
|
|
|
@ -121,18 +121,25 @@ function installHelperSheet(win, source, type = "agent") {
|
|||
}
|
||||
exports.installHelperSheet = installHelperSheet;
|
||||
|
||||
function isNodeValid(node) {
|
||||
// Is it null or dead?
|
||||
/**
|
||||
* Returns true if a DOM node is "valid", where "valid" means that the node isn't a dead
|
||||
* object wrapper, is still attached to a document, and is of a given type.
|
||||
* @param {DOMNode} node
|
||||
* @param {Number} nodeType Optional, defaults to ELEMENT_NODE
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isNodeValid(node, nodeType = Ci.nsIDOMNode.ELEMENT_NODE) {
|
||||
// Is it still alive?
|
||||
if (!node || Cu.isDeadWrapper(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it an element node
|
||||
if (node.nodeType !== node.ELEMENT_NODE) {
|
||||
// Is it of the right type?
|
||||
if (node.nodeType !== nodeType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the document inaccessible?
|
||||
// Is its document accessible?
|
||||
let doc = node.ownerDocument;
|
||||
if (!doc || !doc.defaultView) {
|
||||
return false;
|
||||
|
|
|
@ -486,18 +486,12 @@ function parseDeclarations(isCssPropertyKnown, inputString,
|
|||
*/
|
||||
function RuleRewriter(isCssPropertyKnown, rule, inputString) {
|
||||
this.rule = rule;
|
||||
this.inputString = inputString;
|
||||
// Whether there are any newlines in the input text.
|
||||
this.hasNewLine = /[\r\n]/.test(this.inputString);
|
||||
this.isCssPropertyKnown = isCssPropertyKnown;
|
||||
|
||||
// Keep track of which any declarations we had to rewrite while
|
||||
// performing the requested action.
|
||||
this.changedDeclarations = {};
|
||||
// The declarations.
|
||||
this.declarations = parseDeclarations(isCssPropertyKnown, this.inputString,
|
||||
true);
|
||||
|
||||
this.decl = null;
|
||||
this.result = null;
|
||||
// If not null, a promise that must be wait upon before |apply| can
|
||||
// do its work.
|
||||
this.editPromise = null;
|
||||
|
@ -507,9 +501,28 @@ function RuleRewriter(isCssPropertyKnown, rule, inputString) {
|
|||
// indentation based on the style sheet's text. This override
|
||||
// facility is for testing.
|
||||
this.defaultIndentation = null;
|
||||
|
||||
this.startInitialization(inputString);
|
||||
}
|
||||
|
||||
RuleRewriter.prototype = {
|
||||
/**
|
||||
* An internal function to initialize the rewriter with a given
|
||||
* input string.
|
||||
*
|
||||
* @param {String} inputString the input to use
|
||||
*/
|
||||
startInitialization: function (inputString) {
|
||||
this.inputString = inputString;
|
||||
// Whether there are any newlines in the input text.
|
||||
this.hasNewLine = /[\r\n]/.test(this.inputString);
|
||||
// The declarations.
|
||||
this.declarations = parseDeclarations(this.isCssPropertyKnown, this.inputString,
|
||||
true);
|
||||
this.decl = null;
|
||||
this.result = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* An internal function to complete initialization and set some
|
||||
* properties for further processing.
|
||||
|
@ -924,6 +937,17 @@ RuleRewriter.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the property is disabled, then first enable it, and then
|
||||
// delete it. We take this approach because we want to remove the
|
||||
// entire comment if possible; but the logic for dealing with
|
||||
// comments is hairy and already implemented in
|
||||
// setPropertyEnabled.
|
||||
if (this.decl.commentOffsets) {
|
||||
this.setPropertyEnabled(index, name, true);
|
||||
this.startInitialization(this.result);
|
||||
this.completeInitialization(index);
|
||||
}
|
||||
|
||||
let copyOffset = this.decl.offsets[1];
|
||||
// Maybe removing this rule left us with a completely blank
|
||||
// line. In this case, we'll delete the whole thing. We only
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "AnimationUtils.h"
|
||||
|
||||
#include "nsContentUtils.h" // For nsContentUtils::IsCallerChrome
|
||||
#include "nsDebug.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIContent.h"
|
||||
|
@ -63,7 +64,7 @@ AnimationUtils::IsOffscreenThrottlingEnabled()
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
AnimationUtils::IsCoreAPIEnabled()
|
||||
AnimationUtils::IsCoreAPIEnabledForCaller()
|
||||
{
|
||||
static bool sCoreAPIEnabled;
|
||||
static bool sPrefCached = false;
|
||||
|
@ -74,7 +75,7 @@ AnimationUtils::IsCoreAPIEnabled()
|
|||
"dom.animations-api.core.enabled");
|
||||
}
|
||||
|
||||
return sCoreAPIEnabled;
|
||||
return sCoreAPIEnabled || nsContentUtils::IsCallerChrome();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -63,10 +63,10 @@ public:
|
|||
|
||||
/**
|
||||
* Returns true if the preference to enable the core Web Animations API is
|
||||
* true.
|
||||
* true or the caller is chrome.
|
||||
*/
|
||||
static bool
|
||||
IsCoreAPIEnabled();
|
||||
IsCoreAPIEnabledForCaller();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -132,7 +132,7 @@ KeyframeEffect::SetIterationComposite(
|
|||
{
|
||||
// Ignore iterationComposite if the Web Animations API is not enabled,
|
||||
// then the default value 'Replace' will be used.
|
||||
if (!AnimationUtils::IsCoreAPIEnabled()) {
|
||||
if (!AnimationUtils::IsCoreAPIEnabledForCaller()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ KeyframeEffectParams::ParseSpacing(const nsAString& aSpacing,
|
|||
|
||||
// Ignore spacing if the core API is not enabled since it is not yet ready to
|
||||
// ship.
|
||||
if (!AnimationUtils::IsCoreAPIEnabled()) {
|
||||
if (!AnimationUtils::IsCoreAPIEnabledForCaller()) {
|
||||
aSpacingMode = SpacingMode::distribute;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -512,7 +512,7 @@ KeyframeEffectParamsFromUnion(const OptionsType& aOptions,
|
|||
aRv);
|
||||
// Ignore iterationComposite if the Web Animations API is not enabled,
|
||||
// then the default value 'Replace' will be used.
|
||||
if (AnimationUtils::IsCoreAPIEnabled()) {
|
||||
if (AnimationUtils::IsCoreAPIEnabledForCaller()) {
|
||||
result.mIterationComposite = options.mIterationComposite;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script>
|
||||
window.onload=function(){
|
||||
var e=document.createElement("q");
|
||||
document.documentElement.appendChild(e);
|
||||
e.style="mask-image:url(data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=),url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)";
|
||||
setTimeout(function(){
|
||||
e.style="mask-image:url(data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=)";
|
||||
},0);
|
||||
};
|
||||
</script>
|
||||
</html>
|
|
@ -207,3 +207,4 @@ load xhr_empty_datauri.html
|
|||
load xhr_html_nullresponse.html
|
||||
load 1230422.html
|
||||
load 1251361.html
|
||||
load 1304437.html
|
||||
|
|
|
@ -525,7 +525,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
|
|||
, INIT_MIRROR(mPlaybackPosition, 0)
|
||||
, INIT_MIRROR(mIsAudioDataAudible, false)
|
||||
, INIT_CANONICAL(mVolume, 0.0)
|
||||
, INIT_CANONICAL(mPlaybackRate, 1.0)
|
||||
, INIT_CANONICAL(mPreservesPitch, true)
|
||||
, INIT_CANONICAL(mEstimatedDuration, NullableTimeUnit())
|
||||
, INIT_CANONICAL(mExplicitDuration, Maybe<double>())
|
||||
|
@ -744,6 +743,9 @@ MediaDecoder::SetStateMachineParameters()
|
|||
if (mMinimizePreroll) {
|
||||
mDecoderStateMachine->DispatchMinimizePrerollUntilPlaybackStarts();
|
||||
}
|
||||
if (mPlaybackRate != 1 && mPlaybackRate != 0) {
|
||||
mDecoderStateMachine->DispatchSetPlaybackRate(mPlaybackRate);
|
||||
}
|
||||
mTimedMetadataListener = mDecoderStateMachine->TimedMetadataEvent().Connect(
|
||||
AbstractThread::MainThread(), this, &MediaDecoder::OnMetadataUpdate);
|
||||
mMetadataLoadedListener = mDecoderStateMachine->MetadataLoadedEvent().Connect(
|
||||
|
@ -1510,7 +1512,10 @@ MediaDecoder::SetPlaybackRate(double aPlaybackRate)
|
|||
if (mPlaybackRate == 0.0) {
|
||||
mPausedForPlaybackRateNull = true;
|
||||
Pause();
|
||||
} else if (mPausedForPlaybackRateNull) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPausedForPlaybackRateNull) {
|
||||
// Play() uses mPausedForPlaybackRateNull value, so must reset it first
|
||||
mPausedForPlaybackRateNull = false;
|
||||
// If the playbackRate is no longer null, restart the playback, iff the
|
||||
|
@ -1519,6 +1524,10 @@ MediaDecoder::SetPlaybackRate(double aPlaybackRate)
|
|||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->DispatchSetPlaybackRate(aPlaybackRate);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -764,7 +764,7 @@ protected:
|
|||
Canonical<double> mVolume;
|
||||
|
||||
// PlaybackRate and pitch preservation status we should start at.
|
||||
Canonical<double> mPlaybackRate;
|
||||
double mPlaybackRate = 1;
|
||||
|
||||
Canonical<bool> mPreservesPitch;
|
||||
|
||||
|
@ -827,9 +827,6 @@ public:
|
|||
AbstractCanonical<double>* CanonicalVolume() {
|
||||
return &mVolume;
|
||||
}
|
||||
AbstractCanonical<double>* CanonicalPlaybackRate() {
|
||||
return &mPlaybackRate;
|
||||
}
|
||||
AbstractCanonical<bool>* CanonicalPreservesPitch() {
|
||||
return &mPreservesPitch;
|
||||
}
|
||||
|
|
|
@ -745,7 +745,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
|
||||
INIT_MIRROR(mNextPlayState, MediaDecoder::PLAY_STATE_PAUSED),
|
||||
INIT_MIRROR(mVolume, 1.0),
|
||||
INIT_MIRROR(mLogicalPlaybackRate, 1.0),
|
||||
INIT_MIRROR(mPreservesPitch, true),
|
||||
INIT_MIRROR(mSameOriginMedia, false),
|
||||
INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
|
||||
|
@ -807,7 +806,6 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
|
|||
mPlayState.Connect(aDecoder->CanonicalPlayState());
|
||||
mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
|
||||
mVolume.Connect(aDecoder->CanonicalVolume());
|
||||
mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate());
|
||||
mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
|
||||
mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
|
||||
mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
|
||||
|
@ -824,7 +822,6 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
|
|||
mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
|
||||
mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
|
||||
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
|
||||
mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
|
||||
mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
|
||||
|
@ -1494,8 +1491,7 @@ MediaDecoderStateMachine::MaybeStartBuffering()
|
|||
|
||||
bool shouldBuffer;
|
||||
if (mReader->UseBufferingHeuristics()) {
|
||||
shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
|
||||
HasLowBufferedData();
|
||||
shouldBuffer = HasLowDecodedData() && HasLowBufferedData();
|
||||
} else {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported());
|
||||
shouldBuffer = (OutOfDecodedAudio() && mReader->IsWaitingAudioData()) ||
|
||||
|
@ -1710,7 +1706,6 @@ MediaDecoderStateMachine::Shutdown()
|
|||
mPlayState.DisconnectIfConnected();
|
||||
mNextPlayState.DisconnectIfConnected();
|
||||
mVolume.DisconnectIfConnected();
|
||||
mLogicalPlaybackRate.DisconnectIfConnected();
|
||||
mPreservesPitch.DisconnectIfConnected();
|
||||
mSameOriginMedia.DisconnectIfConnected();
|
||||
mMediaPrincipalHandle.DisconnectIfConnected();
|
||||
|
@ -2318,17 +2313,28 @@ MediaDecoderStateMachine::StartMediaSink()
|
|||
}
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HasLowDecodedData(int64_t aAudioUsecs)
|
||||
bool
|
||||
MediaDecoderStateMachine::HasLowDecodedAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return IsAudioDecoding() &&
|
||||
GetDecodedAudioDuration() < EXHAUSTED_DATA_MARGIN_USECS * mPlaybackRate;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachine::HasLowDecodedVideo()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return IsVideoDecoding() &&
|
||||
VideoQueue().GetSize() < LOW_VIDEO_FRAMES * mPlaybackRate;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachine::HasLowDecodedData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mReader->UseBufferingHeuristics());
|
||||
// We consider ourselves low on decoded data if we're low on audio,
|
||||
// provided we've not decoded to the end of the audio stream, or
|
||||
// if we're low on video frames, provided
|
||||
// we've not decoded to the end of the video stream.
|
||||
return ((IsAudioDecoding() && GetDecodedAudioDuration() < aAudioUsecs) ||
|
||||
(IsVideoDecoding() &&
|
||||
static_cast<uint32_t>(VideoQueue().GetSize()) < LOW_VIDEO_FRAMES));
|
||||
return HasLowDecodedAudio() || HasLowDecodedVideo();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::OutOfDecodedAudio()
|
||||
|
@ -2782,16 +2788,12 @@ bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
|||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::LogicalPlaybackRateChanged()
|
||||
MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aPlaybackRate != 0, "Should be handled by MediaDecoder::Pause()");
|
||||
|
||||
if (mLogicalPlaybackRate == 0) {
|
||||
// This case is handled in MediaDecoder by pausing playback.
|
||||
return;
|
||||
}
|
||||
|
||||
mPlaybackRate = mLogicalPlaybackRate;
|
||||
mPlaybackRate = aPlaybackRate;
|
||||
mMediaSink->SetPlaybackRate(mPlaybackRate);
|
||||
|
||||
if (mIsAudioPrerolling && DonePrerollingAudio()) {
|
||||
|
|
|
@ -174,6 +174,12 @@ public:
|
|||
// Seeks to the decoder to aTarget asynchronously.
|
||||
RefPtr<MediaDecoder::SeekPromise> InvokeSeek(SeekTarget aTarget);
|
||||
|
||||
void DispatchSetPlaybackRate(double aPlaybackRate)
|
||||
{
|
||||
OwnerThread()->DispatchStateChange(NewRunnableMethod<double>(
|
||||
this, &MediaDecoderStateMachine::SetPlaybackRate, aPlaybackRate));
|
||||
}
|
||||
|
||||
// Set/Unset dormant state.
|
||||
void DispatchSetDormant(bool aDormant);
|
||||
|
||||
|
@ -367,7 +373,7 @@ protected:
|
|||
void AudioAudibleChanged(bool aAudible);
|
||||
|
||||
void VolumeChanged();
|
||||
void LogicalPlaybackRateChanged();
|
||||
void SetPlaybackRate(double aPlaybackRate);
|
||||
void PreservesPitchChanged();
|
||||
|
||||
MediaQueue<MediaData>& AudioQueue() { return mAudioQueue; }
|
||||
|
@ -381,11 +387,13 @@ protected:
|
|||
// decode more.
|
||||
bool NeedToDecodeVideo();
|
||||
|
||||
// Returns true if we've got less than aAudioUsecs microseconds of decoded
|
||||
// and playable data. The decoder monitor must be held.
|
||||
//
|
||||
// True if we are low in decoded audio/video data.
|
||||
// May not be invoked when mReader->UseBufferingHeuristics() is false.
|
||||
bool HasLowDecodedData(int64_t aAudioUsecs);
|
||||
bool HasLowDecodedData();
|
||||
|
||||
bool HasLowDecodedAudio();
|
||||
|
||||
bool HasLowDecodedVideo();
|
||||
|
||||
bool OutOfDecodedAudio();
|
||||
|
||||
|
@ -886,11 +894,6 @@ private:
|
|||
// Volume of playback. 0.0 = muted. 1.0 = full volume.
|
||||
Mirror<double> mVolume;
|
||||
|
||||
// TODO: The separation between mPlaybackRate and mLogicalPlaybackRate is a
|
||||
// kludge to preserve existing fragile logic while converting this setup to
|
||||
// state-mirroring. Some hero should clean this up.
|
||||
Mirror<double> mLogicalPlaybackRate;
|
||||
|
||||
// Pitch preservation for the playback rate.
|
||||
Mirror<bool> mPreservesPitch;
|
||||
|
||||
|
|
|
@ -30,8 +30,9 @@ TextTrackList::TextTrackList(nsPIDOMWindowInner* aOwnerWindow)
|
|||
|
||||
TextTrackList::TextTrackList(nsPIDOMWindowInner* aOwnerWindow,
|
||||
TextTrackManager* aTextTrackManager)
|
||||
: DOMEventTargetHelper(aOwnerWindow)
|
||||
, mTextTrackManager(aTextTrackManager)
|
||||
: DOMEventTargetHelper(aOwnerWindow)
|
||||
, mPendingTextTrackChange(false)
|
||||
, mTextTrackManager(aTextTrackManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -131,7 +132,7 @@ TextTrackList::DidSeek()
|
|||
}
|
||||
}
|
||||
|
||||
class TrackEventRunner final: public Runnable
|
||||
class TrackEventRunner : public Runnable
|
||||
{
|
||||
public:
|
||||
TrackEventRunner(TextTrackList* aList, nsIDOMEvent* aEvent)
|
||||
|
@ -144,11 +145,25 @@ public:
|
|||
return mList->DispatchTrackEvent(mEvent);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<TextTrackList> mList;
|
||||
private:
|
||||
RefPtr<nsIDOMEvent> mEvent;
|
||||
};
|
||||
|
||||
class ChangeEventRunner final : public TrackEventRunner
|
||||
{
|
||||
public:
|
||||
ChangeEventRunner(TextTrackList* aList, nsIDOMEvent* aEvent)
|
||||
: TrackEventRunner(aList, aEvent)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mList->mPendingTextTrackChange = false;
|
||||
return TrackEventRunner::Run();
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
TextTrackList::DispatchTrackEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
|
@ -158,13 +173,17 @@ TextTrackList::DispatchTrackEvent(nsIDOMEvent* aEvent)
|
|||
void
|
||||
TextTrackList::CreateAndDispatchChangeEvent()
|
||||
{
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mPendingTextTrackChange) {
|
||||
mPendingTextTrackChange = true;
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
|
||||
event->InitEvent(NS_LITERAL_STRING("change"), false, false);
|
||||
event->SetTrusted(true);
|
||||
event->InitEvent(NS_LITERAL_STRING("change"), false, false);
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsCOMPtr<nsIRunnable> eventRunner = new TrackEventRunner(this, event);
|
||||
NS_DispatchToMainThread(eventRunner);
|
||||
nsCOMPtr<nsIRunnable> eventRunner = new ChangeEventRunner(this, event);
|
||||
NS_DispatchToMainThread(eventRunner);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -67,6 +67,8 @@ public:
|
|||
IMPL_EVENT_HANDLER(addtrack)
|
||||
IMPL_EVENT_HANDLER(removetrack)
|
||||
|
||||
bool mPendingTextTrackChange;
|
||||
|
||||
private:
|
||||
~TextTrackList();
|
||||
|
||||
|
|
|
@ -61,10 +61,15 @@ class VideoPuppeteer(object):
|
|||
'var video = arguments[0];'
|
||||
'var currentTime = video.wrappedJSObject.currentTime;'
|
||||
'var duration = video.wrappedJSObject.duration;'
|
||||
'var buffered = video.wrappedJSObject.buffered;'
|
||||
'var bufferedRanges = [];'
|
||||
'for (var i = 0; i < buffered.length; i++) {'
|
||||
'bufferedRanges.push([buffered.start(i), buffered.end(i)]);'
|
||||
'}'
|
||||
'var played = video.wrappedJSObject.played;'
|
||||
'var timeRanges = [];'
|
||||
'var playedRanges = [];'
|
||||
'for (var i = 0; i < played.length; i++) {'
|
||||
'timeRanges.push([played.start(i), played.end(i)]);'
|
||||
'playedRanges.push([played.start(i), played.end(i)]);'
|
||||
'}'
|
||||
'var totalFrames = '
|
||||
'video.getVideoPlaybackQuality()["totalVideoFrames"];'
|
||||
|
@ -248,6 +253,11 @@ class VideoPuppeteer(object):
|
|||
|
||||
current_time: The current time of the wrapped element.
|
||||
duration: the duration of the wrapped element.
|
||||
buffered: the buffered ranges of the wrapped element. In its raw form
|
||||
this is as a list where the first element is the length and the second
|
||||
element is a list of 2 item lists, where each two items are a buffered
|
||||
range. Once assigned to the tuple this data should be wrapped in the
|
||||
TimeRanges class.
|
||||
played: the played ranges of the wrapped element. In its raw form this
|
||||
is as a list where the first element is the length and the second
|
||||
element is a list of 2 item lists, where each two items are a played
|
||||
|
@ -267,6 +277,7 @@ class VideoPuppeteer(object):
|
|||
['current_time',
|
||||
'duration',
|
||||
'remaining_time',
|
||||
'buffered',
|
||||
'played',
|
||||
'lag',
|
||||
'total_frames',
|
||||
|
@ -279,23 +290,28 @@ class VideoPuppeteer(object):
|
|||
"""
|
||||
Create an instance of the video_state_info named tuple. This function
|
||||
expects a dictionary populated with the following keys: current_time,
|
||||
duration, raw_time_ranges, total_frames, dropped_frames, and
|
||||
duration, raw_played_ranges, total_frames, dropped_frames, and
|
||||
corrupted_frames.
|
||||
|
||||
Aside from raw_time_ranges, see `_video_state_named_tuple` for more
|
||||
information on the above keys and values. For raw_time_ranges a
|
||||
Aside from raw_played_ranges, see `_video_state_named_tuple` for more
|
||||
information on the above keys and values. For raw_played_ranges a
|
||||
list is expected that can be consumed to make a TimeRanges object.
|
||||
|
||||
:return: A named tuple 'video_state_info' derived from arguments and
|
||||
state information from the puppeteer.
|
||||
"""
|
||||
raw_time_ranges = video_state_info_kwargs['raw_time_ranges']
|
||||
# Remove raw ranges from dict as it is not used in the final named
|
||||
raw_buffered_ranges = video_state_info_kwargs['raw_buffered_ranges']
|
||||
raw_played_ranges = video_state_info_kwargs['raw_played_ranges']
|
||||
# Remove raw ranges from dict as they are not used in the final named
|
||||
# tuple and will provide an unexpected kwarg if kept.
|
||||
del video_state_info_kwargs['raw_time_ranges']
|
||||
del video_state_info_kwargs['raw_buffered_ranges']
|
||||
del video_state_info_kwargs['raw_played_ranges']
|
||||
# Create buffered ranges
|
||||
video_state_info_kwargs['buffered'] = (
|
||||
TimeRanges(raw_buffered_ranges[0], raw_buffered_ranges[1]))
|
||||
# Create played ranges
|
||||
video_state_info_kwargs['played'] = (
|
||||
TimeRanges(raw_time_ranges[0], raw_time_ranges[1]))
|
||||
TimeRanges(raw_played_ranges[0], raw_played_ranges[1]))
|
||||
# Calculate elapsed times
|
||||
elapsed_current_time = (video_state_info_kwargs['current_time'] -
|
||||
self._first_seen_time)
|
||||
|
@ -327,7 +343,8 @@ class VideoPuppeteer(object):
|
|||
'return ['
|
||||
'currentTime,'
|
||||
'duration,'
|
||||
'[played.length, timeRanges],'
|
||||
'[buffered.length, bufferedRanges],'
|
||||
'[played.length, playedRanges],'
|
||||
'totalFrames,'
|
||||
'droppedFrames,'
|
||||
'corruptedFrames];')
|
||||
|
@ -342,8 +359,9 @@ class VideoPuppeteer(object):
|
|||
information, such as lag. This is stored in the last seen state to
|
||||
stress that it's based on the snapshot.
|
||||
"""
|
||||
keys = ['current_time', 'duration', 'raw_time_ranges', 'total_frames',
|
||||
'dropped_frames', 'corrupted_frames']
|
||||
keys = ['current_time', 'duration', 'raw_buffered_ranges',
|
||||
'raw_played_ranges', 'total_frames', 'dropped_frames',
|
||||
'corrupted_frames']
|
||||
values = self._execute_video_script(self._fetch_state_script)
|
||||
self._last_seen_video_state = (
|
||||
self._create_video_state_info(**dict(zip(keys, values))))
|
||||
|
|
|
@ -346,7 +346,8 @@ class YouTubePuppeteer(VideoPuppeteer):
|
|||
'return ['
|
||||
'currentTime,'
|
||||
'duration,'
|
||||
'[played.length, timeRanges],'
|
||||
'[buffered.length, bufferedRanges],'
|
||||
'[played.length, playedRanges],'
|
||||
'totalFrames,'
|
||||
'droppedFrames,'
|
||||
'corruptedFrames,'
|
||||
|
@ -371,8 +372,9 @@ class YouTubePuppeteer(VideoPuppeteer):
|
|||
stress that it's based on the snapshot.
|
||||
"""
|
||||
values = self._execute_yt_script(self._fetch_state_script)
|
||||
video_keys = ['current_time', 'duration', 'raw_time_ranges',
|
||||
'total_frames', 'dropped_frames', 'corrupted_frames']
|
||||
video_keys = ['current_time', 'duration', 'raw_buffered_ranges',
|
||||
'raw_played_ranges', 'total_frames', 'dropped_frames',
|
||||
'corrupted_frames']
|
||||
player_keys = ['player_duration', 'player_current_time',
|
||||
'player_playback_quality', 'player_movie_id',
|
||||
'player_movie_title', 'player_url', 'player_state',
|
||||
|
|
|
@ -28,15 +28,22 @@ video.textTracks.addEventListener("change", changed);
|
|||
|
||||
is(track.mode, "hidden", "New TextTrack's mode should be hidden.");
|
||||
track.mode = "showing";
|
||||
// Bug882674: change the mode again to see if we receive only one
|
||||
// change event.
|
||||
track.mode = "hidden";
|
||||
|
||||
var eventCount = 0;
|
||||
function changed(event) {
|
||||
eventCount++;
|
||||
is(eventCount, 1, "change event dispatched multiple times.");
|
||||
is(event.target, video.textTracks, "change event's target should be video.textTracks.");
|
||||
ok(event instanceof window.Event, "change event should be a simple event.");
|
||||
ok(!event.bubbles, "change event should not bubble.");
|
||||
ok(event.isTrusted, "change event should be trusted.");
|
||||
ok(!event.cancelable, "change event should not be cancelable.");
|
||||
|
||||
SimpleTest.finish();
|
||||
// Delay the finish function call for testing the change event count.
|
||||
setTimeout(SimpleTest.finish, 0);
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
|
|
|
@ -186,7 +186,6 @@ SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
|
|||
NS_ENSURE_ARG_POINTER(aLoader);
|
||||
NS_ENSURE_ARG_POINTER(aReporter);
|
||||
|
||||
NS_ConvertUTF16toUTF8 utf8Hash(aString);
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
aLoader->GetChannel(getter_AddRefs(channel));
|
||||
|
||||
|
@ -203,7 +202,10 @@ SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
|
|||
|
||||
SRICheckDataVerifier verifier(aMetadata, aSourceFileURI, aReporter);
|
||||
nsresult rv;
|
||||
rv = verifier.Update(utf8Hash.Length(), (uint8_t*)utf8Hash.get());
|
||||
nsDependentCString rawBuffer;
|
||||
rv = aLoader->GetRawBuffer(rawBuffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = verifier.Update(rawBuffer.Length(), (const uint8_t*)rawBuffer.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return verifier.Verify(aMetadata, channel, aSourceFileURI, aReporter);
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/*! Simple test for bug 1271796 */
|
||||
p::before { content: "\2014"; }
|
|
@ -72,13 +72,13 @@
|
|||
ok(true, "A UTF8 stylesheet (with BOM) was correctly loaded when integrity matched");
|
||||
}
|
||||
function bad_correctUTF8BOMHashBlocked() {
|
||||
todo(false, "We should load UTF8 (with BOM) stylesheets with hashes that match!");
|
||||
ok(false, "We should load UTF8 (with BOM) stylesheets with hashes that match!");
|
||||
}
|
||||
function good_correctUTF8ishHashLoaded() {
|
||||
ok(true, "A UTF8ish stylesheet was correctly loaded when integrity matched");
|
||||
}
|
||||
function bad_correctUTF8ishHashBlocked() {
|
||||
todo(false, "We should load UTF8ish stylesheets with hashes that match!");
|
||||
ok(false, "We should load UTF8ish stylesheets with hashes that match!");
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
file_bug_1271796.css
|
||||
iframe_require-sri-for_main.html
|
||||
iframe_require-sri-for_main.html^headers^
|
||||
iframe_script_crossdomain.html
|
||||
|
@ -43,3 +44,4 @@ support-files =
|
|||
[test_style_sameorigin.html]
|
||||
[test_require-sri-for_csp_directive.html]
|
||||
[test_require-sri-for_csp_directive_disabled.html]
|
||||
[test_bug_1271796.html]
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function good_shouldLoadEncodingProblem() {
|
||||
ok(true, "Problematically encoded file correctly loaded.")
|
||||
};
|
||||
function bad_shouldntEncounterBug1271796() {
|
||||
ok(false, "Problematically encoded should load!")
|
||||
}
|
||||
window.onload = function() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="file_bug_1271796.css" crossorigin="anonymous"
|
||||
integrity="sha384-8Xl0mTN4S2QZ5xeliG1sd4Ar9o1xMw6JoJy9RNjyHGQDha7GiLxo8l1llwLVgTNG"
|
||||
onload="good_shouldLoadEncodingProblem();"
|
||||
onerror="bad_shouldntEncounterBug1271796();">
|
||||
</head>
|
||||
<body>
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1271796">Bug 1271796</a><br>
|
||||
<p>This text is prepended by emdash if css has loaded</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1660,7 +1660,9 @@ CompositorBridgeParent::FlushApzRepaints(const LayerTransactionParent* aLayerTre
|
|||
// use the compositor's root layer tree id.
|
||||
layersId = mRootLayerTreeID;
|
||||
}
|
||||
mApzcTreeManager->FlushApzRepaints(layersId);
|
||||
APZThreadUtils::RunOnControllerThread(NS_NewRunnableFunction([=] () {
|
||||
mApzcTreeManager->FlushApzRepaints(layersId);
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1671,29 +1673,6 @@ CompositorBridgeParent::GetAPZTestData(const LayerTransactionParent* aLayerTree,
|
|||
*aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;
|
||||
}
|
||||
|
||||
class NotifyAPZConfirmedTargetTask : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit NotifyAPZConfirmedTargetTask(const RefPtr<APZCTreeManager>& aAPZCTM,
|
||||
const uint64_t& aInputBlockId,
|
||||
const nsTArray<ScrollableLayerGuid>& aTargets)
|
||||
: mAPZCTM(aAPZCTM),
|
||||
mInputBlockId(aInputBlockId),
|
||||
mTargets(aTargets)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
mAPZCTM->SetTargetAPZC(mInputBlockId, mTargets);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<APZCTreeManager> mAPZCTM;
|
||||
uint64_t mInputBlockId;
|
||||
nsTArray<ScrollableLayerGuid> mTargets;
|
||||
};
|
||||
|
||||
void
|
||||
CompositorBridgeParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
|
||||
const uint64_t& aInputBlockId,
|
||||
|
@ -1702,8 +1681,13 @@ CompositorBridgeParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLa
|
|||
if (!mApzcTreeManager) {
|
||||
return;
|
||||
}
|
||||
RefPtr<Runnable> task =
|
||||
new NotifyAPZConfirmedTargetTask(mApzcTreeManager, aInputBlockId, aTargets);
|
||||
// Need to specifically bind this since it's overloaded.
|
||||
void (APZCTreeManager::*setTargetApzcFunc)
|
||||
(uint64_t, const nsTArray<ScrollableLayerGuid>&) =
|
||||
&APZCTreeManager::SetTargetAPZC;
|
||||
RefPtr<Runnable> task = NewRunnableMethod
|
||||
<uint64_t, StoreCopyPassByConstLRef<nsTArray<ScrollableLayerGuid>>>
|
||||
(mApzcTreeManager.get(), setTargetApzcFunc, aInputBlockId, aTargets);
|
||||
APZThreadUtils::RunOnControllerThread(task.forget());
|
||||
|
||||
}
|
||||
|
|
|
@ -592,40 +592,42 @@ class gfxContextMatrixAutoSaveRestore
|
|||
{
|
||||
public:
|
||||
gfxContextMatrixAutoSaveRestore() :
|
||||
mContext(nullptr)
|
||||
mContext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
explicit gfxContextMatrixAutoSaveRestore(gfxContext *aContext) :
|
||||
mContext(aContext), mMatrix(aContext->CurrentMatrix())
|
||||
mContext(aContext), mMatrix(aContext->CurrentMatrix())
|
||||
{
|
||||
}
|
||||
|
||||
~gfxContextMatrixAutoSaveRestore()
|
||||
{
|
||||
if (mContext) {
|
||||
mContext->SetMatrix(mMatrix);
|
||||
}
|
||||
if (mContext) {
|
||||
mContext->SetMatrix(mMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void SetContext(gfxContext *aContext)
|
||||
{
|
||||
NS_ASSERTION(!mContext, "Not going to restore the matrix on some context!");
|
||||
mContext = aContext;
|
||||
mMatrix = aContext->CurrentMatrix();
|
||||
NS_ASSERTION(!mContext,
|
||||
"Not going to restore the matrix on some context!");
|
||||
mContext = aContext;
|
||||
mMatrix = aContext->CurrentMatrix();
|
||||
}
|
||||
|
||||
void Restore()
|
||||
{
|
||||
if (mContext) {
|
||||
mContext->SetMatrix(mMatrix);
|
||||
}
|
||||
if (mContext) {
|
||||
mContext->SetMatrix(mMatrix);
|
||||
mContext = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const gfxMatrix& Matrix()
|
||||
{
|
||||
MOZ_ASSERT(mContext, "mMatrix doesn't contain a useful matrix");
|
||||
return mMatrix;
|
||||
MOZ_ASSERT(mContext, "mMatrix doesn't contain a useful matrix");
|
||||
return mMatrix;
|
||||
}
|
||||
|
||||
bool HasMatrix() const { return !!mContext; }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#Tue Apr 12 09:52:06 CEST 2016
|
||||
#Fri Sep 16 15:41:50 PDT 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
distributionSha256Sum=496d60c331f8666f99b66d08ff67a880697a7e85a9d9b76ff08814cf97f61a4c
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
distributionSha256Sum=88a910cdf2e03ebbb5fe90f7ecf534fc9ac22e12112dc9a2fee810c598a76091
|
||||
|
|
|
@ -328,7 +328,7 @@ RestyleTracker::AddPendingRestyle(Element* aElement,
|
|||
|
||||
// We can only treat this element as a restyle root if we would
|
||||
// actually restyle its descendants (so either call
|
||||
// ReResolveStyleContext on it or just reframe it).
|
||||
// ElementRestyler::Restyle on it or just reframe it).
|
||||
if ((aRestyleHint & ~eRestyle_LaterSiblings) ||
|
||||
(aMinChangeHint & nsChangeHint_ReconstructFrame)) {
|
||||
Element* cur =
|
||||
|
|
|
@ -3238,7 +3238,8 @@ nsCSSRendering::PaintBackgroundWithSC(const PaintBGParams& aParams,
|
|||
clipSet = true;
|
||||
if (!clipBorderArea.IsEqualEdges(aParams.borderArea)) {
|
||||
// We're drawing the background for the joined continuation boxes
|
||||
// so we need to clip that to the slice that we want for this frame.
|
||||
// so we need to clip that to the slice that we want for this
|
||||
// frame.
|
||||
gfxRect clip =
|
||||
nsLayoutUtils::RectToGfxRect(aParams.borderArea, appUnitsPerPixel);
|
||||
autoSR.EnsureSaved(ctx);
|
||||
|
@ -3259,7 +3260,8 @@ nsCSSRendering::PaintBackgroundWithSC(const PaintBGParams& aParams,
|
|||
if (!state.mFillArea.IsEmpty()) {
|
||||
if (co != CompositionOp::OP_OVER) {
|
||||
NS_ASSERTION(ctx->CurrentOp() == CompositionOp::OP_OVER,
|
||||
"It is assumed the initial op is OP_OVER, when it is restored later");
|
||||
"It is assumed the initial op is OP_OVER, when it is "
|
||||
"restored later");
|
||||
ctx->SetOp(co);
|
||||
}
|
||||
|
||||
|
|
|
@ -6832,16 +6832,28 @@ bool nsDisplayMask::TryMerge(nsDisplayItem* aItem)
|
|||
// items for the same content element should be merged into a single
|
||||
// compositing group
|
||||
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
|
||||
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
||||
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
|
||||
return false;
|
||||
if (aItem->GetClip() != GetClip())
|
||||
}
|
||||
if (aItem->GetClip() != GetClip()) {
|
||||
return false;
|
||||
if (aItem->ScrollClip() != ScrollClip())
|
||||
}
|
||||
if (aItem->ScrollClip() != ScrollClip()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not merge if mFrame has mask. Continuation frames should apply mask
|
||||
// independently(just like nsDisplayBackgroundImage).
|
||||
const nsStyleSVGReset *style = mFrame->StyleSVGReset();
|
||||
if (style->mMask.HasLayerWithImage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDisplayMask* other = static_cast<nsDisplayMask*>(aItem);
|
||||
MergeFromTrackingMergedFrames(other);
|
||||
mEffectsBounds.UnionRect(mEffectsBounds,
|
||||
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6886,7 +6898,7 @@ nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion)
|
||||
nsRegion* aVisibleRegion)
|
||||
{
|
||||
// Our children may be made translucent or arbitrarily deformed so we should
|
||||
// not allow them to subtract area from aVisibleRegion.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Masking: mask on inline element</title>
|
||||
<link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
|
||||
<style type="text/css">
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
font-size: 100px;
|
||||
line-height: 100px;
|
||||
}
|
||||
|
||||
div.mask-by-png {
|
||||
mask-image: url(support/transparent-100x50-blue-100x50.png);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mask-by-png">A</div>
|
||||
<div class="mask-by-png">B</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Masking: mask on inline element</title>
|
||||
<link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-masking-1/#the-mask-image">
|
||||
<link rel="match" href="mask-image-6-ref.html">
|
||||
<meta name="assert" content="Test checks whether mask on inline elemnt works correctly or not.">
|
||||
<style type="text/css">
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
span {
|
||||
font-size: 100px;
|
||||
line-height: 100px;
|
||||
mask-image: url(support/transparent-100x50-blue-100x50.png);
|
||||
mask-repeat: repeat;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<span>A B</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -29,6 +29,7 @@ fuzzy-if(skiaContent,50,50) == mask-image-3f.html mask-image-3-ref.html
|
|||
== mask-image-4a.html blank.html
|
||||
== mask-image-4b.html blank.html
|
||||
== mask-image-5.html mask-image-5-ref.html
|
||||
== mask-image-6.html mask-image-6-ref.html
|
||||
|
||||
# mask-clip test cases
|
||||
== mask-clip-1.html mask-clip-1-ref.html
|
||||
|
|
|
@ -32,7 +32,7 @@ enum class CSSPseudoElementType : uint8_t;
|
|||
* (with a few exceptions, like system color changes), the data in an
|
||||
* nsStyleContext are also immutable (with the additional exception of
|
||||
* GetUniqueStyleData). When style data change,
|
||||
* nsFrameManager::ReResolveStyleContext creates a new style context.
|
||||
* ElementRestyler::Restyle creates a new style context.
|
||||
*
|
||||
* Style contexts are reference counted. References are generally held
|
||||
* by:
|
||||
|
|
|
@ -1318,7 +1318,8 @@ nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aNewData) const
|
|||
hint |= nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
hint |= mMask.CalcDifference(aNewData.mMask, nsChangeHint_RepaintFrame);
|
||||
hint |= mMask.CalcDifference(aNewData.mMask,
|
||||
nsStyleImageLayers::LayerType::Mask);
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
@ -2427,8 +2428,13 @@ nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
|
|||
|
||||
nsChangeHint
|
||||
nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aNewLayers,
|
||||
nsChangeHint aPositionChangeHint) const
|
||||
nsStyleImageLayers::LayerType aType) const
|
||||
{
|
||||
nsChangeHint positionChangeHint =
|
||||
(aType == nsStyleImageLayers::LayerType::Background)
|
||||
? nsChangeHint_UpdateBackgroundPosition
|
||||
: nsChangeHint_RepaintFrame;
|
||||
|
||||
nsChangeHint hint = nsChangeHint(0);
|
||||
|
||||
const nsStyleImageLayers& moreLayers =
|
||||
|
@ -2442,7 +2448,7 @@ nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aNewLayers,
|
|||
if (i < lessLayers.mImageCount) {
|
||||
nsChangeHint layerDifference =
|
||||
moreLayers.mLayers[i].CalcDifference(lessLayers.mLayers[i],
|
||||
aPositionChangeHint);
|
||||
positionChangeHint);
|
||||
hint |= layerDifference;
|
||||
if (layerDifference &&
|
||||
((moreLayers.mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
|
||||
|
@ -2457,6 +2463,11 @@ nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aNewLayers,
|
|||
}
|
||||
}
|
||||
|
||||
if (aType == nsStyleImageLayers::LayerType::Mask &&
|
||||
mImageCount != aNewLayers.mImageCount) {
|
||||
hint |= nsChangeHint_UpdateEffects;
|
||||
}
|
||||
|
||||
if (hint) {
|
||||
return hint;
|
||||
}
|
||||
|
@ -2729,7 +2740,7 @@ nsStyleImageLayers::Layer::CalcDifference(const nsStyleImageLayers::Layer& aNewL
|
|||
{
|
||||
nsChangeHint hint = nsChangeHint(0);
|
||||
if (mSourceURI != aNewLayer.mSourceURI) {
|
||||
hint |= nsChangeHint_RepaintFrame;
|
||||
hint |= nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects;
|
||||
|
||||
// If Layer::mSourceURI links to a SVG mask, it has a fragment. Not vice
|
||||
// versa. Here are examples of URI contains a fragment, two of them link
|
||||
|
@ -2757,10 +2768,9 @@ nsStyleImageLayers::Layer::CalcDifference(const nsStyleImageLayers::Layer& aNewL
|
|||
}
|
||||
}
|
||||
|
||||
// Return nsChangeHint_UpdateEffects and nsChangeHint_UpdateOverflow if
|
||||
// either URI might link to an SVG mask.
|
||||
// Return nsChangeHint_UpdateOverflow if either URI might link to an SVG
|
||||
// mask.
|
||||
if (maybeSVGMask) {
|
||||
hint |= nsChangeHint_UpdateEffects;
|
||||
// Mask changes require that we update the PreEffectsBBoxProperty,
|
||||
// which is done during overflow computation.
|
||||
hint |= nsChangeHint_UpdateOverflow;
|
||||
|
@ -2827,7 +2837,7 @@ nsStyleBackground::CalcDifference(const nsStyleBackground& aNewData) const
|
|||
}
|
||||
|
||||
hint |= mImage.CalcDifference(aNewData.mImage,
|
||||
nsChangeHint_UpdateBackgroundPosition);
|
||||
nsStyleImageLayers::LayerType::Background);
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
@ -3555,17 +3565,17 @@ nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
|
|||
nsChangeHint
|
||||
nsStyleContent::CalcDifference(const nsStyleContent& aNewData) const
|
||||
{
|
||||
// In ReResolveStyleContext we assume that if there's no existing
|
||||
// In ElementRestyler::Restyle we assume that if there's no existing
|
||||
// ::before or ::after and we don't have to restyle children of the
|
||||
// node then we can't end up with a ::before or ::after due to the
|
||||
// restyle of the node itself. That's not quite true, but the only
|
||||
// exception to the above is when the 'content' property of the node
|
||||
// changes and the pseudo-element inherits the changed value. Since
|
||||
// the code here triggers a frame change on the node in that case,
|
||||
// the optimization in ReResolveStyleContext is ok. But if we ever
|
||||
// the optimization in ElementRestyler::Restyle is ok. But if we ever
|
||||
// change this code to not reconstruct frames on changes to the
|
||||
// 'content' property, then we will need to revisit the optimization
|
||||
// in ReResolveStyleContext.
|
||||
// in ElementRestyler::Restyle.
|
||||
|
||||
// Unfortunately we need to reframe even if the content lengths are the same;
|
||||
// a simple reflow will not pick up different text or different image URLs,
|
||||
|
|
|
@ -823,7 +823,7 @@ struct nsStyleImageLayers {
|
|||
}
|
||||
|
||||
nsChangeHint CalcDifference(const nsStyleImageLayers& aNewLayers,
|
||||
nsChangeHint aPositionChangeHint) const;
|
||||
nsStyleImageLayers::LayerType aType) const;
|
||||
|
||||
bool HasLayerWithImage() const;
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@ public:
|
|||
/**
|
||||
* StyleContextChanged
|
||||
*
|
||||
* To be called from nsFrameManager::ReResolveStyleContext when the
|
||||
* To be called from RestyleManager::TryStartingTransition when the
|
||||
* style of an element has changed, to initiate transitions from
|
||||
* that style change. For style contexts with :before and :after
|
||||
* pseudos, aElement is expected to be the generated before/after
|
||||
|
|
|
@ -180,11 +180,6 @@ GetOffsetToBoundingBox(nsIFrame* aFrame)
|
|||
// no offset adjustment to make.
|
||||
return nsPoint();
|
||||
}
|
||||
// We could allow aFrame to be any continuation, but since that would require
|
||||
// a GetPrevContinuation() virtual call and conditional returns, and since
|
||||
// all our current consumers always pass in the first continuation, we don't
|
||||
// currently bother.
|
||||
NS_ASSERTION(!aFrame->GetPrevContinuation(), "Not first continuation");
|
||||
|
||||
// The GetAllInFlowRectsUnion() call gets the union of the frame border-box
|
||||
// rects over all continuations, relative to the origin (top-left of the
|
||||
|
@ -434,8 +429,10 @@ ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
|||
: IntRect();
|
||||
}
|
||||
|
||||
typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
|
||||
|
||||
static IntRect
|
||||
ComputeMaskGeometry(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
ComputeMaskGeometry(const PaintFramesParams& aParams,
|
||||
const nsStyleSVGReset *svgReset,
|
||||
const nsPoint& aOffsetToUserSpace,
|
||||
const nsTArray<nsSVGMaskFrame *>& aMaskFrames)
|
||||
|
@ -494,7 +491,7 @@ ComputeMaskGeometry(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
}
|
||||
|
||||
static DrawResult
|
||||
GenerateMaskSurface(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
GenerateMaskSurface(const PaintFramesParams& aParams,
|
||||
float aOpacity, nsStyleContext* aSC,
|
||||
const nsTArray<nsSVGMaskFrame *>& aMaskFrames,
|
||||
const nsPoint& aOffsetToUserSpace,
|
||||
|
@ -612,7 +609,7 @@ GenerateMaskSurface(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
}
|
||||
|
||||
static float
|
||||
ComputeOpacity(const nsSVGIntegrationUtils::PaintFramesParams& aParams)
|
||||
ComputeOpacity(const PaintFramesParams& aParams)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
float opacity = frame->StyleEffects()->mOpacity;
|
||||
|
@ -626,8 +623,8 @@ ComputeOpacity(const nsSVGIntegrationUtils::PaintFramesParams& aParams)
|
|||
}
|
||||
|
||||
static bool
|
||||
ValidateSVGFrame(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
bool aHasSVGLayout, DrawResult* aResult)
|
||||
ValidateSVGFrame(const PaintFramesParams& aParams, bool aHasSVGLayout,
|
||||
DrawResult* aResult)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
|
||||
|
@ -655,28 +652,37 @@ ValidateSVGFrame(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup transform matrix of a gfx context by a specific frame. Depend on
|
||||
* aClipCtx, this function may clip that context by the visual overflow area
|
||||
* of aFrame.
|
||||
*
|
||||
* @param aFrame is the target frame.
|
||||
* @param aOffsetToBoundingBox returns the offset between the reference frame
|
||||
* and the bounding box of aFrame.
|
||||
* @oaram aOffsetToUserSpace returns the offset between the reference frame and
|
||||
* the user space coordinate of aFrame.
|
||||
* @param aClipCtx indicate whether clip aParams.ctx by visual overflow rect of
|
||||
* aFrame or not.
|
||||
*/
|
||||
static void
|
||||
SetupContextMatrix(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
nsPoint& aOffsetToBoundingBox,
|
||||
nsPoint& aToUserSpace,
|
||||
nsPoint& aOffsetToUserSpace)
|
||||
SetupContextMatrix(nsIFrame* aFrame, const PaintFramesParams& aParams,
|
||||
nsPoint& aOffsetToBoundingBox, nsPoint& aOffsetToUserSpace,
|
||||
bool aClipCtx)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||
|
||||
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
|
||||
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(aFrame) -
|
||||
GetOffsetToBoundingBox(aFrame);
|
||||
if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
/* Snap the offset if the reference frame is not a SVG frame,
|
||||
* since other frames will be snapped to pixel when rendering. */
|
||||
aOffsetToBoundingBox = nsPoint(
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
|
||||
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
|
||||
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
|
||||
}
|
||||
|
||||
// After applying only "aOffsetToBoundingBox", aCtx would have its origin at
|
||||
// the top left corner of frame's bounding box (over all continuations).
|
||||
// After applying only "aOffsetToBoundingBox", aParams.ctx would have its
|
||||
// origin at the top left corner of frame's bounding box (over all
|
||||
// continuations).
|
||||
// However, SVG painting needs the origin to be located at the origin of the
|
||||
// SVG frame's "user space", i.e. the space in which, for example, the
|
||||
// frame's BBox lives.
|
||||
|
@ -686,28 +692,36 @@ SetupContextMatrix(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
// frame's position so that SVG painting can later add it again and the
|
||||
// frame is painted in the right place.
|
||||
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
|
||||
aToUserSpace =
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame);
|
||||
nsPoint toUserSpace =
|
||||
nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
||||
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
||||
|
||||
aOffsetToUserSpace = aOffsetToBoundingBox - aToUserSpace;
|
||||
aOffsetToUserSpace = aOffsetToBoundingBox - toUserSpace;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
NS_ASSERTION(hasSVGLayout || aOffsetToBoundingBox == aOffsetToUserSpace,
|
||||
"For non-SVG frames there shouldn't be any additional offset");
|
||||
#endif
|
||||
|
||||
gfxPoint devPixelOffsetToUserSpace =
|
||||
nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
aParams.ctx.SetMatrix(aParams.ctx.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
gfxContext& context = aParams.ctx;
|
||||
context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
|
||||
if (aClipCtx) {
|
||||
nsRect clipRect =
|
||||
aParams.frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
CreateBlendTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
IntPoint& aTargetOffset)
|
||||
CreateBlendTarget(const PaintFramesParams& aParams, IntPoint& aTargetOffset)
|
||||
{
|
||||
MOZ_ASSERT(aParams.frame->StyleEffects()->mMixBlendMode !=
|
||||
NS_STYLE_BLEND_NORMAL);
|
||||
|
@ -731,8 +745,8 @@ CreateBlendTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
}
|
||||
|
||||
static void
|
||||
BlendToTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
gfxContext* aTarget, const IntPoint& aTargetOffset)
|
||||
BlendToTarget(const PaintFramesParams& aParams, gfxContext* aTarget,
|
||||
const IntPoint& aTargetOffset)
|
||||
{
|
||||
MOZ_ASSERT(aParams.frame->StyleEffects()->mMixBlendMode !=
|
||||
NS_STYLE_BLEND_NORMAL);
|
||||
|
@ -782,11 +796,6 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
|
@ -830,12 +839,23 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
MOZ_ASSERT_IF(shouldGenerateClipMaskLayer,
|
||||
!shouldApplyClipPath && !shouldApplyBasicShape);
|
||||
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint offsetToUserSpace;
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
// Clip the source context first, so that we can generate a smaller temporary
|
||||
// surface. (Since we will clip this context in SetupContextMatrix, a pair
|
||||
// of save/restore is needed.)
|
||||
context.Save();
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
context.Restore();
|
||||
|
||||
if (!target) {
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
@ -846,52 +866,79 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (shouldGenerateMask) {
|
||||
context.Save();
|
||||
nsRect clipRect =
|
||||
frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
frame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
gfxContextMatrixAutoSaveRestore matSR;
|
||||
|
||||
Matrix maskTransform;
|
||||
RefPtr<SourceSurface> maskSurface;
|
||||
|
||||
if (shouldGenerateMaskLayer) {
|
||||
matSR.SetContext(&context);
|
||||
|
||||
// For css-mask, we want to generate a mask for each continuation frame,
|
||||
// so we setup context matrix by the position of the current frame,
|
||||
// instead of the first continuation frame.
|
||||
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
result = GenerateMaskSurface(aParams, opacity,
|
||||
firstFrame->StyleContext(),
|
||||
maskFrames, offsetToUserSpace,
|
||||
maskTransform, maskSurface);
|
||||
}
|
||||
|
||||
if (shouldGenerateMaskLayer && !maskSurface) {
|
||||
// Entire surface is clipped out.
|
||||
context.Restore();
|
||||
return result;
|
||||
context.PopClip();
|
||||
if (!maskSurface) {
|
||||
// Entire surface is clipped out.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldGenerateClipMaskLayer) {
|
||||
matSR.Restore();
|
||||
matSR.SetContext(&context);
|
||||
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
Matrix clippedMaskTransform;
|
||||
RefPtr<SourceSurface> clipMaskSurface =
|
||||
clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
|
||||
&clippedMaskTransform, maskSurface,
|
||||
maskTransform, &result);
|
||||
context.PopClip();
|
||||
|
||||
if (clipMaskSurface) {
|
||||
maskSurface = clipMaskSurface;
|
||||
maskTransform = clippedMaskTransform;
|
||||
} else {
|
||||
// Either entire surface is clipped out, or gfx buffer allocation
|
||||
// failure in nsSVGClipPathFrame::GetClipMask.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// opacity != 1.0f.
|
||||
if (!shouldGenerateClipMaskLayer && !shouldGenerateMaskLayer) {
|
||||
MOZ_ASSERT(opacity != 1.0f);
|
||||
|
||||
matSR.SetContext(&context);
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
}
|
||||
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
|
||||
}
|
||||
|
||||
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
||||
* we can just do normal painting and get it clipped appropriately.
|
||||
*/
|
||||
if (shouldApplyClipPath) {
|
||||
if (shouldApplyClipPath || shouldApplyBasicShape) {
|
||||
context.Save();
|
||||
clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
|
||||
} else if (shouldApplyBasicShape) {
|
||||
context.Save();
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, false);
|
||||
|
||||
MOZ_ASSERT(!shouldApplyClipPath || !shouldApplyBasicShape);
|
||||
if (shouldApplyClipPath) {
|
||||
clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
|
||||
} else {
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Paint the child */
|
||||
|
@ -900,7 +947,7 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
RefPtr<gfxContext> oldCtx = basic->GetTarget();
|
||||
basic->SetTarget(target);
|
||||
aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
|
||||
aParams.builder);
|
||||
aParams.builder);
|
||||
basic->SetTarget(oldCtx);
|
||||
|
||||
if (shouldApplyClipPath || shouldApplyBasicShape) {
|
||||
|
@ -909,7 +956,12 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
|
||||
if (shouldGenerateMask) {
|
||||
target->PopGroupAndBlend();
|
||||
context.Restore();
|
||||
|
||||
if (!shouldGenerateClipMaskLayer && !shouldGenerateMaskLayer) {
|
||||
MOZ_ASSERT(opacity != 1.0f);
|
||||
// Pop the clip push by SetupContextMatrix
|
||||
context.PopClip();
|
||||
}
|
||||
}
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
|
@ -940,14 +992,6 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
nsIFrame* firstFrame =
|
||||
|
@ -959,24 +1003,28 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
return DrawResult::NOT_READY;
|
||||
}
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint offsetToUserSpace;
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
// Clip the source context first, so that we can generate a smaller temporary
|
||||
// surface. (Since we will clip this context in SetupContextMatrix, a pair
|
||||
// of save/restore is needed.)
|
||||
gfxContextAutoSaveRestore autoSR(&context);
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
if (!target) {
|
||||
context.Restore();
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
||||
if (opacity != 1.0f) {
|
||||
context.Save();
|
||||
nsRect clipRect =
|
||||
frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
frame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
|
||||
nullptr, Matrix());
|
||||
}
|
||||
|
@ -991,7 +1039,6 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
|
||||
if (opacity != 1.0f) {
|
||||
target->PopGroupAndBlend();
|
||||
context.Restore();
|
||||
}
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
|
|
|
@ -340,9 +340,10 @@ bool
|
|||
MP4Metadata::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
|
||||
{
|
||||
#ifdef MOZ_RUST_MP4PARSE
|
||||
if (mRust && mPreferRust) {
|
||||
return mRust->ReadTrackIndex(aDest, aTrackID);
|
||||
if (mRust && mPreferRust && mRust->ReadTrackIndex(aDest, aTrackID)) {
|
||||
return true;
|
||||
}
|
||||
aDest.Clear();
|
||||
#endif
|
||||
return mStagefright->ReadTrackIndex(aDest, aTrackID);
|
||||
}
|
||||
|
@ -839,7 +840,7 @@ MP4MetadataRust::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::T
|
|||
}
|
||||
|
||||
// For non-fragmented mp4.
|
||||
MOZ_ASSERT(false, "Not yet implemented");
|
||||
NS_WARNING("Not yet implemented");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ dependencies {
|
|||
compile project(':thirdparty')
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.robolectric:robolectric:3.0'
|
||||
testCompile 'org.robolectric:robolectric:3.1.2'
|
||||
testCompile 'org.simpleframework:simple-http:6.0.1'
|
||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||
|
||||
|
@ -412,3 +412,47 @@ afterEvaluate {
|
|||
dependsOn tasks["spoonLocalOldDebugAndroidTest"]
|
||||
}
|
||||
}
|
||||
|
||||
// Bug 1299015: Complain to treeherder if checkstyle, lint, or unittest fails. It's not obvious
|
||||
// how to listen to individual errors in most cases, so we just link to the reports for now.
|
||||
def makeTaskExecutionListener(artifactRootUrl) {
|
||||
return new TaskExecutionListener() {
|
||||
void beforeExecute(Task task) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void afterExecute(Task task, TaskState state) {
|
||||
if (!state.failure) {
|
||||
return
|
||||
}
|
||||
|
||||
// Link to the failing report. The task path and the report path
|
||||
// depend on the android-lint task in
|
||||
// taskcluster/ci/android-stuff/kind.yml. It's not possible to link
|
||||
// directly, so for now consumers will need to copy-paste the URL.
|
||||
switch (task.path) {
|
||||
case ':app:checkstyle':
|
||||
def url = "${artifactRootUrl}/public/android/checkstyle/checkstyle.xml"
|
||||
println "TEST-UNEXPECTED-FAIL | android-checkstyle | Checkstyle rule violations were found. See the report at: $url"
|
||||
break
|
||||
|
||||
case ':app:lintAutomationDebug':
|
||||
def url = "${artifactRootUrl}/public/android/lint/lint-results-automationDebug.html"
|
||||
println "TEST-UNEXPECTED-FAIL | android-lint | Lint found errors in the project; aborting build. See the report at: $url"
|
||||
break
|
||||
|
||||
case ':app:testAutomationDebugUnitTest':
|
||||
def url = "${artifactRootUrl}/public/android/unittest/automationDebug/index.html"
|
||||
println "TEST-UNEXPECTED-FAIL | android-test | There were failing tests. See the report at: $url"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TASK_ID and RUN_ID are provided by docker-worker; see
|
||||
// https://docs.taskcluster.net/manual/execution/workers/docker-worker.
|
||||
if (System.env.TASK_ID && System.env.RUN_ID) {
|
||||
def artifactRootUrl = "https://queue.taskcluster.net/v1/task/${System.env.TASK_ID}/runs/${System.env.RUN_ID}/artifacts"
|
||||
gradle.addListener(makeTaskExecutionListener(artifactRootUrl))
|
||||
}
|
||||
|
|
|
@ -12,4 +12,5 @@ EXTRA_COMPONENTS += [
|
|||
|
||||
DIRS += ['schemas']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
../../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js
|
||||
tags = webextensions
|
||||
|
||||
[test_ext_all_apis.html]
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
/* exported expectedContentApisTargetSpecific, expectedBackgroundApisTargetSpecific */
|
||||
let expectedContentApisTargetSpecific = [
|
||||
];
|
||||
|
||||
let expectedBackgroundApisTargetSpecific = [
|
||||
];
|
||||
</script>
|
||||
<script src="test_ext_all_apis.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -35,16 +35,16 @@
|
|||
"visibility": "public",
|
||||
"filename": "jcentral.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "43754910576cf6173f0dcb215ec7988f2a30dbfe32050f53ac7a9088b8b878c3ead80e02afc1dc31e229386116c82e88a403a309e5b5695f0b74f5defb13dec7",
|
||||
"size": 42832932
|
||||
"digest": "66640e3f77a0f9c0ea52f66c53bee8db3c1a27ea4a11526d15706b9da6a0302cd2d5b088f9addca84f4a962022cba3b76829cb878c90cf9bebb3aab050b4aaa4",
|
||||
"size": 47315996
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "gradle-dist.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "990edc0e4039dbe5f77790ef59dc0d58faebbb8c82ee497615c7991eec99fe4668d0ab05508c48664b635ff6c0cfd4272db464ae1efaa548e471ab451fe0944f",
|
||||
"size": 51955340
|
||||
"digest": "36f961f85b0be846cc9e72bfa0dd1f74e7da8ef785717ce4fd102fec977f21f8902c233b28a21c1ce3797eb2759c7a74c5f74e47bd8f13c1eec640f8d7bed4ac",
|
||||
"size": 51512016
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
|
|
|
@ -50,16 +50,16 @@
|
|||
"visibility": "public",
|
||||
"filename": "jcentral.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "43754910576cf6173f0dcb215ec7988f2a30dbfe32050f53ac7a9088b8b878c3ead80e02afc1dc31e229386116c82e88a403a309e5b5695f0b74f5defb13dec7",
|
||||
"size": 42832932
|
||||
"digest": "66640e3f77a0f9c0ea52f66c53bee8db3c1a27ea4a11526d15706b9da6a0302cd2d5b088f9addca84f4a962022cba3b76829cb878c90cf9bebb3aab050b4aaa4",
|
||||
"size": 47315996
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "gradle-dist.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "990edc0e4039dbe5f77790ef59dc0d58faebbb8c82ee497615c7991eec99fe4668d0ab05508c48664b635ff6c0cfd4272db464ae1efaa548e471ab451fe0944f",
|
||||
"size": 51955340
|
||||
"digest": "36f961f85b0be846cc9e72bfa0dd1f74e7da8ef785717ce4fd102fec977f21f8902c233b28a21c1ce3797eb2759c7a74c5f74e47bd8f13c1eec640f8d7bed4ac",
|
||||
"size": 51512016
|
||||
},
|
||||
{
|
||||
"size": 30899096,
|
||||
|
|
|
@ -60,16 +60,16 @@
|
|||
"visibility": "public",
|
||||
"filename": "jcentral.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "43754910576cf6173f0dcb215ec7988f2a30dbfe32050f53ac7a9088b8b878c3ead80e02afc1dc31e229386116c82e88a403a309e5b5695f0b74f5defb13dec7",
|
||||
"size": 42832932
|
||||
"digest": "66640e3f77a0f9c0ea52f66c53bee8db3c1a27ea4a11526d15706b9da6a0302cd2d5b088f9addca84f4a962022cba3b76829cb878c90cf9bebb3aab050b4aaa4",
|
||||
"size": 47315996
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "gradle-dist.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "990edc0e4039dbe5f77790ef59dc0d58faebbb8c82ee497615c7991eec99fe4668d0ab05508c48664b635ff6c0cfd4272db464ae1efaa548e471ab451fe0944f",
|
||||
"size": 51955340
|
||||
"digest": "36f961f85b0be846cc9e72bfa0dd1f74e7da8ef785717ce4fd102fec977f21f8902c233b28a21c1ce3797eb2759c7a74c5f74e47bd8f13c1eec640f8d7bed4ac",
|
||||
"size": 51512016
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.11.0 (9b21dcd6a 2016-08-15) repack",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
package org.mozilla.gecko.background.testhelpers;
|
||||
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.robolectric.RobolectricGradleTestRunner;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.manifest.AndroidManifest;
|
||||
import org.robolectric.res.FileFsFile;
|
||||
|
@ -46,7 +46,7 @@ import org.robolectric.util.ReflectionHelpers;
|
|||
* that uses a Gradle `buildConfigField` to find build outputs.
|
||||
* See https://github.com/robolectric/robolectric/issues/1648#issuecomment-113731011.
|
||||
*/
|
||||
public class TestRunner extends RobolectricGradleTestRunner {
|
||||
public class TestRunner extends RobolectricTestRunner {
|
||||
private FsFile buildFolder;
|
||||
|
||||
public TestRunner(Class<?> klass) throws InitializationError {
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -51,6 +52,13 @@ public class BrowserProviderHistoryTest extends BrowserProviderHistoryVisitsTest
|
|||
).build();
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() {
|
||||
thumbnailClient.release();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test aggressive expiration on new (recent) history items
|
||||
*/
|
||||
|
|
|
@ -54,7 +54,7 @@ public class BrowserProviderHistoryVisitsTestBase {
|
|||
}
|
||||
|
||||
/* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount) throws RemoteException {
|
||||
return insertHistoryItem(url, guid, System.currentTimeMillis(), null, null);
|
||||
return insertHistoryItem(url, guid, lastVisited, visitCount, null);
|
||||
}
|
||||
|
||||
/* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount, String title) throws RemoteException {
|
||||
|
|
|
@ -79,4 +79,10 @@ interface nsIUnicharStreamLoader : nsIStreamListener
|
|||
* called.
|
||||
*/
|
||||
readonly attribute ACString charset;
|
||||
|
||||
/**
|
||||
* Get the raw bytes as seen on the wire prior to character converstion.
|
||||
* Used by Subresource Integrity checker to generate the correct hash.
|
||||
*/
|
||||
readonly attribute ACString rawBuffer;
|
||||
};
|
||||
|
|
|
@ -102,10 +102,19 @@ nsUnicharStreamLoader::OnStopRequest(nsIRequest *aRequest,
|
|||
mContext = nullptr;
|
||||
mChannel = nullptr;
|
||||
mCharset.Truncate();
|
||||
mRawData.Truncate();
|
||||
mRawBuffer.Truncate();
|
||||
mBuffer.Truncate();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUnicharStreamLoader::GetRawBuffer(nsACString& aRawBuffer)
|
||||
{
|
||||
aRawBuffer = mRawBuffer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIStreamListener implementation */
|
||||
NS_IMETHODIMP
|
||||
nsUnicharStreamLoader::OnDataAvailable(nsIRequest *aRequest,
|
||||
|
@ -220,6 +229,10 @@ nsUnicharStreamLoader::WriteSegmentFun(nsIInputStream *,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!self->mRawBuffer.Append(aSegment, aCount, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = self->mDecoder->Convert(aSegment,
|
||||
&srcLen,
|
||||
self->mBuffer.BeginWriting() + haveRead,
|
||||
|
|
|
@ -47,6 +47,10 @@ protected:
|
|||
// It will be passed to the OnDetermineCharset callback.
|
||||
nsCString mRawData;
|
||||
|
||||
// Holds complete raw bytes as received so that SRI checks can be
|
||||
// calculated on the raw data prior to character conversion.
|
||||
nsCString mRawBuffer;
|
||||
|
||||
// This holds the complete contents of the stream so far, after
|
||||
// decoding to UTF-16. It will be passed to the OnStreamComplete
|
||||
// callback.
|
||||
|
|
|
@ -15,6 +15,9 @@ from mozbuild.shellutil import quote as shell_quote
|
|||
from .common import CommonBackend
|
||||
from ..frontend.data import (
|
||||
ContextDerived,
|
||||
Defines,
|
||||
GeneratedFile,
|
||||
HostDefines,
|
||||
)
|
||||
from ..util import (
|
||||
FileAvoidWrite,
|
||||
|
@ -33,6 +36,9 @@ class BackendTupfile(object):
|
|||
self.environment = environment
|
||||
self.name = mozpath.join(objdir, 'Tupfile')
|
||||
self.rules_included = False
|
||||
self.shell_exported = False
|
||||
self.defines = []
|
||||
self.host_defines = []
|
||||
|
||||
self.fh = FileAvoidWrite(self.name, capture_diff=True)
|
||||
self.fh.write('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.\n')
|
||||
|
@ -46,18 +52,39 @@ class BackendTupfile(object):
|
|||
self.write('include_rules\n')
|
||||
self.rules_included = True
|
||||
|
||||
def rule(self, cmd, inputs=None, outputs=None, display=None, extra_outputs=None):
|
||||
def rule(self, cmd, inputs=None, outputs=None, display=None, extra_outputs=None, check_unchanged=False):
|
||||
inputs = inputs or []
|
||||
outputs = outputs or []
|
||||
display = display or ""
|
||||
self.include_rules()
|
||||
flags = ""
|
||||
if check_unchanged:
|
||||
# This flag causes tup to compare the outputs with the previous run
|
||||
# of the command, and skip the rest of the DAG for any that are the
|
||||
# same.
|
||||
flags += "o"
|
||||
|
||||
if display:
|
||||
caret_text = flags + ' ' + display
|
||||
else:
|
||||
caret_text = flags
|
||||
|
||||
self.write(': %(inputs)s |> %(display)s%(cmd)s |> %(outputs)s%(extra_outputs)s\n' % {
|
||||
'inputs': ' '.join(inputs),
|
||||
'display': '^ %s^ ' % display if display else '',
|
||||
'display': '^%s^ ' % caret_text if caret_text else '',
|
||||
'cmd': ' '.join(cmd),
|
||||
'outputs': ' '.join(outputs),
|
||||
'extra_outputs': ' | ' + ' '.join(extra_outputs) if extra_outputs else '',
|
||||
})
|
||||
|
||||
def export_shell(self):
|
||||
if not self.shell_exported:
|
||||
# These are used by mach/mixin/process.py to determine the current
|
||||
# shell.
|
||||
for var in ('SHELL', 'MOZILLABUILD', 'COMSPEC'):
|
||||
self.write('export %s\n' % var)
|
||||
self.shell_exported = True
|
||||
|
||||
def close(self):
|
||||
return self.fh.close()
|
||||
|
||||
|
@ -85,6 +112,17 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
self.environment.topsrcdir, self.environment.topobjdir)
|
||||
return self._backend_files[objdir]
|
||||
|
||||
def _get_backend_file_for(self, obj):
|
||||
return self._get_backend_file(obj.relativedir)
|
||||
|
||||
def _py_action(self, action):
|
||||
cmd = [
|
||||
'$(PYTHON)',
|
||||
'-m',
|
||||
'mozbuild.action.%s' % action,
|
||||
]
|
||||
return cmd
|
||||
|
||||
def consume_object(self, obj):
|
||||
"""Write out build files necessary to build with tup."""
|
||||
|
||||
|
@ -98,6 +136,43 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
if consumed:
|
||||
return False
|
||||
|
||||
backend_file = self._get_backend_file_for(obj)
|
||||
|
||||
if isinstance(obj, GeneratedFile):
|
||||
# TODO: These are directories that don't work in the tup backend
|
||||
# yet, because things they depend on aren't built yet.
|
||||
skip_directories = (
|
||||
'build', # FinalTargetPreprocessedFiles
|
||||
'layout/style/test', # HostSimplePrograms
|
||||
'toolkit/library', # libxul.so
|
||||
)
|
||||
if obj.script and obj.method and obj.relobjdir not in skip_directories:
|
||||
backend_file.export_shell()
|
||||
cmd = self._py_action('file_generate')
|
||||
cmd.extend([
|
||||
obj.script,
|
||||
obj.method,
|
||||
obj.outputs[0],
|
||||
'%s.pp' % obj.outputs[0], # deps file required
|
||||
])
|
||||
full_inputs = [f.full_path for f in obj.inputs]
|
||||
cmd.extend(full_inputs)
|
||||
|
||||
outputs = []
|
||||
outputs.extend(obj.outputs)
|
||||
outputs.append('%s.pp' % obj.outputs[0])
|
||||
|
||||
backend_file.rule(
|
||||
display='python {script}:{method} -> [%o]'.format(script=obj.script, method=obj.method),
|
||||
cmd=cmd,
|
||||
inputs=full_inputs,
|
||||
outputs=outputs,
|
||||
)
|
||||
elif isinstance(obj, Defines):
|
||||
self._process_defines(backend_file, obj)
|
||||
elif isinstance(obj, HostDefines):
|
||||
self._process_defines(backend_file, obj, host=True)
|
||||
|
||||
return True
|
||||
|
||||
def consume_finished(self):
|
||||
|
@ -123,34 +198,24 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
fh.write('PYTHON_PATH = $(PYTHON) $(topsrcdir)/config/pythonpath.py\n')
|
||||
fh.write('PLY_INCLUDE = -I$(topsrcdir)/other-licenses/ply\n')
|
||||
fh.write('IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser\n')
|
||||
fh.write('IDL_PARSER_CACHE_DIR = $(MOZ_OBJ_ROOT)/xpcom/idl-parser\n')
|
||||
fh.write('IDL_PARSER_CACHE_DIR = $(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl\n')
|
||||
|
||||
# Run 'tup init' if necessary.
|
||||
if not os.path.exists(mozpath.join(self.environment.topsrcdir, ".tup")):
|
||||
tup = self.environment.substs.get('TUP', 'tup')
|
||||
self._cmd.run_process(cwd=self.environment.topsrcdir, log_name='tup', args=[tup, 'init'])
|
||||
|
||||
def _process_defines(self, backend_file, obj, host=False):
|
||||
defines = list(obj.get_defines())
|
||||
if defines:
|
||||
if host:
|
||||
backend_file.host_defines = defines
|
||||
else:
|
||||
backend_file.defines = defines
|
||||
|
||||
def _handle_idl_manager(self, manager):
|
||||
|
||||
# TODO: This should come from GENERATED_FILES, and can be removed once
|
||||
# those are implemented.
|
||||
backend_file = self._get_backend_file('xpcom/idl-parser')
|
||||
backend_file.rule(
|
||||
display='python header.py -> [%o]',
|
||||
cmd=[
|
||||
'$(PYTHON_PATH)',
|
||||
'$(PLY_INCLUDE)',
|
||||
'$(topsrcdir)/xpcom/idl-parser/xpidl/header.py',
|
||||
],
|
||||
outputs=['xpidlyacc.py', 'xpidllex.py'],
|
||||
)
|
||||
|
||||
backend_file = self._get_backend_file('xpcom/xpidl')
|
||||
|
||||
# These are used by mach/mixin/process.py to determine the current
|
||||
# shell.
|
||||
for var in ('SHELL', 'MOZILLABUILD', 'COMSPEC'):
|
||||
backend_file.write('export %s\n' % var)
|
||||
backend_file.export_shell()
|
||||
|
||||
for module, data in sorted(manager.modules.iteritems()):
|
||||
dest, idls = data
|
||||
|
@ -160,7 +225,7 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
'-I$(IDL_PARSER_DIR)',
|
||||
'-I$(IDL_PARSER_CACHE_DIR)',
|
||||
'$(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py',
|
||||
'--cache-dir', '$(MOZ_OBJ_ROOT)/xpcom/idl-parser',
|
||||
'--cache-dir', '$(IDL_PARSER_CACHE_DIR)',
|
||||
'$(DIST)/idl',
|
||||
'$(DIST)/include',
|
||||
'$(MOZ_OBJ_ROOT)/%s/components' % dest,
|
||||
|
@ -172,14 +237,26 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
outputs.extend(['$(MOZ_OBJ_ROOT)/dist/include/%s.h' % f for f in sorted(idls)])
|
||||
backend_file.rule(
|
||||
inputs=[
|
||||
'$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidllex.py',
|
||||
'$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidlyacc.py',
|
||||
'$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidllex.py',
|
||||
'$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidlyacc.py',
|
||||
],
|
||||
display='XPIDL %s' % module,
|
||||
cmd=cmd,
|
||||
outputs=outputs,
|
||||
)
|
||||
|
||||
def _preprocess(self, backend_file, input_file):
|
||||
cmd = self._py_action('preprocessor')
|
||||
cmd.extend(backend_file.defines)
|
||||
cmd.extend(['$(ACDEFINES)', '%f', '-o', '%o'])
|
||||
|
||||
backend_file.rule(
|
||||
inputs=[input_file],
|
||||
display='Preprocess %o',
|
||||
cmd=cmd,
|
||||
outputs=[mozpath.basename(input_file)],
|
||||
)
|
||||
|
||||
def _handle_ipdl_sources(self, ipdl_dir, sorted_ipdl_sources,
|
||||
unified_ipdl_cppsrcs_mapping):
|
||||
# TODO: This isn't implemented yet in the tup backend, but it is called
|
||||
|
@ -189,9 +266,33 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
def _handle_webidl_build(self, bindings_dir, unified_source_mapping,
|
||||
webidls, expected_build_output_files,
|
||||
global_define_files):
|
||||
# TODO: This isn't implemented yet in the tup backend, but it is called
|
||||
# by the CommonBackend.
|
||||
pass
|
||||
backend_file = self._get_backend_file('dom/bindings')
|
||||
backend_file.export_shell()
|
||||
|
||||
for source in sorted(webidls.all_preprocessed_sources()):
|
||||
self._preprocess(backend_file, source)
|
||||
|
||||
cmd = self._py_action('webidl')
|
||||
cmd.append(mozpath.join(self.environment.topsrcdir, 'dom', 'bindings'))
|
||||
|
||||
# The WebIDLCodegenManager knows all of the .cpp and .h files that will
|
||||
# be created (expected_build_output_files), but there are a few
|
||||
# additional files that are also created by the webidl py_action.
|
||||
outputs = [
|
||||
'_cache/webidlyacc.py',
|
||||
'codegen.json',
|
||||
'codegen.pp',
|
||||
'parser.out',
|
||||
]
|
||||
outputs.extend(expected_build_output_files)
|
||||
|
||||
backend_file.rule(
|
||||
display='WebIDL code generation',
|
||||
cmd=cmd,
|
||||
inputs=webidls.all_non_static_basenames(),
|
||||
outputs=outputs,
|
||||
check_unchanged=True,
|
||||
)
|
||||
|
||||
|
||||
class TupBackend(HybridBackend(TupOnly, RecursiveMakeBackend)):
|
||||
|
|
|
@ -1162,4 +1162,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1482583977213000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1483189296336000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -65,7 +65,7 @@ class CollectionValidator {
|
|||
}
|
||||
|
||||
getServerItems(engine) {
|
||||
let collection = engine._itemSource();
|
||||
let collection = engine.itemSource();
|
||||
let collectionKey = engine.service.collectionKeys.keyForCollection(engine.name);
|
||||
collection.full = true;
|
||||
let items = [];
|
||||
|
|
|
@ -1140,13 +1140,14 @@ add_task(function* test_onItemDeleted_removeFolderTransaction() {
|
|||
|
||||
_("Undo the remove folder transaction");
|
||||
txn.undoTransaction();
|
||||
yield verifyTrackedItems(["menu"]);
|
||||
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
|
||||
yield resetTracker();
|
||||
|
||||
// At this point, the restored folder has the same ID, but a different GUID.
|
||||
let new_folder_guid = yield PlacesUtils.promiseItemGuid(folder_id);
|
||||
|
||||
yield verifyTrackedItems(["menu", new_folder_guid]);
|
||||
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
|
||||
yield resetTracker();
|
||||
|
||||
_("Redo the transaction");
|
||||
txn.redoTransaction();
|
||||
yield verifyTrackedItems(["menu", new_folder_guid]);
|
||||
|
|
|
@ -612,7 +612,7 @@ var TPS = {
|
|||
|
||||
let getServerBookmarkState = () => {
|
||||
let bookmarkEngine = Weave.Service.engineManager.get('bookmarks');
|
||||
let collection = bookmarkEngine._itemSource();
|
||||
let collection = bookmarkEngine.itemSource();
|
||||
let collectionKey = bookmarkEngine.service.collectionKeys.keyForCollection(bookmarkEngine.name);
|
||||
collection.full = true;
|
||||
let items = [];
|
||||
|
|
|
@ -29,6 +29,8 @@ job-defaults:
|
|||
# the functionality that l10n needs
|
||||
|
||||
JOB_SCRIPT: "taskcluster/scripts/builder/build-l10n.sh"
|
||||
# don't run anywhere by default, but still available via try
|
||||
run-on-projects: []
|
||||
when:
|
||||
files-changed:
|
||||
- browser/locales/all-locales
|
||||
|
|
|
@ -23,9 +23,7 @@ logger = logging.getLogger(__name__)
|
|||
CONCURRENCY = 50
|
||||
|
||||
|
||||
def create_tasks(taskgraph, label_to_taskid):
|
||||
# TODO: use the taskGroupId of the decision task
|
||||
task_group_id = slugid()
|
||||
def create_tasks(taskgraph, label_to_taskid, params):
|
||||
taskid_to_label = {t: l for l, t in label_to_taskid.iteritems()}
|
||||
|
||||
session = requests.Session()
|
||||
|
@ -40,6 +38,13 @@ def create_tasks(taskgraph, label_to_taskid):
|
|||
|
||||
decision_task_id = os.environ.get('TASK_ID')
|
||||
|
||||
# when running as an actual decision task, we use the decision task's
|
||||
# taskId as the taskGroupId. The process that created the decision task
|
||||
# helpfully placed it in this same taskGroup. If there is no $TASK_ID,
|
||||
# fall back to a slugid
|
||||
task_group_id = decision_task_id or slugid()
|
||||
scheduler_id = 'gecko-level-{}'.format(params['level'])
|
||||
|
||||
with futures.ThreadPoolExecutor(CONCURRENCY) as e:
|
||||
fs = {}
|
||||
|
||||
|
@ -62,7 +67,7 @@ def create_tasks(taskgraph, label_to_taskid):
|
|||
task_def['dependencies'] = [decision_task_id]
|
||||
|
||||
task_def['taskGroupId'] = task_group_id
|
||||
task_def['schedulerId'] = '-'
|
||||
task_def['schedulerId'] = scheduler_id
|
||||
|
||||
# Wait for dependencies before submitting this.
|
||||
deps_fs = [fs[dep] for dep in task_def.get('dependencies', [])
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче