Merge m-c to b2ginbound, a=merge CLOSED TREE

--HG--
extra : commitid : 6BLSZLPbxgy
This commit is contained in:
Wes Kocher 2015-11-12 16:27:09 -08:00
commit 2ff0ac22d3
136 changed files with 1743 additions and 1090 deletions

View File

@ -60,9 +60,7 @@ var CustomizationHandler = {
if (aDetails.changed) {
gURLBar = document.getElementById("urlbar");
gProxyFavIcon = document.getElementById("page-proxy-favicon");
gHomeButton.updateTooltip();
gIdentityHandler._cacheElements();
XULBrowserWindow.init();
#ifndef XP_MACOSX

View File

@ -370,7 +370,7 @@ var PlacesCommandHook = {
// Try to dock the panel to:
// 1. the bookmarks menu button
// 2. the page-proxy-favicon
// 2. the identity icon
// 3. the content area
if (BookmarkingUI.anchor) {
StarUI.showEditBookmarkPopup(itemId, BookmarkingUI.anchor,
@ -378,9 +378,9 @@ var PlacesCommandHook = {
return;
}
let pageProxyFavicon = document.getElementById("page-proxy-favicon");
if (isElementVisible(pageProxyFavicon)) {
StarUI.showEditBookmarkPopup(itemId, pageProxyFavicon,
let identityIcon = document.getElementById("identity-icon");
if (isElementVisible(identityIcon)) {
StarUI.showEditBookmarkPopup(itemId, identityIcon,
"bottomcenter topright");
} else {
StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap");
@ -446,7 +446,7 @@ var PlacesCommandHook = {
// Try to dock the panel to:
// 1. the bookmarks menu button
// 2. the page-proxy-favicon
// 2. the identity icon
// 3. the content area
if (BookmarkingUI.anchor) {
StarUI.showEditBookmarkPopup(node, BookmarkingUI.anchor,
@ -454,9 +454,9 @@ var PlacesCommandHook = {
return;
}
let pageProxyFavicon = document.getElementById("page-proxy-favicon");
if (isElementVisible(pageProxyFavicon)) {
StarUI.showEditBookmarkPopup(node, pageProxyFavicon,
let identityIcon = document.getElementById("identity-icon");
if (isElementVisible(identityIcon)) {
StarUI.showEditBookmarkPopup(node, identityIcon,
"bottomcenter topright");
} else {
StarUI.showEditBookmarkPopup(node, aBrowser, "overlap");

View File

@ -95,7 +95,6 @@ XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
const nsIWebNavigation = Ci.nsIWebNavigation;
var gLastBrowserCharset = null;
var gProxyFavIcon = null;
var gLastValidURLStr = "";
var gInPrintPreviewMode = false;
var gContextMenu = null; // nsContextMenu instance
@ -2562,11 +2561,7 @@ function SetPageProxyState(aState)
if (!gURLBar)
return;
if (!gProxyFavIcon)
gProxyFavIcon = document.getElementById("page-proxy-favicon");
gURLBar.setAttribute("pageproxystate", aState);
gProxyFavIcon.setAttribute("pageproxystate", aState);
// the page proxy state is set to valid via OnLocationChange, which
// gets called when we switch tabs.
@ -7001,38 +6996,15 @@ var gIdentityHandler = {
delete this._identityIconCountryLabel;
return this._identityIconCountryLabel = document.getElementById("identity-icon-country-label");
},
get _identityIcons () {
delete this._identityIcons;
return this._identityIcons = document.getElementById("identity-icons");
},
get _identityIcon () {
delete this._identityIcon;
return this._identityIcon = document.getElementById("page-proxy-favicon");
return this._identityIcon = document.getElementById("identity-icon");
},
get _permissionList () {
delete this._permissionList;
return this._permissionList = document.getElementById("identity-popup-permission-list");
},
/**
* Rebuild cache of the elements that may or may not exist depending
* on whether there's a location bar.
*/
_cacheElements : function() {
delete this._identityBox;
delete this._identityIcons;
delete this._identityIconLabel;
delete this._identityIconCountryLabel;
delete this._identityIcon;
delete this._permissionList;
this._identityBox = document.getElementById("identity-box");
this._identityIcons = document.getElementById("identity-icons");
this._identityIconLabel = document.getElementById("identity-icon-label");
this._identityIconCountryLabel = document.getElementById("identity-icon-country-label");
this._identityIcon = document.getElementById("page-proxy-favicon");
this._permissionList = document.getElementById("identity-popup-permission-list");
},
/**
* Handler for mouseclicks on the "More Information" button in the
* "identity-popup" panel.
@ -7532,7 +7504,7 @@ var gIdentityHandler = {
this._identityBox.setAttribute("open", "true");
// Now open the popup, anchored off the primary chrome element
this._identityPopup.openPopup(this._identityIcons, "bottomcenter topleft");
this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
},
onPopupShown(event) {
@ -7575,7 +7547,7 @@ var gIdentityHandler = {
dt.setData("text/uri-list", value);
dt.setData("text/plain", value);
dt.setData("text/html", htmlString);
dt.setDragImage(gProxyFavIcon, 16, 16);
dt.setDragImage(this._identityIcon, 16, 16);
},
updateSitePermissions: function () {

View File

@ -704,7 +704,7 @@
<image id="plugins-notification-icon" class="notification-anchor-icon" role="button"
aria-label="&urlbar.pluginsNotificationAnchor.label;"/>
<image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"
aria-label="&urlbar.webNotsNotificationAnchor2.label;"/>
aria-label="&urlbar.webNotsNotificationAnchor3.label;"/>
<image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"
aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
<image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"
@ -738,13 +738,11 @@
onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
ondragstart="gIdentityHandler.onDragStart(event);">
<hbox id="identity-icons"
consumeanchor="identity-box">
<image id="tracking-protection-icon"/>
<image id="page-proxy-favicon"
onclick="PageProxyClickHandler(event);"
pageproxystate="invalid"/>
</hbox>
<image id="identity-icon"
consumeanchor="identity-box"
onclick="PageProxyClickHandler(event);"/>
<image id="tracking-protection-icon"/>
<image id="connection-icon"/>
<hbox id="identity-icon-labels">
<label id="identity-icon-label" class="plain" flex="1"/>
<label id="identity-icon-country-label" class="plain"/>

View File

@ -41,8 +41,9 @@ add_task(function* test_simple() {
document.getElementById("identity-popup-security-expander").click();
if (expectWarning) {
let identityBoxImage = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("page-proxy-favicon"), "")
is_element_visible(document.getElementById("connection-icon"));
let connectionIconImage = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("connection-icon"), "")
.getPropertyValue("list-style-image");
let securityViewBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-securityView"), "")
@ -50,7 +51,7 @@ add_task(function* test_simple() {
let securityContentBG = gBrowser.ownerGlobal
.getComputedStyle(document.getElementById("identity-popup-security-content"), "")
.getPropertyValue("background-image");
is(identityBoxImage,
is(connectionIconImage,
"url(\"chrome://browser/skin/identity-mixed-active-loaded.svg\")",
"Using expected icon image in the identity block");
is(securityViewBG,

View File

@ -781,7 +781,8 @@ function assertMixedContentBlockingState(tabbrowser, states = {}) {
let doc = tabbrowser.ownerDocument;
let identityBox = gIdentityHandler._identityBox;
let classList = identityBox.classList;
let identityBoxImage = tabbrowser.ownerGlobal.getComputedStyle(doc.getElementById("page-proxy-favicon"), "").
let connectionIcon = doc.getElementById("connection-icon");
let connectionIconImage = tabbrowser.ownerGlobal.getComputedStyle(connectionIcon, "").
getPropertyValue("list-style-image");
let stateSecure = gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_SECURE;
@ -799,7 +800,7 @@ function assertMixedContentBlockingState(tabbrowser, states = {}) {
// HTTP request, there should be no MCB classes for the identity box and the non secure icon
// should always be visible regardless of MCB state.
ok(classList.contains("unknownIdentity"), "unknownIdentity on HTTP page");
is(identityBoxImage, "url(\"chrome://browser/skin/identity-not-secure.svg\")", "Using 'non-secure' icon");
is_element_hidden(connectionIcon);
ok(!classList.contains("mixedActiveContent"), "No MCB icon on HTTP page");
ok(!classList.contains("mixedActiveBlocked"), "No MCB icon on HTTP page");
@ -816,20 +817,21 @@ function assertMixedContentBlockingState(tabbrowser, states = {}) {
is(classList.contains("mixedDisplayContentLoadedActiveBlocked"), passiveLoaded && activeBlocked,
"identityBox has expected class for passiveLoaded && activeBlocked");
is_element_visible(connectionIcon);
if (activeLoaded) {
is(identityBoxImage, "url(\"chrome://browser/skin/identity-mixed-active-loaded.svg\")",
is(connectionIconImage, "url(\"chrome://browser/skin/identity-mixed-active-loaded.svg\")",
"Using active loaded icon");
}
if (activeBlocked && !passiveLoaded) {
is(identityBoxImage, "url(\"chrome://browser/skin/identity-mixed-active-blocked.svg\")",
is(connectionIconImage, "url(\"chrome://browser/skin/identity-mixed-active-blocked.svg\")",
"Using active blocked icon");
}
if (passiveLoaded && !(activeLoaded || activeBlocked)) {
is(identityBoxImage, "url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
is(connectionIconImage, "url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
"Using passive loaded icon");
}
if (passiveLoaded && activeBlocked) {
is(identityBoxImage, "url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
is(connectionIconImage, "url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
"Using active blocked and passive loaded icon");
}
}

View File

@ -201,7 +201,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.passwordNotificationAnchor.label "Check if you want to save your password">
<!ENTITY urlbar.webappsNotificationAnchor.label "View the app install message">
<!ENTITY urlbar.pluginsNotificationAnchor.label "Manage plugin usage on this page">
<!ENTITY urlbar.webNotsNotificationAnchor2.label "Change whether the site can receive notifications">
<!ENTITY urlbar.webNotsNotificationAnchor3.label "Change whether you can receive notifications from the site">
<!ENTITY urlbar.webRTCShareDevicesNotificationAnchor.label "Manage sharing your camera and/or microphone with the site">
<!ENTITY urlbar.webRTCSharingDevicesNotificationAnchor.label "You are sharing your camera and/or microphone with the site">

View File

@ -75,13 +75,42 @@
padding-inline-start: calc(var(--backbutton-urlbar-overlap) + 4.01px);
}
/* MAIN IDENTITY ICON */
#identity-icon {
width: 16px;
height: 16px;
list-style-image: url(chrome://browser/skin/identity-icon.svg#normal);
}
#identity-box:hover > #identity-icon,
#identity-box[open=true] > #identity-icon {
list-style-image: url(chrome://browser/skin/identity-icon.svg#hover);
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon {
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
}
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon {
opacity: 0.3;
}
#urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
-moz-image-region: inherit;
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
width: 16px;
height: 16px;
opacity: 1;
}
/* TRACKING PROTECTION ICON */
#tracking-protection-icon {
width: 16px;
height: 16px;
margin-inline-start: 0;
margin-inline-end: 2px;
margin-inline-start: 2px;
margin-inline-end: 0;
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
opacity: 1;
}
@ -95,57 +124,46 @@
}
#tracking-protection-icon:not([state]) {
margin-inline-start: -18px;
margin-inline-end: -18px;
pointer-events: none;
opacity: 0;
/* Only animate the shield in, when it disappears hide it immediately. */
transition: none;
}
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icons > #tracking-protection-icon {
#urlbar[pageproxystate="invalid"] > #identity-box > #tracking-protection-icon {
visibility: collapse;
}
/* MAIN IDENTITY ICON */
/* CONNECTION ICON */
#page-proxy-favicon {
#connection-icon {
width: 16px;
height: 16px;
list-style-image: url(chrome://browser/skin/identity-not-secure.svg);
margin-inline-start: 2px;
visibility: collapse;
}
.chromeUI > #identity-icons > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
}
.verifiedDomain > #identity-icons > #page-proxy-favicon[pageproxystate="valid"],
.verifiedIdentity > #identity-icons > #page-proxy-favicon[pageproxystate="valid"] {
#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon {
list-style-image: url(chrome://browser/skin/identity-secure.svg);
visibility: visible;
}
.insecureLoginForms > #identity-icons > #page-proxy-favicon[pageproxystate="valid"],
.mixedActiveContent > #identity-icons > #page-proxy-favicon[pageproxystate="valid"] {
#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon {
list-style-image: url(chrome://browser/skin/identity-mixed-active-loaded.svg);
visibility: visible;
}
.weakCipher > #identity-icons > #page-proxy-favicon[pageproxystate="valid"],
.mixedDisplayContent > #identity-icons > #page-proxy-favicon[pageproxystate="valid"],
.mixedDisplayContentLoadedActiveBlocked > #identity-icons > #page-proxy-favicon[pageproxystate="valid"] {
#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon {
list-style-image: url(chrome://browser/skin/identity-mixed-passive-loaded.svg);
visibility: visible;
}
.mixedActiveBlocked > #identity-icons > #page-proxy-favicon[pageproxystate="valid"] {
#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon {
list-style-image: url(chrome://browser/skin/identity-mixed-active-blocked.svg);
}
#page-proxy-favicon[pageproxystate="invalid"] {
opacity: 0.3;
}
#urlbar[actiontype="searchengine"] > #identity-box > #identity-icons > #page-proxy-favicon {
-moz-image-region: inherit;
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
width: 16px;
height: 16px;
opacity: 1;
visibility: visible;
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="48" height="16" viewBox="0 0 32 16">
<defs>
<circle id="shape-circle-base" cx="8" cy="8" r="7" />
<g id="shape-i">
<circle cx="8" cy="5" r="1" />
<rect x="7" y="7" width="2" height="5" rx="1" ry="1" />
</g>
<mask id="mask-ring-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-circle-base" fill="#fff" />
<circle cx="8" cy="8" r="6" fill="#000" />
</mask>
</defs>
<view id="normal" viewBox="0 0 16 16"/>
<g>
<use xlink:href="#shape-circle-base" mask="url(#mask-ring-cutout)" fill="#999" />
<use xlink:href="#shape-i" fill="#999" />
</g>
<view id="hover" viewBox="16 0 16 16"/>
<g transform="translate(16)">
<use xlink:href="#shape-circle-base" fill="#4c9ed9" />
<use xlink:href="#shape-i" fill="#fff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -59,6 +59,7 @@
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
skin/classic/browser/identity-not-secure.svg (../shared/identity-block/identity-not-secure.svg)
skin/classic/browser/identity-secure.svg (../shared/identity-block/identity-secure.svg)
skin/classic/browser/identity-mixed-active-blocked.svg (../shared/identity-block/identity-mixed-active-blocked.svg)

View File

@ -82,8 +82,7 @@ DevTools.prototype = {
* - invertIconForLightTheme: The icon can automatically have an inversion
* filter applied (default is false). All builtin tools are true, but
* addons may omit this to prevent unwanted changes to the `icon`
* image. See devtools/client/themes/filters.svg#invert for
* the filter being applied to the images (boolean|optional)
* image. filter: invert(1) is applied to the image (boolean|optional)
* - url: URL pointing to a XUL/XHTML document containing the user interface
* (string|required)
* - label: Localized name for the tool to be displayed to the user

View File

@ -162,10 +162,6 @@ devtools.jar:
skin/images/controls@2x.png (themes/images/controls@2x.png)
skin/images/animation-fast-track.svg (themes/images/animation-fast-track.svg)
skin/images/performance-icons.svg (themes/images/performance-icons.svg)
skin/images/newtab.png (themes/images/newtab.png)
skin/images/newtab@2x.png (themes/images/newtab@2x.png)
skin/images/newtab-inverted.png (themes/images/newtab-inverted.png)
skin/images/newtab-inverted@2x.png (themes/images/newtab-inverted@2x.png)
* skin/widgets.css (themes/widgets.css)
skin/images/power.svg (themes/images/power.svg)
skin/images/filetypes/dir-close.svg (themes/images/filetypes/dir-close.svg)
@ -288,7 +284,6 @@ devtools.jar:
skin/floating-scrollbars-light.css (themes/floating-scrollbars-light.css)
* skin/inspector.css (themes/inspector.css)
skin/images/profiler-stopwatch.svg (themes/images/profiler-stopwatch.svg)
skin/images/profiler-stopwatch-checked.svg (themes/images/profiler-stopwatch-checked.svg)
skin/images/tool-options.svg (themes/images/tool-options.svg)
skin/images/tool-webconsole.svg (themes/images/tool-webconsole.svg)
skin/images/tool-canvas.svg (themes/images/tool-canvas.svg)

View File

@ -19,6 +19,6 @@
</head>
<body role="application">
<div id="spectrum"></div>
<div id="eyedropper-button"></div>
<button id="eyedropper-button" class="devtools-button"></button>
</body>
</html>
</html>

View File

@ -3,38 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#eyedropper-button {
margin-inline-start: 5px;
}
#eyedropper-button::before {
background-image: url("chrome://devtools/skin/images/command-eyedropper.png");
width: 16px;
height: 16px;
background-size: 64px 16px;
background-position: 0 center;
background-repeat: no-repeat;
-moz-margin-start: 5px;
border-radius: 2px;
cursor: pointer;
}
.theme-light #eyedropper-button {
filter: url(chrome://devtools/skin/images/filters.svg#invert);
border: 1px solid #AAA;
}
.theme-dark #eyedropper-button {
border: 1px solid #444;
}
#eyedropper-button:hover {
background-position: -16px center;
}
#eyedropper-button:hover:active {
background-position: -32px center;
}
#eyedropper-button[checked=true] {
background-position: -48px center;
}
@media (min-resolution: 1.1dppx) {
#eyedropper-button {
#eyedropper-button::before {
background-image: url("chrome://devtools/skin/images/command-eyedropper@2x.png");
}
}

View File

@ -133,11 +133,6 @@ body {
background-image: url("images/rewind.png");
}
#element-picker[checked]::before {
background-position: -48px 0;
filter: none; /* Icon is blue when checked, don't invert for light theme */
}
.pause-button.paused::before {
background-image: url("images/debugger-play.png");
}
@ -404,12 +399,12 @@ body {
}
.animation-target .node-highlighter:hover {
background-position: -32px 0;
filter: url(images/filters.svg#checked-icon-state);
}
.animation-target .node-highlighter:active,
.animation-target .node-highlighter.selected {
background-position: -16px 0;
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
}
/* Animation title gutter, contains the name, duration, iteration */

View File

@ -42,10 +42,6 @@
list-style-image: url("chrome://devtools/skin/images/profiler-stopwatch.svg");
}
#record-snapshot[checked] {
list-style-image: url("chrome://devtools/skin/images/profiler-stopwatch-checked.svg");
}
/* Snapshots items */
.snapshot-item-thumbnail {
@ -103,15 +99,8 @@
}
/* Debugging pane controls */
#debugging-controls .devtools-toolbarbutton > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
#resume {
list-style-image: url(images/debugger-play.png);
-moz-image-region: rect(0px,32px,16px,16px);
}
#step-over {
@ -129,7 +118,6 @@
@media (min-resolution: 1.1dppx) {
#resume {
list-style-image: url(images/debugger-play@2x.png);
-moz-image-region: rect(0px,64px,32px,32px);
}
#step-over {
@ -145,14 +133,6 @@
}
}
#debugging-controls > toolbarbutton {
transition: opacity 0.15s ease-in-out;
}
#debugging-controls > toolbarbutton[disabled=true] {
opacity: 0.5;
}
#calls-slider {
-moz-padding-end: 24px;
}

