Merge m-c to b2ginbound, a=merge CLOSED TREE
--HG-- extra : commitid : 6BLSZLPbxgy
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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 () {
|
||||
|
@ -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"/>
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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;
|
||||
}
|
||||
|
31
browser/themes/shared/identity-block/identity-icon.svg
Executable 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 |
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
Before Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 223 B |
Before Width: | Height: | Size: 150 B After Width: | Height: | Size: 108 B |
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 151 B |
Before Width: | Height: | Size: 288 B After Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 195 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 323 B |
@ -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 |
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 866 B |
Before Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 1.7 KiB |
@ -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 |
@ -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 |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 330 B |
@ -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 |
Before Width: | Height: | Size: 709 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 469 B |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 168 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 160 B |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 302 B |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 272 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 98 B |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 116 B |
@ -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 */
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
BIN
dom/html/test/file_bug1166138_1x.png
Normal file
After Width: | Height: | Size: 91 B |
BIN
dom/html/test/file_bug1166138_2x.png
Normal file
After Width: | Height: | Size: 100 B |
BIN
dom/html/test/file_bug1166138_def.png
Normal file
After Width: | Height: | Size: 85 B |
@ -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]
|
||||
|
130
dom/html/test/test_bug1166138.html
Normal 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>
|
@ -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.
|
||||
|
@ -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) {}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 "
|
||||
|
@ -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() {}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
|
||||
virtual MediaDecoderOwner* GetOwner() final override;
|
||||
|
||||
virtual void NotifyDataArrived(bool) final override {};
|
||||
virtual void NotifyDataArrived() final override {};
|
||||
|
||||
private:
|
||||
virtual ~BufferDecoder();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
14
js/src/jit-test/tests/debug/bug1219905.js
Normal 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);
|
12
js/src/jit-test/tests/gc/bug-1223021.js
Normal file
@ -0,0 +1,12 @@
|
||||
if (!('oomTest' in this))
|
||||
quit();
|
||||
|
||||
function f() {
|
||||
return this === null;
|
||||
};
|
||||
|
||||
function g() {
|
||||
if (!f.apply(9)) {}
|
||||
}
|
||||
|
||||
oomTest(g);
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
@ -18,6 +18,9 @@ namespace jit {
|
||||
class MIRGenerator;
|
||||
class MIRGraph;
|
||||
|
||||
bool
|
||||
PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph);
|
||||
|
||||
bool
|
||||
FoldTests(MIRGraph& graph);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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())
|
||||
|