View File

@ -52,7 +52,7 @@
:root[devtoolstheme="light"] #developer-toolbar > toolbarbutton:not([checked=true]) > image,
:root[devtoolstheme="light"] .gclitoolbar-input-node:not([focused=true])::before {
filter: url("chrome://devtools/skin/images/filters.svg#invert");
filter: invert(1);
}
.developer-toolbar-button > .toolbarbutton-icon,

View File

@ -62,6 +62,10 @@
min-width: 32px;
}
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0,16px,16px,0);
}
#black-box {
list-style-image: url(images/debugger-blackbox.png);
}
@ -86,34 +90,33 @@
list-style-image: url(images/debugger-toggleBreakpoints.png);
}
#toggle-breakpoints[checked] {
-moz-image-region: rect(0,32px,16px,16px) !important;
}
#toggle-breakpoints[checked] > image {
/* This button has a special checked image, don't make it blue */
filter: none;
}
@media (min-resolution: 1.1dppx) {
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0,32px,32px,0);
}
#toggle-breakpoints {
list-style-image: url(images/debugger-toggleBreakpoints@2x.png);
}
#toggle-breakpoints[checked] {
-moz-image-region: rect(0,64px,32px,32px) !important;
}
}
#toggle-promise-debugger {
/* TODO Bug 1186119: Add a toggle promise debugger image */
}
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0px,16px,16px,0px);
}
#sources-toolbar .devtools-toolbarbutton:not([label])[checked] {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 1.1dppx) {
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0px,32px,32px,0px);
}
#sources-toolbar .devtools-toolbarbutton:not([label])[checked] {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
#sources .black-boxed {
color: rgba(128,128,128,0.4);
}
@ -219,21 +222,11 @@
#trace {
list-style-image: url(images/tracer-icon.png);
-moz-image-region: rect(0px,16px,16px,0px);
}
#trace[checked] {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 1.1dppx) {
#trace {
list-style-image: url(images/tracer-icon@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#trace[checked] {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
@ -549,15 +542,8 @@
/* Toolbar controls */
#debugger-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon,
#sources-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
#resume {
list-style-image: url(images/debugger-pause.png);
-moz-image-region: rect(0px,16px,16px,0px);
}
#resume[checked] {
@ -567,24 +553,13 @@
@media (min-resolution: 1.1dppx) {
#resume {
list-style-image: url(images/debugger-pause@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#resume[checked] {
list-style-image: url(images/debugger-play@2x.png);
-moz-image-region: rect(0px,64px,32px,32px);
}
}
#debugger-controls toolbarbutton {
transition: opacity 0.15s ease-in-out;
}
#debugger-controls toolbarbutton[disabled] {
opacity: .5;
transition: none;
}
#resume[break-on-next] {
background: var(--theme-highlight-lightorange);
}
@ -616,34 +591,21 @@
}
#instruments-pane-toggle {
background: none;
box-shadow: none;
border: none;
list-style-image: url(images/debugger-collapse.png);
-moz-image-region: rect(0px,16px,16px,0px);
}
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url(images/debugger-expand.png);
}
#instruments-pane-toggle:hover {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 1.1dppx) {
#instruments-pane-toggle {
list-style-image: url(images/debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url(images/debugger-expand@2x.png);
}
#instruments-pane-toggle:hover {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
/* Horizontal vs. vertical layout */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 B

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 323 B

View File

@ -3,13 +3,12 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg height="0" xmlns="http://www.w3.org/2000/svg">
<filter id="invert" x="0%" y="0%" width="100%" height="100%"
primitiveUnits="objectBoundingBox">
<feComponentTransfer>
<feFuncR type="table" tableValues=".1 0"/>
<feFuncG type="table" tableValues=".1 0"/>
<feFuncB type="table" tableValues=".1 0"/>
</feComponentTransfer>
<filter id="checked-icon-state">
<feColorMatrix in="SourceGraphic" type="matrix"
values="0 0 0 0 0.043
0 0 0 0 0.415
0 0 0 0 0.79
0 0 0 1 0"/>
</filter>
<!-- Web Audio Gradients -->

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,17 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="#3bace5" fill-rule="evenodd">
<path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
<path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
<path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
<path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
<g opacity=".3">
<path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
<path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
<path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
<path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1001 B

View File

@ -1,29 +1,20 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="16" height="16" viewBox="0 0 16 16" color="#babec3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style>
use[id^="pseudo-class"]:not(:target) {
display: none;
}
</style>
<rect id="class-block-maskBG" width="8" height="8" fill="#fff"/>
<rect id="class-block" width="8" height="8" rx="1" ry="1"/>
<mask id="mask-block-solid">
<use xlink:href="#class-block-maskBG"/>
<use xlink:href="#class-block" transform="translate(3 3)" fill="#000"/>
</mask>
<g id="pseudo-class-shape">
<rect x=".5" y=".5" width="7" height="7" rx="1" ry="1" mask="url(#mask-block-solid)" fill="none" stroke="currentColor" stroke-width="1"/>
<use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" fill-opacity=".4"/>
<use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" transform="translate(4 4)"/>
<g transform="translate(8 8)" fill="currentColor">
<path d="M2.5,0C2.2,0,2,0.2,2,0.5C2,0.8,2.2,1,2.5,1C2.8,1,3,0.8,3,0.5 C3,0.2,2.8,0,2.5,0z M4.5,0C4.2,0,4,0.2,4,0.5C4,0.8,4.2,1,4.5,1C4.8,1,5,0.8,5,0.5C5,0.2,4.8,0,4.5,0z M0.5,6C0.8,6,1,5.8,1,5.5 C1,5.2,0.8,5,0.5,5C0.2,5,0,5.2,0,5.5C0,5.8,0.2,6,0.5,6z M0.5,4C0.8,4,1,3.8,1,3.5C1,3.2,0.8,3,0.5,3C0.2,3,0,3.2,0,3.5 C0,3.8,0.2,4,0.5,4z M7.5,2C7.2,2,7,2.2,7,2.5C7,2.8,7.2,3,7.5,3C7.8,3,8,2.8,8,2.5C8,2.2,7.8,2,7.5,2z M7.5,4C7.2,4,7,4.2,7,4.5 C7,4.8,7.2,5,7.5,5C7.8,5,8,4.8,8,4.5C8,4.2,7.8,4,7.5,4z M5.5,7C5.2,7,5,7.2,5,7.5C5,7.8,5.2,8,5.5,8C5.8,8,6,7.8,6,7.5 C6,7.2,5.8,7,5.5,7z M3.5,7C3.2,7,3,7.2,3,7.5C3,7.8,3.2,8,3.5,8C3.8,8,4,7.8,4,7.5C4,7.2,3.8,7,3.5,7z M0.5,2C0.8,2,1,1.8,1,1.5v-1 C1,0.2,0.8,0,0.5,0C0.2,0,0,0.2,0,0.5v1C0,1.8,0.2,2,0.5,2z M8,0.5C8,0.2,7.8,0,7.5,0h-1C6.2,0,6,0.2,6,0.5C6,0.8,6.2,1,6.5,1h1 C7.8,1,8,0.8,8,0.5z M7.5,6C7.2,6,7,6.2,7,6.5v1C7,7.8,7.2,8,7.5,8C7.8,8,8,7.8,8,7.5v-1C8,6.2,7.8,6,7.5,6z M1.5,7h-1 C0.2,7,0,7.2,0,7.5C0,7.8,0.2,8,0.5,8h1C1.8,8,2,7.8,2,7.5C2,7.2,1.8,7,1.5,7z"/>
<use xlink:href="#class-block" fill-opacity=".2"/>
</g>
</g>
</defs>
<use xlink:href="#pseudo-class-shape" id="pseudo-class" color="#babec3"/>
<use xlink:href="#pseudo-class-shape" id="pseudo-class-checked" color="#3089C9"/>
<rect x=".5" y=".5" width="7" height="7" rx="1" ry="1" mask="url(#mask-block-solid)" fill="none" stroke="currentColor" stroke-width="1"/>
<use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" fill-opacity=".4"/>
<use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" transform="translate(4 4)"/>
<g transform="translate(8 8)" fill="currentColor">
<path d="M2.5,0C2.2,0,2,0.2,2,0.5C2,0.8,2.2,1,2.5,1C2.8,1,3,0.8,3,0.5 C3,0.2,2.8,0,2.5,0z M4.5,0C4.2,0,4,0.2,4,0.5C4,0.8,4.2,1,4.5,1C4.8,1,5,0.8,5,0.5C5,0.2,4.8,0,4.5,0z M0.5,6C0.8,6,1,5.8,1,5.5 C1,5.2,0.8,5,0.5,5C0.2,5,0,5.2,0,5.5C0,5.8,0.2,6,0.5,6z M0.5,4C0.8,4,1,3.8,1,3.5C1,3.2,0.8,3,0.5,3C0.2,3,0,3.2,0,3.5 C0,3.8,0.2,4,0.5,4z M7.5,2C7.2,2,7,2.2,7,2.5C7,2.8,7.2,3,7.5,3C7.8,3,8,2.8,8,2.5C8,2.2,7.8,2,7.5,2z M7.5,4C7.2,4,7,4.2,7,4.5 C7,4.8,7.2,5,7.5,5C7.8,5,8,4.8,8,4.5C8,4.2,7.8,4,7.5,4z M5.5,7C5.2,7,5,7.2,5,7.5C5,7.8,5.2,8,5.5,8C5.8,8,6,7.8,6,7.5 C6,7.2,5.8,7,5.5,7z M3.5,7C3.2,7,3,7.2,3,7.5C3,7.8,3.2,8,3.5,8C3.8,8,4,7.8,4,7.5C4,7.2,3.8,7,3.5,7z M0.5,2C0.8,2,1,1.8,1,1.5v-1 C1,0.2,0.8,0,0.5,0C0.2,0,0,0.2,0,0.5v1C0,1.8,0.2,2,0.5,2z M8,0.5C8,0.2,7.8,0,7.5,0h-1C6.2,0,6,0.2,6,0.5C6,0.8,6.2,1,6.5,1h1 C7.8,1,8,0.8,8,0.5z M7.5,6C7.2,6,7,6.2,7,6.5v1C7,7.8,7.2,8,7.5,8C7.8,8,8,7.8,8,7.5v-1C8,6.2,7.8,6,7.5,6z M1.5,7h-1 C0.2,7,0,7.2,0,7.5C0,7.8,0.2,8,0.5,8h1C1.8,8,2,7.8,2,7.5C2,7.2,1.8,7,1.5,7z"/>
<use xlink:href="#class-block" fill-opacity=".2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 330 B

View File

@ -1,26 +1,6 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
<style>
use:not(:target) {
display: none;
}
use {
fill: #babec3;
}
use[id$="-disabled"] {
fill-opacity: 0.5;
}
use[id$="-open"] {
fill: #3bace5;
}
</style>
<defs>
<path id="filter-shape" d="M 2,2 v 3 l 5,4 v 6 h 2 v -6 l 5,-4 v -3 L 14,2 z"/>
</defs>
<use id="filter" xlink:href="#filter-shape"/>
<use id="filter-disabled" xlink:href="#filter-shape"/>
<use id="filter-open" xlink:href="#filter-shape"/>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#babec3" d="M2,2v3l5,4v6h2v-6l5,-4v-3L14,2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 845 B

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 709 B

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 116 B

View File

@ -44,39 +44,21 @@
/* Expand/collapse panel toolbar button */
#inspector-pane-toggle {
background: none;
box-shadow: none;
border: none;
list-style-image: url(images/debugger-collapse.png);
-moz-image-region: rect(0px,16px,16px,0px);
}
#inspector-pane-toggle > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
#inspector-pane-toggle[pane-collapsed] {
list-style-image: url(images/debugger-expand.png);
}
#inspector-pane-toggle:active {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 1.1dppx) {
#inspector-pane-toggle {
list-style-image: url(images/debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#inspector-pane-toggle[pane-collapsed] {
list-style-image: url(images/debugger-expand@2x.png);
}
#inspector-pane-toggle:active {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
/* Tooltip: Events */

View File

@ -114,18 +114,6 @@ html, body, #app, #memory-tool {
margin: 2px;
}
/**
* TODO bug 1213100
* Once we figure out how to store invertable buttons (pseudo element like in
* this case?) we should add a .invertable class to handle this generally,
* rather than the definitions in toolbars.css.
*
* @see bug 1173397 for another inverted related bug
*/
.theme-light .devtools-toolbar > .devtools-toolbarbutton.take-snapshot::before {
filter: url(images/filters.svg#invert);
}
/**
* Container (sidebar + main panel)
*/

View File

@ -204,7 +204,7 @@ box.requests-menu-status:not([code]) {
box.requests-menu-status[code="cached"] {
border: 2px solid var(--theme-content-color2);
background-color: transparent;
background-color: transparent;
}
box.requests-menu-status[code^="1"] {
@ -399,39 +399,21 @@ box.requests-menu-status[code^="5"] {
/* Network request details */
#details-pane-toggle {
background: none;
box-shadow: none;
border-color: transparent;
list-style-image: url("chrome://devtools/skin/images/debugger-collapse.png");
-moz-image-region: rect(0px,16px,16px,0px);
}
#details-pane-toggle > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
#details-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://devtools/skin/images/debugger-expand.png");
}
#details-pane-toggle:active {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 1.1dppx) {
#details-pane-toggle {
list-style-image: url("chrome://devtools/skin/images/debugger-collapse@2x.png");
-moz-image-region: rect(0px,32px,32px,0px);
}
#details-pane-toggle[pane-collapsed] {
list-style-image: url("chrome://devtools/skin/images/debugger-expand@2x.png");
}
#details-pane-toggle:active {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
/* Network request details tabpanels */

View File

@ -42,16 +42,7 @@
}
#filter-button {
list-style-image: url(images/timeline-filter.svg#filter);
min-width: 24px;
}
#filter-button[disabled] {
list-style-image: url(images/timeline-filter.svg#filter-disabled);
}
#filter-button[open] {
list-style-image: url(images/timeline-filter.svg#filter-open);
list-style-image: url(images/timeline-filter.svg);
}
#performance-filter-menupopup > menuitem:before {
@ -89,10 +80,6 @@
list-style-image: url(images/profiler-stopwatch.svg);
}
#main-record-button[checked] {
list-style-image: url(images/profiler-stopwatch-checked.svg);
}
#main-record-button .button-icon {
margin: 0;
}

View File

@ -284,12 +284,12 @@
}
.ruleview-selectorhighlighter:hover {
background-position: -32px 0;
filter: url(images/filters.svg#checked-icon-state);
}
.ruleview-selectorhighlighter:active,
.ruleview-selectorhighlighter.highlighted {
background-position: -16px 0;
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
}
#ruleview-add-rule-button::before {
@ -298,34 +298,13 @@
}
#pseudo-class-panel-toggle::before {
background-image: url("chrome://devtools/skin/images/pseudo-class.svg#pseudo-class");
background-image: url("chrome://devtools/skin/images/pseudo-class.svg");
background-size: cover;
}
#pseudo-class-panel-toggle[checked]::before {
background-image: url("chrome://devtools/skin/images/pseudo-class.svg#pseudo-class-checked");
filter: none !important;
}
/**
* These buttons are using opacity instead of background color to indicate
* the state
*/
#ruleview-add-rule-button,
#pseudo-class-panel-toggle,
.ruleview-overridden-rule-filter {
opacity: 0.8;
}
#ruleview-add-rule-button:not([disabled]):hover,
#pseudo-class-panel-toggle:hover,
#pseudo-class-panel-toggle[checked],
.ruleview-overridden-rule-filter:hover {
opacity: 1;
}
#ruleview-add-rule-button,
#pseudo-class-panel-toggle,
#pseudo-class-panel-toggle:hover,
#pseudo-class-panel-toggle[checked]::before {
background-color: transparent !important;
}

View File

@ -72,7 +72,7 @@
/* Invert all toggle icons but the one in the active row for light theme */
.theme-light .side-menu-widget-item:not(.selected) .checkbox-check {
filter: url(images/filters.svg#invert);
filter: invert(1);
}
/* Shader source editors */

View File

@ -120,7 +120,7 @@
/* Invert all toggle icons but the one in the active row for light theme */
.theme-light .splitview-nav > li:not(.splitview-active) .stylesheet-enabled {
filter: url(images/filters.svg#invert);
filter: invert(1);
}
.splitview-nav > li > .stylesheet-enabled:focus,

View File

@ -54,22 +54,26 @@
}
/* Toolbar buttons */
.devtools-menulist,
.devtools-toolbarbutton {
.devtools-toolbarbutton,
.devtools-button {
-moz-appearance: none;
-moz-box-align: center;
background: transparent;
min-width: 78px;
min-height: 18px;
padding: 1px;
text-shadow: none;
border: none;
border-radius: 0;
margin: 2px 3px;
color: inherit;
color: var(--theme-body-color);
transition: background 0.05s ease-in-out;
color: var(--theme-content-color1);
background-color: var(--theme-toolbar-background);
}
.devtools-menulist,
.devtools-toolbarbutton {
-moz-box-align: center;
min-width: 78px;
padding: 1px;
margin: 2px 3px;
}
.devtools-menulist:-moz-focusring,
@ -78,15 +82,66 @@
outline-offset: -4px;
}
.devtools-toolbarbutton[standalone], .devtools-toolbarbutton[data-standalone] {
-moz-margin-end: 5px;
.devtools-toolbarbutton:not([label]) > .toolbarbutton-icon,
.devtools-button::before {
width: 16px;
height: 16px;
transition: opacity 0.05s ease-in-out;
}
/* HTML buttons */
.devtools-button {
margin: 0;
padding: 0;
min-width: 32px;
/* The icon is absolutely positioned in the button using ::before */
position: relative;
}
.devtools-button::before {
content: "";
display: block;
position: absolute;
left: 50%;
top: 50%;
margin: -8px 0 0 -8px;
background-size: cover;
background-repeat: no-repeat;
transition: opacity 0.05s ease-in-out;
}
/* Standalone buttons */
.devtools-button[standalone],
.devtools-button[data-standalone],
.devtools-toolbarbutton[standalone],
.devtools-toolbarbutton[data-standalone] {
border-width: 1px;
border-style: solid;
min-height: 32px;
background-color: var(--theme-toolbar-background);
}
.devtools-toolbarbutton[standalone], .devtools-toolbarbutton[data-standalone] {
-moz-margin-end: 5px;
}
.devtools-toolbarbutton[label][standalone] {
min-height: 2em;
}
.theme-dark .devtools-menulist,
.theme-dark .devtools-toolbarbutton,
.theme-dark .devtools-button {
border-color: rgba(0, 0, 0, .4); /* Splitters */
}
.theme-light .devtools-menulist,
.theme-light .devtools-toolbarbutton,
.theme-light .devtools-button {
border-color: rgba(170, 170, 170, .5); /* Splitters */
}
/* Icon button styles */
.devtools-toolbarbutton:not([label]),
.devtools-toolbarbutton[text-as-image] {
min-width: 32px;
@ -98,11 +153,6 @@
min-width: inherit;
}
/* Command buttons with menupopups should be styled slightly differently -
no background color and a bit more narrow */
#toolbox-buttons .devtools-toolbarbutton:not([text-as-image]):not(:hover):not([open=true]) {
background: transparent;
}
#toolbox-buttons .devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker {
padding: 0 2px;
}
@ -111,14 +161,11 @@
display: none;
}
.devtools-toolbar .devtools-toolbarbutton {
border-width: 0;
}
.devtools-toolbarbutton > .toolbarbutton-icon {
margin: 0;
}
/* Menu button styles (eg. web console filters) */
.devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-button {
-moz-appearance: none;
color: inherit;
@ -152,13 +199,32 @@
padding: 0 3px;
}
.theme-dark .devtools-menulist,
.theme-dark .devtools-toolbarbutton {
border-color: rgba(0, 0, 0, .4); /* Splitters */
/* Icon-only buttons */
.devtools-button:empty::before,
.devtools-toolbarbutton:not([label]):not([disabled]) > image {
opacity: 0.8;
}
.theme-light .devtools-menulist,
.theme-light .devtools-toolbarbutton {
border-color: rgba(170, 170, 170, .5); /* Splitters */
.devtools-button:hover:empty::before,
.devtools-button[checked]:empty::before,
.devtools-button[open]:empty::before,
.devtools-toolbarbutton:not([label]):hover > image,
.devtools-toolbarbutton:not([label])[checked=true] > image,
.devtools-toolbarbutton:not([label])[open=true] > image {
opacity: 1;
}
.devtools-button:disabled,
.devtools-button[disabled],
.devtools-toolbarbutton[disabled] {
opacity: 0.5 !important;
}
.devtools-button[checked]:empty::before,
.devtools-button[open]:empty::before,
.devtools-toolbarbutton:not([label])[checked=true] > image,
.devtools-toolbarbutton:not([label])[open=true] > image {
filter: url(images/filters.svg#checked-icon-state);
}
/* Text-only buttons */
@ -173,68 +239,45 @@
background-color: rgba(0, 0, 0, .2); /* Splitter */
}
/* Button States */
.theme-dark .devtools-toolbarbutton:not([disabled]):hover,
/* Text-only button states */
.theme-dark .devtools-button:not(:empty):not([disabled]):hover,
.theme-dark #toolbox-buttons .devtools-toolbarbutton:not([disabled])[text-as-image]:hover,
.theme-dark .devtools-toolbarbutton:not([disabled])[label]:not([text-as-image]):not([type=menu-button]):hover {
.theme-dark .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled],[text-as-image]))[label]:hover {
background: rgba(0, 0, 0, .3); /* Splitters */
}
.theme-light .devtools-toolbarbutton:not([disabled]):hover,
.theme-light .devtools-button:not(:empty):not([disabled]):hover,
.theme-light #toolbox-buttons .devtools-toolbarbutton:not([disabled])[text-as-image]:hover,
.theme-light .devtools-toolbarbutton:not([disabled])[label]:not([text-as-image]):not([type=menu-button]):hover {
.theme-light .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled],[text-as-image]))[label]:hover {
background: rgba(170, 170, 170, .3); /* Splitters */
}
.theme-dark .devtools-toolbarbutton:not([disabled]):hover:active,
.theme-dark .devtools-button:not(:empty):not([disabled]):hover:active,
.theme-dark #toolbox-buttons .devtools-toolbarbutton:not([disabled])[text-as-image]:hover:active,
.theme-dark .devtools-toolbarbutton:not([disabled])[label]:not([text-as-image]):not([type=menu-button]):hover:active {
.theme-dark .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled],[text-as-image]))[label]:hover:active {
background: rgba(0, 0, 0, .4); /* Splitters */
}
.theme-light .devtools-toolbarbutton:not([disabled]):hover:active,
.theme-light .devtools-button:not(:empty):not([disabled]):hover:active,
.theme-light #toolbox-buttons .devtools-toolbarbutton:not([disabled])[text-as-image]:hover:active,
.theme-light .devtools-toolbarbutton:not([disabled])[label]:not([text-as-image]):not([type=menu-button]):hover:active {
.theme-light .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled],[text-as-image]))[label]:hover:active {
background: rgba(170, 170, 170, .4); /* Splitters */
}
/* Menu type buttons and checked states */
.theme-dark .devtools-toolbarbutton[checked=true],
.theme-dark #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked] {
.theme-dark .devtools-toolbarbutton:not([disabled])[label][checked=true],
.theme-dark .devtools-toolbarbutton:not([disabled])[label][open],
.theme-dark .devtools-button:not(:empty)[checked=true],
.theme-dark #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked=true] {
background: rgba(29, 79, 115, .7); /* Select highlight blue */
color: var(--theme-selection-color);
}
.theme-light .devtools-toolbarbutton[checked=true],
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked] {
background: rgba(76, 158, 217, .2); /* Select highlight blue */
}
.theme-dark .devtools-menulist[open=true],
.theme-dark .devtools-toolbarbutton[open=true],
.theme-dark .devtools-toolbarbutton[open=true]:hover,
.theme-dark .devtools-toolbarbutton[open=true]:hover:active,
.theme-dark .devtools-toolbarbutton[checked=true]:hover {
background: rgba(29, 79, 115, .8); /* Select highlight blue */
color: var(--theme-selection-color);
}
.theme-light .devtools-menulist[open=true],
.theme-light .devtools-toolbarbutton[open=true],
.theme-light .devtools-toolbarbutton[open=true]:hover,
.theme-light .devtools-toolbarbutton[open=true]:hover:active,
.theme-light .devtools-toolbarbutton[checked=true]:hover {
background: rgba(76, 158, 217, .4); /* Select highlight blue */
.theme-light .devtools-toolbarbutton:not([disabled])[label][checked=true],
.theme-light .devtools-toolbarbutton:not([disabled])[label][open],
.theme-light .devtools-button:not(:empty)[checked=true],
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image][checked=true] {
background: rgba(76, 158, 217, .3); /* Select highlight blue */
}
.devtools-option-toolbarbutton {
-moz-appearance: none;
list-style-image: url("chrome://devtools/skin/images/tool-options.svg");
background: none;
opacity: .8;
border: none;
}
.devtools-option-toolbarbutton[open=true] {
opacity: 1;
}
/* Toolbar button groups */
@ -257,73 +300,6 @@
-moz-margin-start: 1px;
}
/* HTML buttons, similar to toolbar buttons, but work in HTML documents */
.devtools-button {
border: 0 solid var(--theme-splitter-color);
background: var(--theme-toolbar-background);
color: var(--theme-body-color);
margin: 0;
padding: 0;
min-width: 32px;
min-height: 18px;
/* The icon is absolutely positioned in the button using ::before */
position: relative;
}
.devtools-button[standalone], .devtools-button[data-standalone] {
min-height: 32px;
border-width: 1px;
}
/* Button States */
.theme-dark .devtools-button:not([disabled]):hover {
background: rgba(0, 0, 0, .3); /* Splitters */
}
.theme-light .devtools-button:not([disabled]):hover {
background: rgba(170, 170, 170, .3); /* Splitters */
}
.theme-dark .devtools-button:not([disabled]):hover:active {
background: rgba(0, 0, 0, .4); /* Splitters */
}
.theme-light .devtools-button:not([disabled]):hover:active {
background: rgba(170, 170, 170, .4); /* Splitters */
}
/* Menu type buttons and checked states */
.theme-dark .devtools-button[checked] {
background: rgba(29, 79, 115, .7) !important; /* Select highlight blue */
color: var(--theme-selection-color);
}
.theme-light .devtools-button[checked] {
background: rgba(76, 158, 217, .2) !important; /* Select highlight blue */
}
.devtools-button::before {
content: "";
display: block;
width: 16px;
height: 16px;
position: absolute;
left: 50%;
top: 50%;
margin: -8px 0 0 -8px;
background-repeat: no-repeat;
}
.devtools-button[disabled]::before,
.devtools-button:disabled::before {
opacity: 0.5;
}
@media (min-resolution: 1.1dppx) {
.devtools-button::before {
background-size: 32px;
}
}
/* Text input */
.devtools-textinput,
@ -1000,27 +976,23 @@
.theme-light .command-button-invertable:active > image,
.theme-light .devtools-closebutton > image,
.theme-light .devtools-toolbarbutton > image,
.theme-light .devtools-option-toolbarbutton > image,
.theme-light .devtools-button::before,
.theme-light #breadcrumb-separator-normal,
.theme-light .scrollbutton-up > .toolbarbutton-icon,
.theme-light .scrollbutton-down > .toolbarbutton-icon,
.theme-light #black-boxed-message-button .button-icon,
.theme-light .notice-container button .button-icon,
.theme-light #requests-menu-perf-notice-button .button-icon,
.theme-light #requests-menu-network-summary-button .button-icon,
.theme-light .event-tooltip-debugger-icon,
.theme-light .devtools-button::before {
filter: url(images/filters.svg#invert);
.theme-light #toggle-breakpoints[checked] > image,
.theme-light .event-tooltip-debugger-icon {
filter: invert(1);
}
/* Since selected backgrounds are blue, we want to use the normal
* (light) icons. */
.theme-light .command-button-invertable[checked=true]:not(:active) > image,
.theme-light .devtools-tab[icon-invertable][selected] > image,
.theme-light .devtools-tab[icon-invertable][highlighted] > image,
.theme-light #record-snapshot[checked] > image,
.theme-light #profiler-start[checked] > image,
.theme-light .notice-container button[checked] .button-icon {
.theme-light .devtools-tab[icon-invertable][highlighted] > image {
filter: none !important;
}

View File

@ -208,21 +208,6 @@ text {
list-style-image: url(images/power.svg);
}
#audio-node-toolbar toolbarbutton[disabled] {
opacity: 0.5;
background-color: transparent;
}
#audio-node-toolbar toolbarbutton[checked] {
background-color: var(--theme-selection-background);
}
/* don't invert checked buttons so we can have white icons on light theme */
#audio-node-toolbar toolbarbutton[checked] > .toolbarbutton-icon {
filter: none;
}
/**
* Responsive Styles
* `.devtools-responsive-container` takes care of most of

View File

@ -527,11 +527,12 @@ a {
.elementNode:hover .open-inspector,
.open-inspector:hover {
background-position: -32px 0;
filter: url(images/filters.svg#checked-icon-state);
}
.elementNode:hover .open-inspector:active,
.open-inspector:active {
background-position: -16px 0;
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
}
@media (max-width: 500px) {

View File

@ -739,12 +739,35 @@
}
/* Variables and properties editing */
.variables-view-delete {
background: url("chrome://devtools/skin/images/vview-delete.png");
background-size: cover;
.variables-view-delete,
.variables-view-edit,
.variables-view-open-inspector {
width: 16px;
height: 16px;
background-size: cover;
cursor: pointer;
}
.variables-view-delete:hover,
.variables-view-edit:hover,
.variables-view-open-inspector:hover {
filter: url(images/filters.svg#checked-icon-state);
}
.variables-view-delete:active,
.variables-view-edit:active,
.variables-view-open-inspector:active {
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
}
.variable-or-property:focus > .title > .variables-view-delete,
.variable-or-property:focus > .title > .variables-view-edit,
.variable-or-property:focus > .title > .variables-view-open-inspector {
filter: none;
}
.variables-view-delete {
background-image: url("chrome://devtools/skin/images/vview-delete.png");
}
@media (min-resolution: 1.1dppx) {
@ -753,24 +776,8 @@
}
}
.variables-view-delete:hover {
background-position: 16px;
}
.variables-view-delete:active {
background-position: 32px;
}
.variable-or-property:focus > .title > .variables-view-delete {
background-position: 0px;
}
.variables-view-edit {
background: url("chrome://devtools/skin/images/vview-edit.png");
background-size: cover;
width: 16px;
height: 16px;
cursor: pointer;
background-image: url("chrome://devtools/skin/images/vview-edit.png");
}
@media (min-resolution: 1.1dppx) {
@ -779,24 +786,8 @@
}
}
.variables-view-edit:hover {
background-position: 16px;
}
.variables-view-edit:active {
background-position: 32px;
}
.variable-or-property:focus > .title > .variables-view-edit {
background-position: 0px;
}
.variables-view-open-inspector {
background: url("chrome://devtools/skin/images/vview-open-inspector.png");
background-size: cover;
width: 16px;
height: 16px;
cursor: pointer;
background-image: url("chrome://devtools/skin/images/vview-open-inspector.png");
}
@media (min-resolution: 1.1dppx) {
@ -805,17 +796,6 @@
}
}
.variables-view-open-inspector:hover {
background-position: 16px;
}
.variables-view-open-inspector:active {
background-position: 32px;
}
.variable-or-property:focus > .title > .variables-view-open-inspector {
background-position: 0px;
}
/* Variables and properties input boxes */

View File

@ -80,8 +80,9 @@ namespace dom {
class ImageLoadTask : public nsRunnable
{
public:
explicit ImageLoadTask(HTMLImageElement *aElement) :
mElement(aElement)
ImageLoadTask(HTMLImageElement *aElement, bool aAlwaysLoad)
: mElement(aElement)
, mAlwaysLoad(aAlwaysLoad)
{
mDocument = aElement->OwnerDoc();
mDocument->BlockOnload();
@ -91,7 +92,7 @@ public:
{
if (mElement->mPendingImageLoadTask == this) {
mElement->mPendingImageLoadTask = nullptr;
mElement->LoadSelectedImage(true, true);
mElement->LoadSelectedImage(true, true, mAlwaysLoad);
}
mDocument->UnblockOnload(false);
return NS_OK;
@ -101,11 +102,13 @@ private:
~ImageLoadTask() {}
RefPtr<HTMLImageElement> mElement;
nsCOMPtr<nsIDocument> mDocument;
bool mAlwaysLoad;
};
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mForm(nullptr)
, mInDocResponsiveContent(false)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
@ -427,7 +430,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
mResponsiveSelector->Content() == this) {
mResponsiveSelector->SetDefaultSource(NullString());
}
QueueImageLoadTask();
QueueImageLoadTask(true);
} else {
// Bug 1076583 - We still behave synchronously in the non-responsive case
CancelImageRequests(aNotify);
@ -447,7 +450,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
if (InResponsiveMode()) {
// per spec, full selection runs when this changes, even though
// it doesn't directly affect the source selection
QueueImageLoadTask();
QueueImageLoadTask(true);
} else {
// Bug 1076583 - We still use the older synchronous algorithm in
// non-responsive mode. Force a new load of the image with the
@ -543,7 +546,7 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
mResponsiveSelector->Content() == this) {
mResponsiveSelector->SetDefaultSource(aValue);
}
QueueImageLoadTask();
QueueImageLoadTask(true);
} else if (aNotify) {
// If aNotify is false, we are coming from the parser or some such place;
// we'll get bound after all the attributes have been set, so we'll do the
@ -586,13 +589,15 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
UpdateFormOwner();
}
bool addedToPicture = aParent && aParent->IsHTMLElement(nsGkAtoms::picture) &&
HTMLPictureElement::IsPictureEnabled();
if (addedToPicture) {
if (aDocument) {
if (HaveSrcsetOrInPicture()) {
if (aDocument && !mInDocResponsiveContent) {
aDocument->AddResponsiveContent(this);
mInDocResponsiveContent = true;
}
QueueImageLoadTask();
bool forceLoadEvent = HTMLPictureElement::IsPictureEnabled() &&
aParent && aParent->IsHTMLElement(nsGkAtoms::picture);
QueueImageLoadTask(forceLoadEvent);
} else if (!InResponsiveMode() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
// We skip loading when our attributes were set from parser land,
@ -633,17 +638,22 @@ HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
if (mInDocResponsiveContent) {
nsIDocument* doc = GetOurOwnerDoc();
MOZ_ASSERT(doc);
if (doc) {
doc->RemoveResponsiveContent(this);
mInDocResponsiveContent = false;
}
}
if (GetParent() &&
GetParent()->IsHTMLElement(nsGkAtoms::picture) &&
HTMLPictureElement::IsPictureEnabled()) {
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
doc->RemoveResponsiveContent(this);
}
// Being removed from picture re-triggers selection, even if we
// weren't using a <source> peer
if (aNullParent) {
QueueImageLoadTask();
QueueImageLoadTask(true);
}
}
@ -687,7 +697,7 @@ HTMLImageElement::MaybeLoadImage()
// Note, check LoadingEnabled() after LoadImage call.
LoadSelectedImage(false, true);
LoadSelectedImage(false, true, false);
if (!LoadingEnabled()) {
CancelImageRequests(true);
@ -887,7 +897,7 @@ HTMLImageElement::ClearForm(bool aRemoveFromForm)
}
void
HTMLImageElement::QueueImageLoadTask()
HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
{
// If loading is temporarily disabled, we don't want to queue tasks
// that may then run when loading is re-enabled.
@ -895,7 +905,7 @@ HTMLImageElement::QueueImageLoadTask()
return;
}
nsCOMPtr<nsIRunnable> task = new ImageLoadTask(this);
nsCOMPtr<nsIRunnable> task = new ImageLoadTask(this, aAlwaysLoad);
// The task checks this to determine if it was the last
// queued event, and so earlier tasks are implicitly canceled.
mPendingImageLoadTask = task;
@ -929,7 +939,7 @@ HTMLImageElement::InResponsiveMode()
}
nsresult
HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify)
HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
{
nsresult rv = NS_ERROR_FAILURE;
@ -937,7 +947,9 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify)
// In responsive mode we generally want to re-run the full
// selection algorithm whenever starting a new load, per
// spec. This also causes us to re-resolve the URI as appropriate.
UpdateResponsiveSource();
if (!UpdateResponsiveSource() && !aAlwaysLoad) {
return NS_OK;
}
}
if (mResponsiveSelector) {
@ -990,9 +1002,17 @@ HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode,
mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue);
}
if (!mInDocResponsiveContent) {
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
doc->AddResponsiveContent(this);
mInDocResponsiveContent = true;
}
}
// This always triggers the image update steps per the spec, even if
// we are not using this source.
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@ -1019,7 +1039,7 @@ HTMLImageElement::PictureSourceSizesChanged(nsIContent *aSourceNode,
// This always triggers the image update steps per the spec, even if
// we are not using this source.
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@ -1035,7 +1055,7 @@ HTMLImageElement::PictureSourceMediaOrTypeChanged(nsIContent *aSourceNode,
// This always triggers the image update steps per the spec, even if
// we are not switching to/from this source
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@ -1045,7 +1065,7 @@ HTMLImageElement::PictureSourceAdded(nsIContent *aSourceNode)
return;
}
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@ -1055,15 +1075,17 @@ HTMLImageElement::PictureSourceRemoved(nsIContent *aSourceNode)
return;
}
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
bool
HTMLImageElement::UpdateResponsiveSource()
{
bool hadSelector = !!mResponsiveSelector;
if (!IsSrcsetEnabled()) {
mResponsiveSelector = nullptr;
return;
return hadSelector;
}
nsIContent *currentSource =
@ -1083,7 +1105,7 @@ HTMLImageElement::UpdateResponsiveSource()
if (candidateSource == currentSource) {
// found no better source before current, re-run selection on
// that and keep it if it's still usable.
mResponsiveSelector->SelectImage(true);
bool changed = mResponsiveSelector->SelectImage(true);
if (mResponsiveSelector->NumCandidates()) {
bool isUsableCandidate = true;
@ -1095,7 +1117,7 @@ HTMLImageElement::UpdateResponsiveSource()
}
if (isUsableCandidate) {
break;
return changed;
}
}
@ -1124,6 +1146,8 @@ HTMLImageElement::UpdateResponsiveSource()
// Ran out of siblings without finding ourself, e.g. XBL magic.
mResponsiveSelector = nullptr;
}
return !hadSelector || mResponsiveSelector;
}
/*static */ bool
@ -1296,7 +1320,7 @@ HTMLImageElement::DestroyContent()
void
HTMLImageElement::MediaFeatureValuesChanged()
{
QueueImageLoadTask();
QueueImageLoadTask(false);
}
void

View File

@ -280,7 +280,7 @@ protected:
// algorithm (InResponsiveMode()) -- synchronous actions when just
// using img.src will bypass this, and update source and kick off
// image load synchronously.
void QueueImageLoadTask();
void QueueImageLoadTask(bool aAlwaysLoad);
// True if we have a srcset attribute or a <picture> parent, regardless of if
// any valid responsive sources were parsed from either.
@ -292,7 +292,7 @@ protected:
// Resolve and load the current mResponsiveSelector (responsive mode) or src
// attr image.
nsresult LoadSelectedImage(bool aForce, bool aNotify);
nsresult LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad);
// True if this string represents a type we would support on <source type>
static bool SupportedPictureSourceType(const nsAString& aType);
@ -321,7 +321,9 @@ protected:
// the existing mResponsiveSelector, meaning you need to update its
// parameters as appropriate before calling (or null it out to force
// recreation)
void UpdateResponsiveSource();
//
// Returns true if the source has changed, and false otherwise.
bool UpdateResponsiveSource();
// Given a <source> node that is a previous sibling *or* ourselves, try to
// create a ResponsiveSelector.
@ -359,6 +361,7 @@ private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
bool mInDocResponsiveContent;
nsCOMPtr<nsIRunnable> mPendingImageLoadTask;
};

View File

@ -3243,6 +3243,12 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
// cut & copy are allowed in non editable documents
if (isCutCopy) {
if (!nsContentUtils::IsCutCopyAllowed()) {
// We have rejected the event due to it not being performed in an
// input-driven context therefore, we report the error to the console.
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM"), this,
nsContentUtils::eDOM_PROPERTIES,
"ExecCommandCutCopyDeniedNotInputDriven");
return false;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

View File

@ -197,6 +197,9 @@ support-files =
file_ignoreuserfocus.html
simpleFileOpener.js
file_mozaudiochannel.html
file_bug1166138_1x.png
file_bug1166138_2x.png
file_bug1166138_def.png
[test_a_text.html]
[test_anchor_href_cache_invalidation.html]
@ -595,3 +598,4 @@ skip-if = buildapp == 'b2g' # bug 1129014
[test_viewport_resize.html]
[test_extapp.html]
[test_image_clone_load.html]
[test_bug1166138.html]

View File

@ -0,0 +1,130 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1166138
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1166138</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1166138">Mozilla Bug 1166138</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<img srcset="file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x"
src="file_bug1166138_def.png"
onload="onLoad()">
<script type="application/javascript">
var img1x = "http://mochi.test:8888/tests/dom/html/test/file_bug1166138_1x.png";
var img2x = "http://mochi.test:8888/tests/dom/html/test/file_bug1166138_2x.png";
var imgdef = "http://mochi.test:8888/tests/dom/html/test/file_bug1166138_def.png";
var onLoadCallback = null;
var done = false;
var startPromise = new Promise((a) => {
onLoadCallback = () => {
var image = document.querySelector('img');
// If we aren't starting at 2x scale, resize to 2x scale, and wait for a load
if (image.currentSrc != img2x) {
onLoadCallback = a;
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]});
} else {
a();
}
};
});
// if aLoad is true, waits for a load event. Otherwise, spins the event loop twice to
// ensure that no events were queued to be fired.
function spin(aLoad) {
if (aLoad) {
return new Promise((a) => {
ok(!onLoadCallback, "Shouldn't be an existing callback");
onLoadCallback = a;
});
} else {
return new Promise((a) => SimpleTest.executeSoon(() => SimpleTest.executeSoon(a)));
}
}
function onLoad() {
if (done) return;
ok(onLoadCallback, "Expected a load event");
if (onLoadCallback) {
var cb = onLoadCallback;
onLoadCallback = null;
cb();
}
}
add_task(function* () {
yield startPromise;
var image = document.querySelector('img');
is(image.currentSrc, img2x, "initial scale must be 2x");
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]});
yield spin(true);
is(image.currentSrc, img1x, "pre-existing img tag to 1x");
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]});
yield spin(true);
is(image.currentSrc, img2x, "pre-existing img tag to 2x");
// Try removing & re-adding the image
document.body.removeChild(image);
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]});
yield spin(false); // No load should occur because the element is unbound
document.body.appendChild(image);
yield spin(true);
is(image.currentSrc, img1x, "remove and re-add tag after changing to 1x");
document.body.removeChild(image);
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]});
yield spin(false); // No load should occur because the element is unbound
document.body.appendChild(image);
yield spin(true);
is(image.currentSrc, img2x, "remove and re-add tag after changing to 2x");
// get rid of the srcset attribute! It should become the default
image.removeAttribute('srcset');
yield spin(true);
is(image.currentSrc, imgdef, "remove srcset attribute");
// Setting srcset again should return it to the correct value
image.setAttribute('srcset', "file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x");
yield spin(true);
is(image.currentSrc, img2x, "restore srcset attribute");
// Create a new image
var newImage = document.createElement('img');
// Switch load listening over to newImage
newImage.addEventListener('load', onLoad);
image.removeEventListener('load', onLoad);
document.body.appendChild(newImage);
yield spin(false); // no load event should fire - as the image has no attributes
is(newImage.currentSrc, "", "New element with no attributes");
newImage.setAttribute('srcset', "file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x");
yield spin(true);
is(newImage.currentSrc, img2x, "Adding srcset attribute");
SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]});
yield spin(true);
is(newImage.currentSrc, img1x, "new image after switching to 1x");
is(image.currentSrc, img1x, "old image after switching to 1x");
// Clear the listener
done = true;
});
</script>
</body>
</html>

View File

@ -188,3 +188,4 @@ InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the lo
InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", "FetchEvent.respondWith()", or "Response". %1$S is a URL. %2$S is an error string.
InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'.
ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.

View File

@ -111,7 +111,7 @@ public:
// Called by the reader's MediaResource as data arrives over the network.
// Must be called on the main thread.
virtual void NotifyDataArrived(bool aThrottleUpdates) = 0;
virtual void NotifyDataArrived() = 0;
// Set by Reader if the current audio track can be offloaded
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {}

View File

@ -1341,11 +1341,11 @@ void MediaDecoder::AddSizeOfResources(ResourceSizes* aSizes) {
}
void
MediaDecoder::NotifyDataArrived(bool aThrottleUpdates) {
MediaDecoder::NotifyDataArrived() {
MOZ_ASSERT(NS_IsMainThread());
if (mDecoderStateMachine) {
mDecoderStateMachine->DispatchNotifyDataArrived(aThrottleUpdates);
mDecoderStateMachine->DispatchNotifyDataArrived();
}
// ReadyState computation depends on MediaDecoder::CanPlayThrough, which

View File

@ -433,7 +433,7 @@ public:
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
virtual void NotifyDataArrived(bool aThrottleUpdates) override;
virtual void NotifyDataArrived() override;
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.

View File

@ -68,11 +68,8 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
, mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
/* aSupportsTailDispatch = */ true))
, mWatchManager(this, mTaskQueue)
, mTimer(new MediaTimer())
, mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
, mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)")
, mThrottleDuration(TimeDuration::FromMilliseconds(500))
, mLastThrottledNotify(TimeStamp::Now() - mThrottleDuration)
, mIgnoreAudioOutputFormat(false)
, mHitAudioDecodeError(false)
, mShutdown(false)
@ -182,43 +179,6 @@ MediaDecoderReader::UpdateBuffered()
mBuffered = GetBuffered();
}
void
MediaDecoderReader::ThrottledNotifyDataArrived()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE_VOID(!mShutdown);
// If it's been long enough since our last update, do it.
if (TimeStamp::Now() - mLastThrottledNotify > mThrottleDuration) {
DoThrottledNotify();
} else if (!mThrottledNotify.Exists()) {
// Otherwise, schedule an update if one isn't scheduled already.
RefPtr<MediaDecoderReader> self = this;
mThrottledNotify.Begin(
mTimer->WaitUntil(mLastThrottledNotify + mThrottleDuration, __func__)
->Then(OwnerThread(), __func__,
[self] () -> void {
self->mThrottledNotify.Complete();
NS_ENSURE_TRUE_VOID(!self->mShutdown);
self->DoThrottledNotify();
},
[self] () -> void {
self->mThrottledNotify.Complete();
NS_WARNING("throttle callback rejected");
})
);
}
}
void
MediaDecoderReader::DoThrottledNotify()
{
MOZ_ASSERT(OnTaskQueue());
mLastThrottledNotify = TimeStamp::Now();
mThrottledNotify.DisconnectIfExists();
NotifyDataArrived();
}
media::TimeIntervals
MediaDecoderReader::GetBuffered()
{
@ -400,8 +360,6 @@ MediaDecoderReader::Shutdown()
mBaseAudioPromise.RejectIfExists(END_OF_STREAM, __func__);
mBaseVideoPromise.RejectIfExists(END_OF_STREAM, __func__);
mThrottledNotify.DisconnectIfExists();
ReleaseMediaResources();
mDuration.DisconnectIfConnected();
mBuffered.DisconnectAll();
@ -411,7 +369,6 @@ MediaDecoderReader::Shutdown()
RefPtr<ShutdownPromise> p;
mTimer = nullptr;
mDecoder = nullptr;
return mTaskQueue->BeginShutdown();

View File

@ -223,18 +223,10 @@ public:
virtual size_t SizeOfVideoQueueInFrames();
virtual size_t SizeOfAudioQueueInFrames();
// In situations where these notifications come from stochastic network
// activity, we can save significant recomputation by throttling the delivery
// of these updates to the reader implementation. We don't want to do this
// throttling when the update comes from MSE code, since that code needs the
// updates to be observable immediately, and is generally less
// trigger-happy with notifications anyway.
void DispatchNotifyDataArrived(bool aThrottleUpdates)
void DispatchNotifyDataArrived()
{
RefPtr<nsRunnable> r = NS_NewRunnableMethod(
this,
aThrottleUpdates ? &MediaDecoderReader::ThrottledNotifyDataArrived :
&MediaDecoderReader::NotifyDataArrived);
this, &MediaDecoderReader::NotifyDataArrived);
OwnerThread()->Dispatch(
r.forget(), AbstractThread::DontAssertDispatchSuccess);
@ -350,9 +342,6 @@ protected:
// State-watching manager.
WatchManager<MediaDecoderReader> mWatchManager;
// MediaTimer.
RefPtr<MediaTimer> mTimer;
// Buffered range.
Canonical<media::TimeIntervals> mBuffered;
@ -362,11 +351,6 @@ protected:
// Duration, mirrored from the state machine task queue.
Mirror<media::NullableTimeUnit> mDuration;
// State for ThrottledNotifyDataArrived.
MozPromiseRequestHolder<MediaTimerPromise> mThrottledNotify;
const TimeDuration mThrottleDuration;
TimeStamp mLastThrottledNotify;
// Whether we should accept media that we know we can't play
// directly, because they have a number of channel higher than
// what we support.
@ -415,11 +399,6 @@ private:
virtual void NotifyDataArrivedInternal() {}
// Invokes NotifyDataArrived while throttling the calls to occur
// at most every mThrottleDuration ms.
void ThrottledNotifyDataArrived();
void DoThrottledNotify();
// Overrides of this function should decodes an unspecified amount of
// audio data, enqueuing the audio data in mAudioQueue. Returns true
// when there's more audio to decode, false if the audio is finished,

View File

@ -168,9 +168,9 @@ public:
OwnerThread()->Dispatch(runnable.forget());
}
void DispatchNotifyDataArrived(bool aThrottleUpdates)
void DispatchNotifyDataArrived()
{
mReader->DispatchNotifyDataArrived(aThrottleUpdates);
mReader->DispatchNotifyDataArrived();
}
// Notifies the state machine that should minimize the number of samples

View File

@ -455,7 +455,7 @@ ChannelMediaResource::CopySegmentToCache(nsIInputStream *aInStream,
{
CopySegmentClosure* closure = static_cast<CopySegmentClosure*>(aClosure);
closure->mResource->mCallback->NotifyDataArrived(/* aThrottleUpdates = */ true);
closure->mResource->mCallback->NotifyDataArrived();
// Keep track of where we're up to.
RESOURCE_LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "

View File

@ -49,7 +49,7 @@ public:
virtual void NotifyDecodeError() {}
// Notify that data arrives on the stream and is read into the cache.
virtual void NotifyDataArrived(bool aThrottleUpdates) {}
virtual void NotifyDataArrived() {}
// Notify that MediaResource has received some data.
virtual void NotifyBytesDownloaded() {}

View File

@ -301,7 +301,7 @@ SourceBuffer::Ended()
mContentManager->Ended();
// We want the MediaSourceReader to refresh its buffered range as it may
// have been modified (end lined up).
mMediaSource->GetDecoder()->NotifyDataArrived(/* aThrottleUpdates = */ false);
mMediaSource->GetDecoder()->NotifyDataArrived();
}
SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
@ -481,9 +481,7 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
}
if (mActive) {
// Tell our parent decoder that we have received new data.
// The information provided do not matter much so long as it is monotonically
// increasing.
mMediaSource->GetDecoder()->NotifyDataArrived(/* aThrottleUpdates = */ false);
mMediaSource->GetDecoder()->NotifyDataArrived();
// Send progress event.
mMediaSource->GetDecoder()->NotifyBytesDownloaded();
}

View File

@ -57,7 +57,7 @@ public:
virtual MediaDecoderOwner* GetOwner() final override;
virtual void NotifyDataArrived(bool) final override {};
virtual void NotifyDataArrived() final override {};
private:
virtual ~BufferDecoder();

View File

@ -19,7 +19,7 @@ class OSXSpeechSynthesizerService final : public nsISpeechService
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSISPEECHSERVICE
NS_DECL_NSIOBSERVER

View File

@ -179,29 +179,43 @@ SpeechTaskCallback::OnDidFinishSpeaking()
namespace mozilla {
namespace dom {
class RegisterVoicesRunnable final : public nsRunnable
struct OSXVoice
{
public:
explicit RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService)
: mSpeechService(aSpeechService)
OSXVoice() : mIsDefault(false)
{
}
NS_IMETHOD Run();
nsString mUri;
nsString mName;
nsString mLocale;
bool mIsDefault;
};
class RegisterVoicesRunnable final : public nsRunnable
{
public:
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService,
nsTArray<OSXVoice>& aList)
: mSpeechService(aSpeechService)
, mVoices(aList)
{
}
NS_IMETHOD Run() override;
private:
~RegisterVoicesRunnable()
{
}
RefPtr<OSXSpeechSynthesizerService> mSpeechService;
// This runnable always use sync mode. It is unnecesarry to reference object
OSXSpeechSynthesizerService* mSpeechService;
nsTArray<OSXVoice>& mVoices;
};
NS_IMETHODIMP
RegisterVoicesRunnable::Run()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsresult rv;
nsCOMPtr<nsISynthVoiceRegistry> registry =
do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
@ -209,37 +223,75 @@ RegisterVoicesRunnable::Run()
return rv;
}
for (OSXVoice voice : mVoices) {
rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName, voice.mLocale, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
if (voice.mIsDefault) {
registry->SetDefaultVoice(voice.mUri, true);
}
}
return NS_OK;
}
class EnumVoicesRunnable final : public nsRunnable
{
public:
explicit EnumVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService)
: mSpeechService(aSpeechService)
{
}
NS_IMETHOD Run() override;
private:
~EnumVoicesRunnable()
{
}
RefPtr<OSXSpeechSynthesizerService> mSpeechService;
};
NS_IMETHODIMP
EnumVoicesRunnable::Run()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsAutoTArray<OSXVoice, 64> list;
NSArray* voices = [NSSpeechSynthesizer availableVoices];
NSString* defaultVoice = [NSSpeechSynthesizer defaultVoice];
for (NSString* voice in voices) {
OSXVoice item;
NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice];
nsAutoString identifier;
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier],
identifier);
nsAutoString name;
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName], name);
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName], item.mName);
nsAutoString locale;
nsCocoaUtils::GetStringForNSString(
[attr objectForKey:NSVoiceLocaleIdentifier], locale);
locale.ReplaceChar('_', '-');
[attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale);
item.mLocale.ReplaceChar('_', '-');
nsAutoString uri;
uri.AssignLiteral("urn:moz-tts:osx:");
uri.Append(identifier);
rv = registry->AddVoice(mSpeechService, uri, name, locale, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
item.mUri.AssignLiteral("urn:moz-tts:osx:");
item.mUri.Append(identifier);
if ([voice isEqualToString:defaultVoice]) {
registry->SetDefaultVoice(uri, true);
item.mIsDefault = true;
}
list.AppendElement(item);
}
RefPtr<RegisterVoicesRunnable> runnable = new RegisterVoicesRunnable(mSpeechService, list);
NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@ -274,9 +326,14 @@ OSXSpeechSynthesizerService::Init()
return false;
}
nsCOMPtr<nsIThread> thread;
if (NS_FAILED(NS_NewNamedThread("SpeechWorker", getter_AddRefs(thread)))) {
return false;
}
// Get all the voices and register in the SynthVoiceRegistry
nsCOMPtr<nsIRunnable> runnable = new RegisterVoicesRunnable(this);
NS_DispatchToMainThread(runnable);
nsCOMPtr<nsIRunnable> runnable = new EnumVoicesRunnable(this);
thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
mInitialized = true;
return true;

View File

@ -33,8 +33,9 @@
if (expectingLoads > 0) {
expectingLoads--;
}
if (!expectingLoads && !expectingErrors) {
if (!expectingLoads && !expectingErrors && afterExpectCallback) {
setTimeout(afterExpectCallback, 0);
afterExpectCallback = null;
}
}
function onImgError() {
@ -42,8 +43,9 @@
if (expectingErrors > 0) {
expectingErrors--;
}
if (!expectingLoads && !expectingErrors) {
if (!expectingLoads && !expectingErrors && afterExpectCallback) {
setTimeout(afterExpectCallback, 0);
afterExpectCallback = null;
}
}
function expectEvents(loads, errors, callback) {
@ -150,7 +152,7 @@
expectEvents(0, 0, nextTest);
});
// Re-binding image to document should be a no-op
// re-binding the image to the document should be a no-op
tests.push(function () {
info("test 8");
document.body.appendChild(img);
@ -167,19 +169,20 @@
expectEvents(1, 0, function() {
is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request");
SpecialPowers.pushPrefEnv({'set': [ ["layout.css.devPixelsPerPx", "2.0"] ] },
function() {
// We don't currently dynamically switch, but doing so is
// up to the UA so we may in the future. In which case
// this test needs to be changed.
is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request");
// The preference change will trigger a load, as the image will change
SpecialPowers.pushPrefEnv({'set': [ ["layout.css.devPixelsPerPx", "2.0"] ] });
expectEvents(1, 0, function() {
is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
img.src = img.src;
is(img.currentSrc, testPNG50, "Should still have testPNG50 as current request");
is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
// img.src = img.src is special-cased by the spec. It should always
// trigger an load event
expectEvents(1, 0, function() {
is(img.currentSrc, testPNG200, "Should now have testPNG200 as current request");
nextTest();
is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request");
expectEvents(0, 0, nextTest);
});
});
})
});
});
@ -206,6 +209,10 @@
(tests.shift())();
}, 0);
} else {
// Remove the event listeners to prevent the prefenv being popped from
// causing test failures.
img.removeEventListener("load", onImgLoad);
img.removeEventListener("error", onImgError);
SimpleTest.finish();
}
}

View File

@ -37,13 +37,13 @@
namespace skia {
// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
// |src_data| and continues for the num_values() of the filter.
void ConvolveHorizontally_LS3(const unsigned char* src_data,
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row) {
int num_values = filter.num_values();
int tmp, filter_offset, filter_length;
double zero, mask[3], shuf_50, shuf_fa;
double zero, mask[4], shuf_50, shuf_fa;
asm volatile (
".set push \n\t"
@ -51,27 +51,28 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
"xor %[zero], %[zero], %[zero] \n\t"
// |mask| will be used to decimate all extra filter coefficients that are
// loaded by SIMD when |filter_length| is not divisible by 4.
// mask[0] is not used in following algorithm.
"li %[tmp], 1 \n\t"
"dsll32 %[tmp], 0x10 \n\t"
"daddiu %[tmp], -1 \n\t"
"dmtc1 %[tmp], %[mask2] \n\t"
"dmtc1 %[tmp], %[mask3] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask2] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask1] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask0] \n\t"
"ori %[tmp], $0, 0x50 \n\t"
"mtc1 %[tmp], %[shuf_50] \n\t"
"ori %[tmp], $0, 0xfa \n\t"
"mtc1 %[tmp], %[shuf_fa] \n\t"
".set pop \n\t"
:[zero]"=f"(zero), [mask0]"=f"(mask[0]),
[mask1]"=f"(mask[1]), [mask2]"=f"(mask[2]),
:[zero]"=f"(zero), [mask1]"=f"(mask[1]),
[mask2]"=f"(mask[2]), [mask3]"=f"(mask[3]),
[shuf_50]"=f"(shuf_50), [shuf_fa]"=f"(shuf_fa),
[tmp]"=&r"(tmp)
);
// Output one pixel each iteration, calculating all channels (RGBA) together.
for (int out_x = begin; out_x < end; out_x++) {
for (int out_x = 0; out_x < num_values; out_x++) {
const ConvolutionFilter1D::Fixed* filter_values =
filter.FilterForValue(out_x, &filter_offset, &filter_length);
double accumh, accuml;
@ -203,7 +204,7 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
[mul_hih]"=&f"(mul_hih), [mul_hil]"=&f"(mul_hil),
[mul_loh]"=&f"(mul_loh), [mul_lol]"=&f"(mul_lol)
:[fval]"r"(filter_values), [rtf]"r"(row_to_filter),
[zeroh]"f"(zero), [zerol]"f"(zero), [mask]"f"(mask[r-1]),
[zeroh]"f"(zero), [zerol]"f"(zero), [mask]"f"(mask[r]),
[shuf_50]"f"(shuf_50), [shuf_fa]"f"(shuf_fa)
);
}
@ -235,15 +236,15 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
}
// Convolves horizontally along four rows. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
// |src_data| and continues for the num_values() of the filter.
// The algorithm is almost same as |ConvolveHorizontally_LS3|. Please
// refer to that function for detailed comments.
void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row[4]) {
int num_values = filter.num_values();
int tmp, filter_offset, filter_length;
double zero, mask[3], shuf_50, shuf_fa;
double zero, mask[4], shuf_50, shuf_fa;
asm volatile (
".set push \n\t"
@ -251,27 +252,28 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
"xor %[zero], %[zero], %[zero] \n\t"
// |mask| will be used to decimate all extra filter coefficients that are
// loaded by SIMD when |filter_length| is not divisible by 4.
// mask[0] is not used in following algorithm.
"li %[tmp], 1 \n\t"
"dsll32 %[tmp], 0x10 \n\t"
"daddiu %[tmp], -1 \n\t"
"dmtc1 %[tmp], %[mask2] \n\t"
"dmtc1 %[tmp], %[mask3] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask2] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask1] \n\t"
"dsrl %[tmp], 0x10 \n\t"
"mtc1 %[tmp], %[mask0] \n\t"
"ori %[tmp], $0, 0x50 \n\t"
"mtc1 %[tmp], %[shuf_50] \n\t"
"ori %[tmp], $0, 0xfa \n\t"
"mtc1 %[tmp], %[shuf_fa] \n\t"
".set pop \n\t"
:[zero]"=f"(zero), [mask0]"=f"(mask[0]),
[mask1]"=f"(mask[1]), [mask2]"=f"(mask[2]),
:[zero]"=f"(zero), [mask1]"=f"(mask[1]),
[mask2]"=f"(mask[2]), [mask3]"=f"(mask[3]),
[shuf_50]"=f"(shuf_50), [shuf_fa]"=f"(shuf_fa),
[tmp]"=&r"(tmp)
);
// Output one pixel each iteration, calculating all channels (RGBA) together.
for (int out_x = begin; out_x < end; out_x++) {
for (int out_x = 0; out_x < num_values; out_x++) {
const ConvolutionFilter1D::Fixed* filter_values =
filter.FilterForValue(out_x, &filter_offset, &filter_length);
double accum0h, accum0l, accum1h, accum1l;
@ -385,7 +387,7 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
:[coeffh]"=&f"(coeffh), [coeffl]"=&f"(coeffl),
[coeff16loh]"=&f"(coeff16loh), [coeff16lol]"=&f"(coeff16lol),
[coeff16hih]"=&f"(coeff16hih), [coeff16hil]"=&f"(coeff16hil)
:[fval]"r"(filter_values), [mask]"f"(mask[r-1]),
:[fval]"r"(filter_values), [mask]"f"(mask[r]),
[shuf_50]"f"(shuf_50), [shuf_fa]"f"(shuf_fa)
);
@ -440,16 +442,17 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
// Does vertical convolution to produce one output row. The filter values and
// length are given in the first two parameters. These are applied to each
// of the rows pointed to in the |source_data_rows| array, with each row
// being |end - begin| wide.
// being |pixel_width| wide.
//
// The output must have room for |(end - begin) * 4| bytes.
// The output must have room for |pixel_width * 4| bytes.
template<bool has_alpha>
void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row) {
uint64_t tmp;
int width = pixel_width & ~3;
double zero, sra, coeff16h, coeff16l;
double accum0h, accum0l, accum1h, accum1l;
double accum2h, accum2l, accum3h, accum3l;
@ -468,7 +471,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
);
// Output four pixels per iteration (16 bytes).
for (out_x = begin; out_x + 3 < end; out_x += 4) {
for (out_x = 0; out_x < width; out_x += 4) {
// Accumulated result for each pixel. 32 bits per RGBA channel.
asm volatile (
".set push \n\t"
@ -651,8 +654,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
// When the width of the output is not divisible by 4, We need to save one
// pixel (4 bytes) each time. And also the fourth pixel is always absent.
int r = end - out_x;
if (r > 0) {
if (pixel_width & 3) {
asm volatile (
".set push \n\t"
".set arch=loongson3a \n\t"
@ -793,7 +795,7 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
:[s4]"=f"(s4), [s64]"=f"(s64),
[tmp]"=&r"(tmp)
);
for (; out_x < end; out_x++) {
for (int out_x = width; out_x < pixel_width; out_x++) {
double t;
asm volatile (
@ -815,14 +817,14 @@ void ConvolveVertically_LS3_impl(const ConvolutionFilter1D::Fixed* filter_values
void ConvolveVertically_LS3(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row, bool has_alpha) {
if (has_alpha) {
ConvolveVertically_LS3_impl<true>(filter_values, filter_length,
source_data_rows, begin, end, out_row);
source_data_rows, pixel_width, out_row);
} else {
ConvolveVertically_LS3_impl<false>(filter_values, filter_length,
source_data_rows, begin, end, out_row);
source_data_rows, pixel_width, out_row);
}
}

View File

@ -40,7 +40,6 @@ namespace skia {
// Convolves horizontally along a single row. The row data is given in
// |src_data| and continues for the [begin, end) of the filter.
void ConvolveHorizontally_LS3(const unsigned char* src_data,
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row);
@ -49,7 +48,6 @@ void ConvolveHorizontally_LS3(const unsigned char* src_data,
// The algorithm is almost same as |ConvolveHorizontally_LS3|. Please
// refer to that function for detailed comments.
void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
int begin, int end,
const ConvolutionFilter1D& filter,
unsigned char* out_row[4]);
@ -62,7 +60,7 @@ void ConvolveHorizontally4_LS3(const unsigned char* src_data[4],
void ConvolveVertically_LS3(const ConvolutionFilter1D::Fixed* filter_values,
int filter_length,
unsigned char* const* source_data_rows,
int begin, int end,
int pixel_width,
unsigned char* out_row, bool has_alpha);
} // namespace skia

View File

@ -1166,7 +1166,6 @@ OOMTest(JSContext* cx, unsigned argc, Value* vp)
OOM_maxAllocations = UINT32_MAX;
MOZ_ASSERT_IF(ok, !cx->isExceptionPending());
MOZ_ASSERT_IF(!ok, cx->isExceptionPending());
// Note that it is possible that the function throws an exception
// unconnected to OOM, in which case we ignore it. More correct

View File

@ -1,3 +1,4 @@
// |jit-test| --ion-pgo=off;
// This script check that when we enable / disable the code coverage collection,
// then we have different results for the getOffsetsCoverage methods.

View File

@ -0,0 +1,14 @@
// |jit-test| allow-oom
// We need allow-oom here because the debugger reports an uncaught exception if
// it hits OOM calling the exception unwind hook. This causes the shell to exit
// with the OOM reason.
if (!('oomTest' in this))
quit();
var g = newGlobal();
g.parent = this;
g.eval("new Debugger(parent).onExceptionUnwind = function() {}");
let finished = false;
oomTest(() => l);

View File

@ -0,0 +1,12 @@
if (!('oomTest' in this))
quit();
function f() {
return this === null;
};
function g() {
if (!f.apply(9)) {}
}
oomTest(g);

View File

@ -1,4 +1,4 @@
// |jit-test| test-join=--no-unboxed-objects
// |jit-test| test-join=--no-unboxed-objects; --ion-pgo=on
//
// Unboxed object optimization might not trigger in all cases, thus we ensure
// that Scalar Replacement optimization is working well independently of the
@ -7,8 +7,8 @@
// Ion eager fails the test below because we have not yet created any
// template object in baseline before running the content of the top-level
// function.
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 30)
setJitCompilerOption("ion.warmup.trigger", 30);
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90)
setJitCompilerOption("ion.warmup.trigger", 90);
// This test checks that we are able to remove the getelem & setelem with scalar
// replacement, so we should not force inline caches, as this would skip the
@ -28,8 +28,11 @@ function f(j) {
i: i,
v: i + i
};
assertRecoveredOnBailout(obj, false); // :TODO: Fixed by Bug 1165348
assertRecoveredOnBailout(obj.v, false); // :TODO: Fixed by Bug 1165348
// These can only be recovered on bailout iff either we have type
// information for the property access in the branch, or the branch is
// removed before scalar replacement.
assertRecoveredOnBailout(obj, true);
assertRecoveredOnBailout(obj.v, true);
if (uceFault(j) || uceFault(j)) {
// MObjectState::recover should neither fail,
// nor coerce its result to an int32.

View File

@ -1,4 +1,4 @@
// |jit-test| test-join=--no-unboxed-objects
// |jit-test| test-join=--no-unboxed-objects; --ion-pgo=on
//
// Unboxed object optimization might not trigger in all cases, thus we ensure
// that Scalar Replacement optimization is working well independently of the
@ -25,7 +25,7 @@ var uceFault = function (i) {
// Without "use script" in the inner function, the arguments might be
// obersvable.
// observable.
function inline_notSoEmpty1(a, b, c, d) {
// This function is not strict, so we might be able to observe its
// arguments, if somebody ever called fun.arguments inside it.
@ -50,9 +50,10 @@ function notSoEmpty1() {
assertRecoveredOnBailout(c, true);
assertRecoveredOnBailout(d, true);
assertRecoveredOnBailout(unused, true);
// Scalar Replacement is coming after the branch removal made by GVN, and
// the ucefault branch is not taken yet.
assertRecoveredOnBailout(res, false);
// This can only be recovered on bailout iff either we have type
// information for the property access in the branch, or the branch is
// removed before scalar replacement.
assertRecoveredOnBailout(res, true);
}
// Check that we can recover objects with their content.
@ -75,9 +76,10 @@ function notSoEmpty2(i) {
assertRecoveredOnBailout(c, true);
assertRecoveredOnBailout(d, true);
assertRecoveredOnBailout(unused, true);
// Scalar Replacement is coming after the branch removal made by GVN, and
// the ucefault branch is not taken yet.
assertRecoveredOnBailout(res, false);
// This can only be recovered on bailout iff either we have type
// information for the property access in the branch, or the branch is
// removed before scalar replacement.
assertRecoveredOnBailout(res, true);
}
// Check that we can recover objects with their content.

View File

@ -270,17 +270,21 @@ jit::EnsureHasScopeObjects(JSContext* cx, AbstractFramePtr fp)
}
bool
jit::CheckFrequentBailouts(JSContext* cx, JSScript* script)
jit::CheckFrequentBailouts(JSContext* cx, JSScript* script, BailoutKind bailoutKind)
{
if (script->hasIonScript()) {
// Invalidate if this script keeps bailing out without invalidation. Next time
// we compile this script LICM will be disabled.
IonScript* ionScript = script->ionScript();
if (ionScript->numBailouts() >= js_JitOptions.frequentBailoutThreshold &&
!script->hadFrequentBailouts())
{
script->setHadFrequentBailouts();
if (ionScript->numBailouts() >= js_JitOptions.frequentBailoutThreshold) {
// If we bailout because of the first execution of a basic block,
// then we should record which basic block we are returning in,
// which should prevent this from happening again. Also note that
// the first execution bailout can be related to an inlined script,
// so there is no need to penalize the caller.
if (bailoutKind != Bailout_FirstExecution && !script->hadFrequentBailouts())
script->setHadFrequentBailouts();
JitSpew(JitSpew_IonInvalidate, "Invalidating due to too many bailouts");

View File

@ -211,7 +211,7 @@ uint32_t ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame
uint32_t FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo);
bool CheckFrequentBailouts(JSContext* cx, JSScript* script);
bool CheckFrequentBailouts(JSContext* cx, JSScript* script, BailoutKind bailoutKind);
} // namespace jit
} // namespace js

View File

@ -795,6 +795,16 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
jsbytecode* pc = catchingException ? excInfo->resumePC() : script->offsetToPC(iter.pcOffset());
bool resumeAfter = catchingException ? false : iter.resumeAfter();
// When pgo is enabled, increment the counter of the block in which we
// resume, as Ion does not keep track of the code coverage.
//
// We need to do that when pgo is enabled, as after a specific number of
// FirstExecution bailouts, we invalidate and recompile the script with
// IonMonkey. Failing to increment the counter of the current basic block
// might lead to repeated bailouts and invalidations.
if (!js_JitOptions.disablePgo && script->hasScriptCounts())
script->incHitCount(pc);
JSOp op = JSOp(*pc);
// Fixup inlined JSOP_FUNCALL, JSOP_FUNAPPLY, and accessors on the caller side.
@ -1890,6 +1900,12 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
// Do nothing.
break;
case Bailout_FirstExecution:
// Do not return directly, as this was not frequent in the first place,
// thus rely on the check for frequent bailouts to recompile the current
// script.
break;
// Invalid assumption based on baseline code.
case Bailout_OverflowInvalidate:
case Bailout_NonStringInputInvalidate:
@ -1923,7 +1939,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
MOZ_CRASH("Unknown bailout kind!");
}
if (!CheckFrequentBailouts(cx, outerScript))
if (!CheckFrequentBailouts(cx, outerScript, bailoutKind))
return false;
// We're returning to JIT code, so we should clear the override pc.

View File

@ -1503,6 +1503,17 @@ OptimizeMIR(MIRGenerator* mir)
if (mir->shouldCancel("Start"))
return false;
if (!js_JitOptions.disablePgo && !mir->compilingAsmJS()) {
AutoTraceLog log(logger, TraceLogger_PruneUnusedBranches);
if (!PruneUnusedBranches(mir, graph))
return false;
gs.spewPass("Prune Unused Branches");
AssertBasicGraphCoherency(graph);
if (mir->shouldCancel("Prune Unused Branches"))
return false;
}
{
AutoTraceLog log(logger, TraceLogger_FoldTests);
if (!FoldTests(graph))

View File

@ -27,6 +27,390 @@ using namespace js::jit;
using mozilla::DebugOnly;
typedef Vector<MPhi*, 16, SystemAllocPolicy> MPhiVector;
static bool
FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVector& worklist)
{
// When removing an edge between 2 blocks, we might remove the ability of
// later phases to figure out that the uses of a Phi should be considered as
// a use of all its inputs. Thus we need to mark the Phi inputs as having
// removed uses iff the phi has any uses.
//
//
// +--------------------+ +---------------------+
// |12 MFoo 6 | |32 MBar 5 |
// | | | |
// | ... | | ... |
// | | | |
// |25 MGoto Block 4 | |43 MGoto Block 4 |
// +--------------------+ +---------------------+
// | |
// | | |
// | | |
// | +-----X------------------------+
// | Edge |
// | Removed |
// | |
// | +------------v-----------+
// | |50 MPhi 12 32 |
// | | |
// | | ... |
// | | |
// | |70 MReturn 50 |
// | +------------------------+
// |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |
// v
//
// ^ +--------------------+ +---------------------+
// /!\ |12 MConst opt-out | |32 MBar 5 |
// '---' | | | |
// | ... | | ... |
// |78 MBail | | |
// |80 MUnreachable | |43 MGoto Block 4 |
// +--------------------+ +---------------------+
// |
// |
// |
// +---------------+
// |
// |
// |
// +------------v-----------+
// |50 MPhi 32 |
// | |
// | ... |
// | |
// |70 MReturn 50 |
// +------------------------+
//
//
// If the inputs of the Phi are not flagged as having removed uses, then
// later compilation phase might optimize them out. The problem is that a
// bailout will use this value and give it back to baseline, which will then
// use the OptimizedOut magic value in a computation.
// Conservative upper limit for the number of Phi instructions which are
// visited while looking for uses.
const size_t conservativeUsesLimit = 128;
MOZ_ASSERT(worklist.empty());
size_t predIndex = succ->getPredecessorIndex(block);
MPhiIterator end = succ->phisEnd();
MPhiIterator it = succ->phisBegin();
for (; it != end; it++) {
MPhi* phi = *it;
// We are looking to mark the Phi inputs which are used across the edge
// between the |block| and its successor |succ|.
MDefinition* def = phi->getOperand(predIndex);
if (def->isUseRemoved())
continue;
phi->setInWorklist();
if (!worklist.append(phi))
return false;
// Fill the work list with all the Phi nodes uses until we reach either:
// - A resume point which uses the Phi as an observable operand.
// - An explicit use of the Phi instruction.
// - An implicit use of the Phi instruction.
bool isUsed = false;
for (size_t idx = 0; !isUsed && idx < worklist.length(); idx++) {
phi = worklist[idx];
MUseIterator usesEnd(phi->usesEnd());
for (MUseIterator use(phi->usesBegin()); use != usesEnd; use++) {
MNode* consumer = (*use)->consumer();
if (consumer->isResumePoint()) {
MResumePoint* rp = consumer->toResumePoint();
if (rp->isObservableOperand(*use)) {
// The phi is observable via a resume point operand.
isUsed = true;
break;
}
continue;
}
MDefinition* cdef = consumer->toDefinition();
if (!cdef->isPhi()) {
// The phi is explicitly used.
isUsed = true;
break;
}
phi = cdef->toPhi();
if (phi->isInWorklist())
continue;
if (phi->isUseRemoved() || phi->isImplicitlyUsed()) {
// The phi is implicitly used.
isUsed = true;
break;
}
phi->setInWorklist();
if (!worklist.append(phi))
return false;
}
// Use a conservative upper bound to avoid iterating too many times
// on very large graphs.
if (idx >= conservativeUsesLimit) {
isUsed = true;
break;
}
}
if (isUsed)
def->setUseRemoved();
// Remove all the InWorklist flags.
while (!worklist.empty()) {
phi = worklist.popCopy();
phi->setNotInWorklist();
}
}
return true;
}
static bool
FlagAllOperandsAsHavingRemovedUses(MBasicBlock* block)
{
// Flag all instructions operands as having removed uses.
MInstructionIterator end = block->end();
for (MInstructionIterator it = block->begin(); it != end; it++) {
MInstruction* ins = *it;
for (size_t i = 0, e = ins->numOperands(); i < e; i++)
ins->getOperand(i)->setUseRemovedUnchecked();
// Flag observable resume point operands as having removed uses.
if (MResumePoint* rp = ins->resumePoint()) {
// Note: no need to iterate over the caller's of the resume point as
// this is the same as the entry resume point.
for (size_t i = 0, e = rp->numOperands(); i < e; i++) {
if (!rp->isObservableOperand(i))
continue;
rp->getOperand(i)->setUseRemovedUnchecked();
}
}
}
// Flag observable operands of the entry resume point as having removed uses.
MResumePoint* rp = block->entryResumePoint();
do {
for (size_t i = 0, e = rp->numOperands(); i < e; i++) {
if (!rp->isObservableOperand(i))
continue;
rp->getOperand(i)->setUseRemovedUnchecked();
}
rp = rp->caller();
} while (rp);
// Flag Phi inputs of the successors has having removed uses.
MPhiVector worklist;
for (size_t i = 0, e = block->numSuccessors(); i < e; i++) {
if (!FlagPhiInputsAsHavingRemovedUses(block, block->getSuccessor(i), worklist))
return false;
}
return true;
}
static void
RemoveFromSuccessors(MBasicBlock* block)
{
// Remove this block from its successors.
size_t numSucc = block->numSuccessors();
while (numSucc--) {
MBasicBlock* succ = block->getSuccessor(numSucc);
if (succ->isDead())
continue;
JitSpew(JitSpew_Prune, "Remove block edge %d -> %d.", block->id(), succ->id());
succ->removePredecessor(block);
}
}
static void
ConvertToBailingBlock(TempAllocator& alloc, MBasicBlock* block)
{
// Add a bailout instruction.
MBail* bail = MBail::New(alloc, Bailout_FirstExecution);
MInstruction* bailPoint = block->safeInsertTop();
block->insertBefore(block->safeInsertTop(), bail);
// Discard all remaining instructions.
MInstructionIterator clearStart = block->begin(bailPoint);
block->discardAllInstructionsStartingAt(clearStart);
if (block->outerResumePoint())
block->clearOuterResumePoint();
// And replace the last instruction by the unreachable control instruction.
block->end(MUnreachable::New(alloc));
}
bool
jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph)
{
MOZ_ASSERT(!mir->compilingAsmJS(), "AsmJS compilation have no code coverage support.");
// We do a reverse-post-order traversal, marking basic blocks when the block
// have to be converted into bailing blocks, and flagging block as
// unreachable if all predecessors are flagged as bailing or unreachable.
bool someUnreachable = false;
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
JitSpew(JitSpew_Prune, "Investigate Block %d:", block->id());
// Do not touch entry basic blocks.
if (*block == graph.osrBlock() || *block == graph.entryBlock())
continue;
// Compute if all the predecessors of this block are either bailling out
// or are already flagged as unreachable.
bool isUnreachable = true;
bool isLoopHeader = block->isLoopHeader();
size_t numPred = block->numPredecessors();
size_t i = 0;
for (; i < numPred; i++) {
MBasicBlock* pred = block->getPredecessor(i);
// The backedge is visited after the loop header, but if the loop
// header is unreachable, then we can assume that the backedge would
// be unreachable too.
if (isLoopHeader && pred == block->backedge())
continue;
// Break if any of the predecessor can continue in this block.
if (!pred->isMarked() && !pred->unreachable()) {
isUnreachable = false;
break;
}
}
// Compute if the block should bailout, based on the trivial heuristic
// which is that if the block never got visited before, then it is
// likely to not be visited after.
bool shouldBailout =
block->getHitState() == MBasicBlock::HitState::Count &&
block->getHitCount() == 0;
// Check if the predecessors got accessed a large number of times in
// comparisons of the current block, in order to know if our attempt at
// removing this block is not premature.
if (shouldBailout) {
size_t p = numPred;
size_t predCount = 0;
bool isLoopExit = false;
while (p--) {
MBasicBlock* pred = block->getPredecessor(p);
if (pred->getHitState() == MBasicBlock::HitState::Count)
predCount += pred->getHitCount();
isLoopExit |= pred->isLoopHeader() && pred->backedge() != *block;
}
// This assumes that instructions are numbered in sequence, which is
// the case after IonBuilder creation of basic blocks.
size_t numInst = block->rbegin()->id() - block->begin()->id();
// This sum is not homogeneous but gives good results on benchmarks
// like Kraken and Octane. The current block has not been executed
// yet, and ...
//
// 1. If the number of times the predecessor got executed is
// larger, then we are less likely to hit this block.
//
// 2. If the block is large, then this is likely a corner case,
// and thus we are less likely to hit this block.
if (predCount + numInst < 75)
shouldBailout = false;
// If this is the exit block of a loop, then keep this basic
// block. This heuristic is useful as a bailout is often much more
// costly than a simple exit sequence.
if (isLoopExit)
shouldBailout = false;
}
// Continue to the next basic block if the current basic block can
// remain unchanged.
if (!isUnreachable && !shouldBailout)
continue;
JitSpewIndent indent(JitSpew_Prune);
someUnreachable = true;
if (isUnreachable) {
JitSpew(JitSpew_Prune, "Mark block %d as unreachable.", block->id());
block->setUnreachable();
// If the block is unreachable, then there is no need to convert it
// to a bailing block.
} else if (shouldBailout) {
JitSpew(JitSpew_Prune, "Mark block %d as bailing block.", block->id());
block->markUnchecked();
}
// When removing a loop header, we should ensure that its backedge is
// removed first, otherwise this triggers an assertion in
// removePredecessorsWithoutPhiOperands.
if (block->isLoopHeader()) {
JitSpew(JitSpew_Prune, "Mark block %d as bailing block. (loop backedge)", block->backedge()->id());
block->backedge()->markUnchecked();
}
}
// Returns early if nothing changed.
if (!someUnreachable)
return true;
JitSpew(JitSpew_Prune, "Convert basic block to bailing blocks, and remove unreachable blocks:");
JitSpewIndent indent(JitSpew_Prune);
// As we are going to remove edges and basic block, we have to mark
// instructions which would be needed by baseline if we were to bailout.
for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) {
MBasicBlock* block = *it++;
if (!block->isMarked() && !block->unreachable())
continue;
FlagAllOperandsAsHavingRemovedUses(block);
}
// Remove the blocks in post-order such that consumers are visited before
// the predecessors, the only exception being the Phi nodes of loop headers.
for (PostorderIterator it(graph.poBegin()); it != graph.poEnd();) {
MBasicBlock* block = *it++;
if (!block->isMarked() && !block->unreachable())
continue;
JitSpew(JitSpew_Prune, "Remove / Replace block %d.", block->id());
JitSpewIndent indent(JitSpew_Prune);
// As we are going to replace/remove the last instruction, we first have
// to remove this block from the predecessor list of its successors.
RemoveFromSuccessors(block);
// Convert the current basic block to a bailing block which ends with an
// Unreachable control instruction.
if (block->isMarked()) {
JitSpew(JitSpew_Prune, "Convert Block %d to a bailing block.", block->id());
if (!graph.alloc().ensureBallast())
return false;
ConvertToBailingBlock(graph.alloc(), block);
block->unmark();
}
// Remove all instructions.
if (block->unreachable()) {
JitSpew(JitSpew_Prune, "Remove Block %d.", block->id());
JitSpewIndent indent(JitSpew_Prune);
graph.removeBlock(block);
}
}
return true;
}
static bool
SplitCriticalEdgesForBlock(MIRGraph& graph, MBasicBlock* block)
{
@ -496,7 +880,7 @@ jit::EliminateDeadResumePointOperands(MIRGenerator* mir, MIRGraph& graph)
// If the instruction's behavior has been constant folded into a
// separate instruction, we can't determine precisely where the
// instruction becomes dead and can't eliminate its uses.
if (ins->isImplicitlyUsed())
if (ins->isImplicitlyUsed() || ins->isUseRemoved())
continue;
// Check if this instruction's result is only used within the
@ -609,7 +993,7 @@ IsPhiObservable(MPhi* phi, Observability observe)
{
// If the phi has uses which are not reflected in SSA, then behavior in the
// interpreter may be affected by removing the phi.
if (phi->isImplicitlyUsed())
if (phi->isImplicitlyUsed() || phi->isUseRemoved())
return true;
// Check for uses of this phi node outside of other phi nodes.

View File

@ -18,6 +18,9 @@ namespace jit {
class MIRGenerator;
class MIRGraph;
bool
PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph);
bool
FoldTests(MIRGraph& graph);

View File

@ -733,12 +733,9 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
bool
IonBuilder::pushLoop(CFGState::State initial, jsbytecode* stopAt, MBasicBlock* entry, bool osr,
jsbytecode* loopHead, jsbytecode* initialPc,
jsbytecode* bodyStart, jsbytecode* bodyEnd, jsbytecode* exitpc,
jsbytecode* continuepc)
jsbytecode* bodyStart, jsbytecode* bodyEnd,
jsbytecode* exitpc, jsbytecode* continuepc)
{
if (!continuepc)
continuepc = entry->pc();
ControlFlowInfo loop(cfgStack_.length(), continuepc);
if (!loops_.append(loop))
return false;
@ -3133,7 +3130,7 @@ IonBuilder::doWhileLoop(JSOp op, jssrcnote* sn)
bool osr = info().hasOsrAt(loopEntry);
if (osr) {
MBasicBlock* preheader = newOsrPreheader(current, loopEntry);
MBasicBlock* preheader = newOsrPreheader(current, loopEntry, pc);
if (!preheader)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), preheader));
@ -3142,7 +3139,7 @@ IonBuilder::doWhileLoop(JSOp op, jssrcnote* sn)
}
unsigned stackPhiCount = 0;
MBasicBlock* header = newPendingLoopHeader(current, pc, osr, canOsr, stackPhiCount);
MBasicBlock* header = newPendingLoopHeader(current, loopEntry, osr, canOsr, stackPhiCount);
if (!header)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), header));
@ -3198,7 +3195,7 @@ IonBuilder::whileOrForInLoop(jssrcnote* sn)
bool osr = info().hasOsrAt(loopEntry);
if (osr) {
MBasicBlock* preheader = newOsrPreheader(current, loopEntry);
MBasicBlock* preheader = newOsrPreheader(current, loopEntry, pc);
if (!preheader)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), preheader));
@ -3214,7 +3211,7 @@ IonBuilder::whileOrForInLoop(jssrcnote* sn)
else
stackPhiCount = 0;
MBasicBlock* header = newPendingLoopHeader(current, pc, osr, canOsr, stackPhiCount);
MBasicBlock* header = newPendingLoopHeader(current, loopEntry, osr, canOsr, stackPhiCount);
if (!header)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), header));
@ -3224,10 +3221,11 @@ IonBuilder::whileOrForInLoop(jssrcnote* sn)
jsbytecode* bodyStart = GetNextPc(loopHead);
jsbytecode* bodyEnd = pc + GetJumpOffset(pc);
jsbytecode* exitpc = GetNextPc(ifne);
jsbytecode* continuepc = pc;
if (!analyzeNewLoopTypes(header, bodyStart, exitpc))
return ControlStatus_Error;
if (!pushLoop(CFGState::WHILE_LOOP_COND, ifne, header, osr,
loopHead, bodyEnd, bodyStart, bodyEnd, exitpc))
loopHead, bodyEnd, bodyStart, bodyEnd, exitpc, continuepc))
{
return ControlStatus_Error;
}
@ -3299,7 +3297,7 @@ IonBuilder::forLoop(JSOp op, jssrcnote* sn)
bool canOsr = LoopEntryCanIonOsr(loopEntry);
if (osr) {
MBasicBlock* preheader = newOsrPreheader(current, loopEntry);
MBasicBlock* preheader = newOsrPreheader(current, loopEntry, pc);
if (!preheader)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), preheader));
@ -3308,7 +3306,7 @@ IonBuilder::forLoop(JSOp op, jssrcnote* sn)
}
unsigned stackPhiCount = 0;
MBasicBlock* header = newPendingLoopHeader(current, pc, osr, canOsr, stackPhiCount);
MBasicBlock* header = newPendingLoopHeader(current, loopEntry, osr, canOsr, stackPhiCount);
if (!header)
return ControlStatus_Error;
current->end(MGoto::New(alloc(), header));
@ -7280,6 +7278,8 @@ IonBuilder::addBlock(MBasicBlock* block, uint32_t loopDepth)
{
if (!block)
return nullptr;
if (block->pc() && script()->hasScriptCounts())
block->setHitCount(script()->getHitCount(block->pc()));
graph().addBlock(block);
block->setLoopDepth(loopDepth);
return block;
@ -7316,6 +7316,7 @@ IonBuilder::newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode*
bytecodeSite(pc), MBasicBlock::NORMAL);
if (!block)
return nullptr;
block->setHitCount(0); // osr block
graph().insertBlockAfter(at, block);
return block;
}
@ -7329,7 +7330,7 @@ IonBuilder::newBlock(MBasicBlock* predecessor, jsbytecode* pc, uint32_t loopDept
}
MBasicBlock*
IonBuilder::newOsrPreheader(MBasicBlock* predecessor, jsbytecode* loopEntry)
IonBuilder::newOsrPreheader(MBasicBlock* predecessor, jsbytecode* loopEntry, jsbytecode* beforeLoopEntry)
{
MOZ_ASSERT(LoopEntryCanIonOsr(loopEntry));
MOZ_ASSERT(loopEntry == info().osrPc());
@ -7342,6 +7343,10 @@ IonBuilder::newOsrPreheader(MBasicBlock* predecessor, jsbytecode* loopEntry)
if (!osrBlock || !preheader)
return nullptr;
// Give the pre-header the same hit count as the code before the loop.
if (script()->hasScriptCounts())
preheader->setHitCount(script()->getHitCount(beforeLoopEntry));
MOsrEntry* entry = MOsrEntry::New(alloc());
osrBlock->add(entry);

View File

@ -268,8 +268,8 @@ class IonBuilder
ControlStatus maybeLoop(JSOp op, jssrcnote* sn);
bool pushLoop(CFGState::State state, jsbytecode* stopAt, MBasicBlock* entry, bool osr,
jsbytecode* loopHead, jsbytecode* initialPc,
jsbytecode* bodyStart, jsbytecode* bodyEnd, jsbytecode* exitpc,
jsbytecode* continuepc = nullptr);
jsbytecode* bodyStart, jsbytecode* bodyEnd,
jsbytecode* exitpc, jsbytecode* continuepc);
bool analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecode* end);
MBasicBlock* addBlock(MBasicBlock* block, uint32_t loopDepth);
@ -278,7 +278,8 @@ class IonBuilder
MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, MResumePoint* priorResumePoint);
MBasicBlock* newBlockPopN(MBasicBlock* predecessor, jsbytecode* pc, uint32_t popped);
MBasicBlock* newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode* pc);
MBasicBlock* newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry);
MBasicBlock* newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry,
jsbytecode* beforeLoopEntry);
MBasicBlock* newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool osr, bool canOsr,
unsigned stackPhiCount);
MBasicBlock* newBlock(jsbytecode* pc) {

View File

@ -117,6 +117,9 @@ enum BailoutKind
// Derived constructors must return object or undefined
Bailout_BadDerivedConstructorReturn,
// We hit this code for the first time.
Bailout_FirstExecution,
// END Normal bailouts
// Bailouts caused by invalid assumptions based on Baseline code.
@ -218,6 +221,8 @@ BailoutKindString(BailoutKind kind)
return "Bailout_UninitializedThis";
case Bailout_BadDerivedConstructorReturn:
return "Bailout_BadDerivedConstructorReturn";
case Bailout_FirstExecution:
return "Bailout_FirstExecution";
// Bailouts caused by invalid assumptions.
case Bailout_OverflowInvalidate:

View File

@ -259,6 +259,8 @@ JSONSpewer::spewMIR(MIRGraph* mir)
beginObject();
integerProperty("number", block->id());
if (block->getHitState() == MBasicBlock::HitState::Count)
integerProperty("count", block->getHitCount());
beginListProperty("attributes");
if (block->isLoopBackedge())

Some files were not shown because too many files have changed in this diff Show More