Merge autoland to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2019-07-11 07:02:15 +03:00
commit 4b4656bd47
408 changed files with 1491 additions and 1177 deletions

View File

@ -359,12 +359,14 @@ var gSync = {
const mainWindowEl = document.documentElement;
// The Firefox Account toolbar currently handles 3 different states for
// users. The default `not_configured state shows an empty avatar, `unverified`
// users. The default `not_configured` state shows an empty avatar, `unverified`
// state shows an avatar with an email icon and the `verified` state will show
// the users custom profile image or a filled avatar.
let stateValue = "not_configured";
document.getElementById("PanelUI-fxa").removeAttribute("title");
if (
if (state.status === UIState.STATUS_NOT_CONFIGURED) {
mainWindowEl.style.removeProperty("--avatar-image-url");
} else if (
state.status === UIState.STATUS_LOGIN_FAILED ||
state.status === UIState.STATUS_NOT_VERIFIED
) {

View File

@ -103,6 +103,7 @@ let LEGACY_ACTORS = {
},
messages: [
"AboutLogins:AllLogins",
"AboutLogins:UpdateBreaches",
"AboutLogins:LoginAdded",
"AboutLogins:LoginModified",
"AboutLogins:LoginRemoved",

View File

@ -111,6 +111,9 @@ class AboutLoginsChild extends ActorChild {
case "AboutLogins:AllLogins":
this.sendToContent("AllLogins", message.data);
break;
case "AboutLogins:UpdateBreaches":
this.sendToContent("UpdateBreaches", message.data);
break;
case "AboutLogins:LoginAdded":
this.sendToContent("LoginAdded", message.data);
break;

View File

@ -24,6 +24,11 @@ ChromeUtils.defineModuleGetter(
"MigrationUtils",
"resource:///modules/MigrationUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"RemoteSettings",
"resource://services-settings/remote-settings.js"
);
ChromeUtils.defineModuleGetter(
this,
"Services",
@ -177,9 +182,12 @@ var AboutLoginsParent = {
this._subscribers.add(message.target);
let messageManager = message.target.messageManager;
const logins = await this.getAllLogins();
messageManager.sendAsyncMessage("AboutLogins:AllLogins", logins);
const breachesByLoginGUID = await this.getBreachesForLogins(logins);
messageManager.sendAsyncMessage(
"AboutLogins:AllLogins",
await this.getAllLogins()
"AboutLogins:UpdateBreaches",
breachesByLoginGUID
);
break;
}
@ -365,4 +373,24 @@ var AboutLoginsParent = {
throw e;
}
},
async getBreachesForLogins(logins) {
const breaches = await RemoteSettings("fxmonitor-breaches").get();
const breachHostMap = new Map();
for (const breach of breaches) {
breachHostMap.set(breach.Domain, breach);
}
const breachesByLoginGUID = new Map();
for (const login of logins) {
const loginURI = Services.io.newURI(login.origin);
const breach = breachHostMap.get(loginURI.host) || false;
if (
breach &&
login.timePasswordChanged < new Date(breach.BreachDate).getTime()
) {
breachesByLoginGUID.set(login.guid, breach);
}
}
return breachesByLoginGUID;
},
};

View File

@ -88,8 +88,8 @@
<span class="login-item-title"></span>
<span class="new-login-title" data-l10n-id="login-item-new-login-title"></span>
</h2>
<button class="edit-button alternate-button" data-l10n-id="login-item-edit-button"></button>
<button class="delete-button alternate-button" data-l10n-id="login-item-delete-button"></button>
<button class="edit-button ghost-button" data-l10n-id="login-item-edit-button"></button>
<button class="delete-button ghost-button" data-l10n-id="login-item-delete-button"></button>
</div>
<form>
<div class="detail-row">
@ -143,12 +143,12 @@
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/common.css">
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/menu-button.css">
<button class="menu-button alternate-button" data-l10n-id="menu"></button>
<button class="menu-button ghost-button" data-l10n-id="menu"></button>
<ul class="menu" role="menu" hidden>
<button role="menuitem" class="menuitem-button menuitem-import alternate-button" hidden data-supported-platforms="Win32" data-event-name="AboutLoginsImport" data-l10n-id="menu-menuitem-import"></button>
<button role="menuitem" class="menuitem-button menuitem-preferences alternate-button" data-event-name="AboutLoginsOpenPreferences" data-l10n-id="menu-menuitem-preferences"></button>
<button role="menuitem" class="menuitem-button menuitem-feedback alternate-button" data-event-name="AboutLoginsOpenFeedback" data-l10n-id="menu-menuitem-feedback"></button>
<button role="menuitem" class="menuitem-button menuitem-faq alternate-button" data-event-name="AboutLoginsOpenFAQ" data-l10n-id="menu-menuitem-faq"></button>
<button role="menuitem" class="menuitem-button menuitem-import ghost-button" hidden data-supported-platforms="Win32" data-event-name="AboutLoginsImport" data-l10n-id="menu-menuitem-import"></button>
<button role="menuitem" class="menuitem-button menuitem-preferences ghost-button" data-event-name="AboutLoginsOpenPreferences" data-l10n-id="menu-menuitem-preferences"></button>
<button role="menuitem" class="menuitem-button menuitem-feedback ghost-button" data-event-name="AboutLoginsOpenFeedback" data-l10n-id="menu-menuitem-feedback"></button>
<button role="menuitem" class="menuitem-button menuitem-faq ghost-button" data-event-name="AboutLoginsOpenFAQ" data-l10n-id="menu-menuitem-faq"></button>
</ul>
</template>
</body>

View File

@ -31,6 +31,10 @@ window.addEventListener("AboutLoginsChromeToContent", event => {
gElements.loginList.setLogins(event.detail.value);
break;
}
case "UpdateBreaches": {
gElements.loginList.updateBreaches(event.detail.value);
break;
}
case "LoginAdded": {
gElements.loginList.loginAdded(event.detail.value);
gElements.loginItem.loginAdded(event.detail.value);

View File

@ -7,15 +7,3 @@
[hidden] {
display: none !important;
}
.alternate-button {
background-color: transparent;
}
.alternate-button:hover {
background-color: var(--in-content-button-background-hover);
}
.alternate-button:hover:active {
background-color: var(--in-content-button-background-active);
}

View File

@ -65,6 +65,10 @@ ol {
background-color: var(--in-content-box-background-hover);
}
.login-list-item.breached {
border-inline-start-color: var(--in-content-border-invalid);
}
.title {
font-weight: bold;
}

View File

@ -90,7 +90,12 @@ export default class LoginList extends HTMLElement {
if (login.guid == this._selectedGuid) {
this._setListItemAsSelected(listItem);
}
if (
this._breachesByLoginGUID &&
this._breachesByLoginGUID.has(login.guid)
) {
listItem.classList.add("breached");
}
if (!visibleLogins.includes(login.guid)) {
listItem.hidden = true;
}
@ -212,6 +217,14 @@ export default class LoginList extends HTMLElement {
}
}
/**
* @param {Map} breachesByLoginGUID A Map of breaches by login GUIDs used for displaying breached login indicators.
*/
updateBreaches(breachesByLoginGUID) {
this._breachesByLoginGUID = breachesByLoginGUID;
this.render();
}
/**
* @param {login} login A login that was added to storage.
*/

View File

@ -18,8 +18,9 @@ add_task(async function() {
// This is due to a fetch request that has the default user context. Since
// the fetch request omits credentials, the user context doesn't matter.
"addons",
// about:credits will initiate network request.
// about:credits and about:logins will initiate network request.
"credits",
"logins",
// about:telemetry will fetch Telemetry asynchronously and takes longer,
// so we skip this for now.
"telemetry",

View File

@ -168,7 +168,7 @@ add_task(async function test_aboutURL() {
let aboutURLs = [];
// List of about: URLs that will initiate network requests.
let networkURLs = ["credits"];
let networkURLs = ["credits", "logins"];
for (let cid in Cc) {
let result = cid.match(

View File

@ -20,12 +20,9 @@ var UrlbarTestUtils = {
* @param {object} win The window containing the urlbar
* @returns {Promise} Resolved when done.
*/
promiseSearchComplete(win) {
let urlbar = getUrlbarAbstraction(win);
return BrowserTestUtils.waitForPopupEvent(urlbar.panel, "shown").then(
async () => {
await urlbar.promiseSearchComplete();
}
async promiseSearchComplete(win) {
return BrowserTestUtils.waitForPopupEvent(win.gURLBar.panel, "shown").then(
() => win.gURLBar.lastQueryContextPromise
);
},
@ -48,29 +45,28 @@ var UrlbarTestUtils = {
selectionStart = -1,
selectionEnd = -1,
} = {}) {
let urlbar = getUrlbarAbstraction(window);
await new Promise(resolve => waitForFocus(resolve, window));
let lastSearchString = urlbar.lastSearchString;
urlbar.focus();
urlbar.value = value;
let lastSearchString = window.gURLBar._lastSearchString;
window.gURLBar.inputField.focus();
window.gURLBar.value = value;
if (selectionStart >= 0 && selectionEnd >= 0) {
urlbar.selectionEnd = selectionEnd;
urlbar.selectionStart = selectionStart;
window.gURLBar.selectionEnd = selectionEnd;
window.gURLBar.selectionStart = selectionStart;
}
if (fireInputEvent) {
// This is necessary to get the urlbar to set gBrowser.userTypedValue.
urlbar.fireInputEvent();
this.fireInputEvent(window);
} else {
window.gURLBar.setAttribute("pageproxystate", "invalid");
}
// An input event will start a new search, with a couple of exceptions, so
// be careful not to call startSearch if we fired an input event since that
// be careful not to call _startSearch if we fired an input event since that
// would start two searches. The first exception is when the new search and
// old search are the same. Many tests do consecutive searches with the
// same string and expect new searches to start, so call startSearch
// same string and expect new searches to start, so call _startSearch
// directly then.
if (!fireInputEvent || value == lastSearchString) {
urlbar.startSearch(value, selectionStart, selectionEnd);
this._startSearch(window.gURLBar, value, selectionStart, selectionEnd);
}
return this.promiseSearchComplete(window);
},
@ -84,8 +80,12 @@ var UrlbarTestUtils = {
* @returns {HtmlElement|XulElement} the result's element.
*/
async waitForAutocompleteResultAt(win, index) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.promiseResultAt(index);
// TODO Bug 1530338: Quantum Bar doesn't yet implement lazy results replacement.
await this.promiseSearchComplete(win);
if (index >= win.gURLBar.view._rows.length) {
throw new Error("Not enough results");
}
return win.gURLBar.view._rows.children[index];
},
/**
@ -94,8 +94,7 @@ var UrlbarTestUtils = {
* @returns {object} The oneOffSearchButtons
*/
getOneOffSearchButtons(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.oneOffSearchButtons;
return win.gURLBar.view.oneOffSearchButtons;
},
/**
@ -104,291 +103,27 @@ var UrlbarTestUtils = {
* @returns {boolean} True if the buttons are visible.
*/
getOneOffSearchButtonsVisible(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.oneOffSearchButtonsVisible;
return this.getOneOffSearchButtons(win).style.display != "none";
},
_startSearch(urlbar, text, selectionStart = -1, selectionEnd = -1) {
urlbar.value = text;
if (selectionStart >= 0 && selectionEnd >= 0) {
urlbar.selectionEnd = selectionEnd;
urlbar.selectionStart = selectionStart;
}
urlbar.setAttribute("pageproxystate", "invalid");
urlbar.startQuery();
},
/**
* Gets an abstracted rapresentation of the result at an index.
* @see See the implementation of UrlbarAbstraction.getDetailsOfResultAt.
* Gets an abstracted representation of the result at an index.
* @param {object} win The window containing the urlbar
* @param {number} index The index to look for
* @returns {object} An object with numerous properties describing the result.
*/
async getDetailsOfResultAt(win, index) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.getDetailsOfResultAt(index);
},
/**
* Gets the currently selected element.
* @param {object} win The window containing the urlbar
* @returns {HtmlElement|XulElement} the selected element.
*/
getSelectedElement(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.getSelectedElement();
},
/**
* Gets the index of the currently selected item.
* @param {object} win The window containing the urlbar.
* @returns {number} The selected index.
*/
getSelectedIndex(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.getSelectedIndex();
},
/**
* Selects the item at the index specified.
* @param {object} win The window containing the urlbar.
* @param {index} index The index to select.
*/
setSelectedIndex(win, index) {
let urlbar = getUrlbarAbstraction(win);
urlbar.setSelectedIndex(index);
},
/**
* Gets the number of results.
* You must wait for the query to be complete before using this.
* @param {object} win The window containing the urlbar
* @returns {number} the number of results.
*/
getResultCount(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.getResultCount();
},
/**
* Returns the results panel object associated with the window.
* @note generally tests should use getDetailsOfResultAt rather than
* accessing panel elements directly.
* @param {object} win The window containing the urlbar
* @returns {object} the results panel object.
*/
getPanel(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.panel;
},
getDropMarker(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.dropMarker;
},
/**
* Ensures at least one search suggestion is present.
* @param {object} win The window containing the urlbar
* @returns {boolean} whether at least one search suggestion is present.
*/
promiseSuggestionsPresent(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.promiseSearchSuggestions();
},
/**
* Waits for the given number of connections to an http server.
* @param {object} httpserver an HTTP Server instance
* @param {number} count Number of connections to wait for
* @returns {Promise} resolved when all the expected connections were started.
*/
promiseSpeculativeConnections(httpserver, count) {
if (!httpserver) {
throw new Error("Must provide an http server");
}
return BrowserTestUtils.waitForCondition(
() => httpserver.connectionNumber == count,
"Waiting for speculative connection setup"
);
},
/**
* Waits for the popup to be hidden.
* @param {object} win The window containing the urlbar
* @param {function} openFn Function to be used to open the popup.
* @returns {Promise} resolved once the popup is closed
*/
promisePopupOpen(win, openFn) {
if (!openFn) {
throw new Error("openFn should be supplied to promisePopupOpen");
}
let urlbar = getUrlbarAbstraction(win);
return urlbar.promisePopupOpen(openFn);
},
/**
* Waits for the popup to be hidden.
* @param {object} win The window containing the urlbar
* @param {function} [closeFn] Function to be used to close the popup, if not
* supplied it will default to a closing the popup directly.
* @returns {Promise} resolved once the popup is closed
*/
promisePopupClose(win, closeFn = null) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.promisePopupClose(closeFn);
},
/**
* @param {object} win The browser window
* @returns {boolean} Whether the popup is open
*/
isPopupOpen(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.isPopupOpen();
},
/**
* Returns the userContextId (container id) for the last search.
* @param {object} win The browser window
* @returns {Promise} resolved when fetching is complete
* @resolves {number} a userContextId
*/
promiseUserContextId(win) {
let urlbar = getUrlbarAbstraction(win);
return urlbar.promiseUserContextId();
},
/**
* Dispatches an input event to the input field.
* @param {object} win The browser window
*/
fireInputEvent(win) {
getUrlbarAbstraction(win).fireInputEvent();
},
};
/**
* Maps windows to urlbar abstractions.
*/
var gUrlbarAbstractions = new WeakMap();
function getUrlbarAbstraction(win) {
if (!gUrlbarAbstractions.has(win)) {
gUrlbarAbstractions.set(win, new UrlbarAbstraction(win));
}
return gUrlbarAbstractions.get(win);
}
/**
* Abstracts the urlbar implementation, so it can be used regardless of
* Quantum Bar being enabled.
*/
class UrlbarAbstraction {
constructor(win) {
if (!win) {
throw new Error("Must provide a browser window");
}
this.urlbar = win.gURLBar;
this.window = win;
this.window.addEventListener(
"unload",
() => {
this.urlbar = null;
this.window = null;
},
{ once: true }
);
}
/**
* Focus the input field.
*/
focus() {
this.urlbar.inputField.focus();
}
/**
* Dispatches an input event to the input field.
*/
fireInputEvent() {
// Set event.data to the last character in the input, for a couple of
// reasons: It simulates the user typing, and it's necessary for autofill.
let event = new InputEvent("input", {
data: this.urlbar.value[this.urlbar.value.length - 1] || null,
});
this.urlbar.inputField.dispatchEvent(event);
}
set value(val) {
this.urlbar.value = val;
}
get value() {
return this.urlbar.value;
}
get lastSearchString() {
return this.urlbar._lastSearchString;
}
get panel() {
return this.urlbar.panel;
}
get dropMarker() {
return this.window.document.getAnonymousElementByAttribute(
this.urlbar.textbox,
"anonid",
"historydropmarker"
);
}
get oneOffSearchButtons() {
return this.urlbar.view.oneOffSearchButtons;
}
get oneOffSearchButtonsVisible() {
return this.oneOffSearchButtons.style.display != "none";
}
startSearch(text, selectionStart = -1, selectionEnd = -1) {
this.urlbar.value = text;
if (selectionStart >= 0 && selectionEnd >= 0) {
this.urlbar.selectionEnd = selectionEnd;
this.urlbar.selectionStart = selectionStart;
}
this.urlbar.setAttribute("pageproxystate", "invalid");
this.urlbar.startQuery();
}
promiseSearchComplete() {
return this.urlbar.lastQueryContextPromise;
}
async promiseUserContextId() {
const defaultId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
let context = await this.urlbar.lastQueryContextPromise;
return context.userContextId || defaultId;
}
async promiseResultAt(index) {
// TODO Bug 1530338: Quantum Bar doesn't yet implement lazy results replacement.
await this.promiseSearchComplete();
if (index >= this.urlbar.view._rows.length) {
throw new Error("Not enough results");
}
return this.urlbar.view._rows.children[index];
}
getSelectedElement() {
return this.urlbar.view._selected || null;
}
getSelectedIndex() {
return this.urlbar.view.selectedIndex;
}
setSelectedIndex(index) {
return (this.urlbar.view.selectedIndex = index);
}
getResultCount() {
return this.urlbar.view._rows.children.length;
}
async getDetailsOfResultAt(index) {
let element = await this.promiseResultAt(index);
let element = await this.waitForAutocompleteResultAt(win, index);
let details = {};
let result = element.result;
let { url, postData } = UrlbarUtils.getUrlFromResult(result);
@ -403,7 +138,7 @@ class UrlbarAbstraction {
let actions = element.getElementsByClassName("urlbarView-action");
let urls = element.getElementsByClassName("urlbarView-url");
let typeIcon = element.querySelector(".urlbarView-type-icon");
let typeIconStyle = this.window.getComputedStyle(typeIcon);
let typeIconStyle = win.getComputedStyle(typeIcon);
details.displayed = {
title: element.getElementsByClassName("urlbarView-title")[0].textContent,
action: actions.length > 0 ? actions[0].textContent : null,
@ -430,44 +165,162 @@ class UrlbarAbstraction {
details.keyword = result.payload.keyword;
}
return details;
}
},
async promiseSearchSuggestions() {
/**
* Gets the currently selected element.
* @param {object} win The window containing the urlbar
* @returns {HtmlElement|XulElement} the selected element.
*/
getSelectedElement(win) {
return win.gURLBar.view._selected || null;
},
/**
* Gets the index of the currently selected item.
* @param {object} win The window containing the urlbar.
* @returns {number} The selected index.
*/
getSelectedIndex(win) {
return win.gURLBar.view.selectedIndex;
},
/**
* Selects the item at the index specified.
* @param {object} win The window containing the urlbar.
* @param {index} index The index to select.
*/
setSelectedIndex(win, index) {
win.gURLBar.view.selectedIndex = index;
},
/**
* Gets the number of results.
* You must wait for the query to be complete before using this.
* @param {object} win The window containing the urlbar
* @returns {number} the number of results.
*/
getResultCount(win) {
return win.gURLBar.view._rows.children.length;
},
/**
* Returns the results panel object associated with the window.
* @note generally tests should use getDetailsOfResultAt rather than
* accessing panel elements directly.
* @param {object} win The window containing the urlbar
* @returns {object} the results panel object.
*/
getPanel(win) {
return win.gURLBar.panel;
},
getDropMarker(win) {
return win.document.getAnonymousElementByAttribute(
win.gURLBar.textbox,
"anonid",
"historydropmarker"
);
},
/**
* Ensures at least one search suggestion is present.
* @param {object} win The window containing the urlbar
* @returns {boolean} whether at least one search suggestion is present.
*/
promiseSuggestionsPresent(win) {
// TODO Bug 1530338: Quantum Bar doesn't yet implement lazy results replacement. When
// we do that, we'll have to be sure the suggestions we find are relevant
// for the current query. For now let's just wait for the search to be
// complete.
return this.promiseSearchComplete().then(context => {
return this.promiseSearchComplete(win).then(context => {
// Look for search suggestions.
if (
!context.results.some(
r => r.type == UrlbarUtils.RESULT_TYPE.SEARCH && r.payload.suggestion
)
) {
let hasSearchSuggestion = context.results.some(
r => r.type == UrlbarUtils.RESULT_TYPE.SEARCH && r.payload.suggestion
);
if (!hasSearchSuggestion) {
throw new Error("Cannot find a search suggestion");
}
});
}
},
async promisePopupOpen(openFn) {
/**
* Waits for the given number of connections to an http server.
* @param {object} httpserver an HTTP Server instance
* @param {number} count Number of connections to wait for
* @returns {Promise} resolved when all the expected connections were started.
*/
promiseSpeculativeConnections(httpserver, count) {
if (!httpserver) {
throw new Error("Must provide an http server");
}
return BrowserTestUtils.waitForCondition(
() => httpserver.connectionNumber == count,
"Waiting for speculative connection setup"
);
},
/**
* Waits for the popup to be hidden.
* @param {object} win The window containing the urlbar
* @param {function} openFn Function to be used to open the popup.
* @returns {Promise} resolved once the popup is closed
*/
async promisePopupOpen(win, openFn) {
if (!openFn) {
throw new Error("openFn should be supplied to promisePopupOpen");
}
await openFn();
return BrowserTestUtils.waitForPopupEvent(this.panel, "shown");
}
return BrowserTestUtils.waitForPopupEvent(this.getPanel(win), "shown");
},
closePopup() {
this.urlbar.view.close();
}
async promisePopupClose(closeFn) {
/**
* Waits for the popup to be hidden.
* @param {object} win The window containing the urlbar
* @param {function} [closeFn] Function to be used to close the popup, if not
* supplied it will default to a closing the popup directly.
* @returns {Promise} resolved once the popup is closed
*/
async promisePopupClose(win, closeFn = null) {
if (closeFn) {
await closeFn();
} else {
this.closePopup();
win.gURLBar.view.close();
}
return BrowserTestUtils.waitForPopupEvent(this.panel, "hidden");
}
return BrowserTestUtils.waitForPopupEvent(this.getPanel(win), "hidden");
},
isPopupOpen() {
return this.panel.state == "open" || this.panel.state == "showing";
}
}
/**
* @param {object} win The browser window
* @returns {boolean} Whether the popup is open
*/
isPopupOpen(win) {
let panel = this.getPanel(win);
return panel.state == "open" || panel.state == "showing";
},
/**
* Returns the userContextId (container id) for the last search.
* @param {object} win The browser window
* @returns {Promise} resolved when fetching is complete
* @resolves {number} a userContextId
*/
async promiseUserContextId(win) {
const defaultId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
let context = await win.gURLBar.lastQueryContextPromise;
return context.userContextId || defaultId;
},
/**
* Dispatches an input event to the input field.
* @param {object} win The browser window
*/
fireInputEvent(win) {
// Set event.data to the last character in the input, for a couple of
// reasons: It simulates the user typing, and it's necessary for autofill.
let event = new InputEvent("input", {
data: win.gURLBar.value[win.gURLBar.value.length - 1] || null,
});
win.gURLBar.inputField.dispatchEvent(event);
},
};

View File

@ -9,6 +9,7 @@
[localization] @AB_CD@.jar:
browser/aboutLogins.ftl (../components/aboutlogins/content/aboutLogins.ftl)
toolkit/certviewer.ftl (../../toolkit/components/certviewer/content/certviewer.ftl)
browser (%browser/**/*.ftl)
@AB_CD@.jar:

View File

@ -49,6 +49,13 @@ void Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
MOZ_DIAGNOSTIC_ASSERT(mWindow);
mSubmitTime = aBaseTime;
mSubmitTime = aBaseTime;
#ifdef MOZ_GECKO_PROFILER
if (profiler_is_active()) {
mCause = profiler_get_backtrace();
}
#endif
// If we are frozen simply set mTimeRemaining to be the "time remaining" in
// the timeout (i.e., the interval itself). This will be used to create a
// new mWhen time when the window is thawed. The end effect is that time does

View File

@ -13,6 +13,7 @@
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "GeckoProfiler.h"
class nsIEventTarget;
class nsIPrincipal;
@ -50,6 +51,10 @@ class Timeout final : public LinkedListElement<RefPtr<Timeout>> {
// Can only be called when frozen.
const TimeDuration& TimeRemaining() const;
#ifdef MOZ_GECKO_PROFILER
UniqueProfilerBacktrace TakeProfilerBacktrace() { return std::move(mCause); }
#endif
private:
// mWhen and mTimeRemaining can't be in a union, sadly, because they
// have constructors.
@ -82,6 +87,10 @@ class Timeout final : public LinkedListElement<RefPtr<Timeout>> {
// Interval
TimeDuration mInterval;
#ifdef MOZ_GECKO_PROFILER
UniqueProfilerBacktrace mCause;
#endif
// Returned as value of setTimeout()
uint32_t mTimeoutId;

View File

@ -29,6 +29,11 @@ void TimeoutHandler::GetLocation(const char** aFileName, uint32_t* aLineNo,
*aColumn = mColumn;
}
void TimeoutHandler::GetDescription(nsACString& aOutString) {
aOutString.AppendPrintf("<generic handler> (%s:%d:%d)", mFileName.get(),
mLineNo, mColumn);
}
NS_IMPL_CYCLE_COLLECTION_0(TimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeoutHandler)
@ -84,6 +89,19 @@ NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)
NS_IMPL_ADDREF_INHERITED(ScriptTimeoutHandler, TimeoutHandler)
NS_IMPL_RELEASE_INHERITED(ScriptTimeoutHandler, TimeoutHandler)
void ScriptTimeoutHandler::GetDescription(nsACString& aOutString) {
if (mExpr.Length() > 15) {
aOutString.AppendPrintf(
"<string handler (truncated): \"%s...\"> (%s:%d:%d)",
NS_ConvertUTF16toUTF8(Substring(mExpr, 0, 13)).get(), mFileName.get(),
mLineNo, mColumn);
} else {
aOutString.AppendPrintf("<string handler: \"%s\"> (%s:%d:%d)",
NS_ConvertUTF16toUTF8(mExpr).get(), mFileName.get(),
mLineNo, mColumn);
}
}
//-----------------------------------------------------------------------------
// CallbackTimeoutHandler
//-----------------------------------------------------------------------------
@ -167,5 +185,9 @@ bool CallbackTimeoutHandler::Call(const char* aExecutionReason) {
void CallbackTimeoutHandler::MarkForCC() { mFunction->MarkForCC(); }
void CallbackTimeoutHandler::GetDescription(nsACString& aOutString) {
mFunction->GetDescription(aOutString);
}
} // namespace dom
} // namespace mozilla

View File

@ -34,6 +34,12 @@ class TimeoutHandler : public nsISupports {
// nsITimeoutHandler and should not be freed by the caller.
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
uint32_t* aColumn);
// Append a UTF-8 string to aOutString that describes the callback function,
// for use in logging or profiler markers.
// The string contains the function name and its source location, if
// available, in the following format:
// "<functionName> (<sourceURL>:<lineNumber>:<columnNumber>)"
virtual void GetDescription(nsACString& aOutString);
virtual void MarkForCC() {}
protected:
@ -65,6 +71,7 @@ class ScriptTimeoutHandler : public TimeoutHandler {
MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* /* unused */) override {
return false;
};
virtual void GetDescription(nsACString& aOutString) override;
protected:
virtual ~ScriptTimeoutHandler() {}
@ -87,6 +94,7 @@ class CallbackTimeoutHandler final : public TimeoutHandler {
MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* aExecutionReason) override;
virtual void MarkForCC() override;
virtual void GetDescription(nsACString& aOutString) override;
void ReleaseJSObjects();

View File

@ -5854,6 +5854,21 @@ int32_t nsGlobalWindowInner::SetTimeoutOrInterval(JSContext* aCx,
return result;
}
static const char* GetTimeoutReasonString(Timeout* aTimeout) {
switch (aTimeout->mReason) {
case Timeout::Reason::eTimeoutOrInterval:
if (aTimeout->mIsInterval) {
return "setInterval handler";
}
return "setTimeout handler";
case Timeout::Reason::eIdleCallbackTimeout:
return "setIdleCallback handler (timed out)";
default:
MOZ_CRASH("Unexpected enum value");
return "";
}
}
bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
nsIScriptContext* aScx) {
// Hold on to the timeout in case mExpr or mFunObj releases its
@ -5881,12 +5896,25 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
TimeoutManager::SetNestingLevel(timeout->mNestingLevel);
}
const char* reason;
if (timeout->mIsInterval) {
reason = "setInterval handler";
} else {
reason = "setTimeout handler";
const char* reason = GetTimeoutReasonString(timeout);
#ifdef MOZ_GECKO_PROFILER
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
nsCString str;
if (profiler_is_active()) {
TimeDuration originalInterval = timeout->When() - timeout->SubmitTime();
str.Append(reason);
str.Append(" with interval ");
str.AppendInt(int(originalInterval.ToMilliseconds()));
str.Append("ms: ");
nsCString handlerDescription;
timeout->mScriptHandler->GetDescription(handlerDescription);
str.Append(handlerDescription);
}
AUTO_PROFILER_TEXT_MARKER_DOCSHELL_CAUSE("setTimeout callback", str, JS,
docShell,
timeout->TakeProfilerBacktrace());
#endif
bool abortIntervalHandler;
{

View File

@ -131,6 +131,64 @@ JSObject* CallbackObject::Callback(JSContext* aCx) {
return callback;
}
void CallbackObject::GetDescription(nsACString& aOutString) {
JSObject* wrappedCallback = CallbackOrNull();
if (!wrappedCallback) {
aOutString.Append("<callback from a nuked compartment>");
return;
}
JS::Rooted<JSObject*> unwrappedCallback(
RootingCx(), js::CheckedUnwrapStatic(wrappedCallback));
if (!unwrappedCallback) {
aOutString.Append("<not a function>");
return;
}
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
JS::RootedObject rootedCallback(cx, unwrappedCallback);
JSAutoRealm ar(cx, rootedCallback);
JS::Rooted<JSFunction*> rootedFunction(cx,
JS_GetObjectFunction(rootedCallback));
if (!rootedFunction) {
aOutString.Append("<not a function>");
return;
}
JS::Rooted<JSString*> displayId(cx, JS_GetFunctionDisplayId(rootedFunction));
if (displayId) {
nsAutoJSString funcNameStr;
if (funcNameStr.init(cx, displayId)) {
if (funcNameStr.IsEmpty()) {
aOutString.Append("<empty name>");
} else {
AppendUTF16toUTF8(funcNameStr, aOutString);
}
} else {
aOutString.Append("<function name string failed to materialize>");
jsapi.ClearException();
}
} else {
aOutString.Append("<anonymous>");
}
JS::Rooted<JSScript*> rootedScript(cx,
JS_GetFunctionScript(cx, rootedFunction));
if (!rootedScript) {
return;
}
aOutString.Append(" (");
aOutString.Append(JS_GetScriptFilename(rootedScript));
aOutString.Append(":");
aOutString.AppendInt(JS_GetScriptBaseLineNumber(cx, rootedScript));
aOutString.Append(")");
}
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
ErrorResult& aRv,
const char* aExecutionReason,

View File

@ -162,6 +162,13 @@ class CallbackObject : public nsISupports {
eRethrowExceptions
};
// Append a UTF-8 string to aOutString that describes the callback function,
// for use in logging or profiler markers.
// The string contains the function name and its source location, if
// available, in the following format:
// "<functionName> (<sourceURL>:<lineNumber>)"
void GetDescription(nsACString& aOutString);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this);
}

View File

@ -411,7 +411,8 @@ APZCTreeManager::UpdateHitTestingTreeImpl(const ScrollNode& aRoot,
HitTestingTreeNode* parent = nullptr;
HitTestingTreeNode* next = nullptr;
LayersId layersId = mRootLayersId;
wr::RenderRoot renderRoot = wr::RenderRoot::Default;
std::stack<wr::RenderRoot> renderRoots;
renderRoots.push(wr::RenderRoot::Default);
ancestorTransforms.push(AncestorTransform());
state.mParentHasPerspective.push(false);
@ -441,7 +442,7 @@ APZCTreeManager::UpdateHitTestingTreeImpl(const ScrollNode& aRoot,
HitTestingTreeNode* node = PrepareNodeForLayer(
lock, aLayerMetrics, aLayerMetrics.Metrics(), layersId,
ancestorTransforms.top(), parent, next, state, renderRoot);
ancestorTransforms.top(), parent, next, state, renderRoots.top());
MOZ_ASSERT(node);
AsyncPanZoomController* apzc = node->GetApzc();
aLayerMetrics.SetApzc(apzc);
@ -490,7 +491,7 @@ APZCTreeManager::UpdateHitTestingTreeImpl(const ScrollNode& aRoot,
}
if (Maybe<wr::RenderRoot> newRenderRoot =
aLayerMetrics.GetReferentRenderRoot()) {
renderRoot = *newRenderRoot;
renderRoots.push(*newRenderRoot);
}
indents.push(gfx::TreeAutoIndent<LOG_DEFAULT>(mApzcTreeLog));
@ -508,6 +509,9 @@ APZCTreeManager::UpdateHitTestingTreeImpl(const ScrollNode& aRoot,
ancestorTransforms.pop();
indents.pop();
state.mParentHasPerspective.pop();
if (aLayerMetrics.GetReferentRenderRoot()) {
renderRoots.pop();
}
});
mApzcTreeLog << "[end]\n";

View File

@ -68,7 +68,7 @@ static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub,
ReceiverGuard* receiver) {
// We match:
//
// GuardIsObject 0
// GuardToObject 0
// GuardShape 0
// LoadFixedSlotResult 0 or LoadDynamicSlotResult 0
@ -76,7 +76,7 @@ static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub,
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return false;
}
@ -94,7 +94,7 @@ static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub,
ReceiverGuard* receiver) {
// We match:
//
// GuardIsObject 0
// GuardToObject 0
// GuardGroup 0
// GuardShape 0
// StoreFixedSlot 0 or StoreDynamicSlot 0
@ -102,7 +102,7 @@ static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub,
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return false;
}
@ -241,10 +241,10 @@ bool BaselineInspector::dimorphicStub(jsbytecode* pc, ICStub** pfirst,
static void SkipBinaryGuards(CacheIRReader& reader) {
while (true) {
// Two skip opcodes
if (reader.matchOp(CacheOp::GuardIsInt32) ||
if (reader.matchOp(CacheOp::GuardToInt32) ||
reader.matchOp(CacheOp::GuardType) ||
reader.matchOp(CacheOp::TruncateDoubleToUInt32) ||
reader.matchOp(CacheOp::GuardIsBoolean)) {
reader.matchOp(CacheOp::GuardToBoolean)) {
reader.skip(); // Skip over operandId
reader.skip(); // Skip over result/type.
continue;
@ -252,8 +252,8 @@ static void SkipBinaryGuards(CacheIRReader& reader) {
// One skip
if (reader.matchOp(CacheOp::GuardIsNumber) ||
reader.matchOp(CacheOp::GuardIsString) ||
reader.matchOp(CacheOp::GuardIsObject)) {
reader.matchOp(CacheOp::GuardToString) ||
reader.matchOp(CacheOp::GuardToObject)) {
reader.skip(); // Skip over operandId
continue;
}
@ -357,13 +357,13 @@ static bool GuardType(CacheIRReader& reader,
switch (op) {
// 0 Skip cases
case CacheOp::GuardIsString:
case CacheOp::GuardToString:
guardType[guardOperand] = MIRType::String;
break;
case CacheOp::GuardIsSymbol:
case CacheOp::GuardToSymbol:
guardType[guardOperand] = MIRType::Symbol;
break;
case CacheOp::GuardIsBigInt:
case CacheOp::GuardToBigInt:
guardType[guardOperand] = MIRType::BigInt;
break;
case CacheOp::GuardIsNumber:
@ -373,12 +373,12 @@ static bool GuardType(CacheIRReader& reader,
guardType[guardOperand] = MIRType::Undefined;
break;
// 1 skip
case CacheOp::GuardIsInt32:
case CacheOp::GuardToInt32:
guardType[guardOperand] = MIRType::Int32;
// Skip over result
reader.skip();
break;
case CacheOp::GuardIsBoolean:
case CacheOp::GuardToBoolean:
guardType[guardOperand] = MIRType::Boolean;
// Skip over result
reader.skip();
@ -948,7 +948,7 @@ static bool GuardSpecificAtomOrSymbol(CacheIRReader& reader, ICStub* stub,
ValOperandId keyId, jsid id) {
// Try to match an id guard emitted by IRGenerator::emitIdGuard.
if (JSID_IS_ATOM(id)) {
if (!reader.matchOp(CacheOp::GuardIsString, keyId)) {
if (!reader.matchOp(CacheOp::GuardToString, keyId)) {
return false;
}
if (!reader.matchOp(CacheOp::GuardSpecificAtom, keyId)) {
@ -961,7 +961,7 @@ static bool GuardSpecificAtomOrSymbol(CacheIRReader& reader, ICStub* stub,
}
} else {
MOZ_ASSERT(JSID_IS_SYMBOL(id));
if (!reader.matchOp(CacheOp::GuardIsSymbol, keyId)) {
if (!reader.matchOp(CacheOp::GuardToSymbol, keyId)) {
return false;
}
if (!reader.matchOp(CacheOp::GuardSpecificSymbol, keyId)) {
@ -984,7 +984,7 @@ static bool AddCacheIRGetPropFunction(
JSScript* script) {
// We match either an own getter:
//
// GuardIsObject objId
// GuardToObject objId
// [..Id Guard..]
// [..WindowProxy innerization..]
// <GuardReceiver objId>
@ -992,7 +992,7 @@ static bool AddCacheIRGetPropFunction(
//
// Or a getter on the prototype:
//
// GuardIsObject objId
// GuardToObject objId
// [..Id Guard..]
// [..WindowProxy innerization..]
// <GuardReceiver objId>
@ -1016,7 +1016,7 @@ static bool AddCacheIRGetPropFunction(
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape,
commonGetter, globalShape, isOwnProperty,
receivers, script);
@ -1179,7 +1179,7 @@ static JSFunction* GetMegamorphicGetterSetterFunction(
ICStub* stub, const CacheIRStubInfo* stubInfo, jsid id, bool isGetter) {
// We match:
//
// GuardIsObject objId
// GuardToObject objId
// [..Id Guard..]
// GuardHasGetterSetter objId propShape
//
@ -1192,7 +1192,7 @@ static JSFunction* GetMegamorphicGetterSetterFunction(
CacheIRReader reader(stubInfo);
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return nullptr;
}
@ -1276,13 +1276,13 @@ static bool AddCacheIRSetPropFunction(
BaselineInspector::ReceiverVector& receivers) {
// We match either an own setter:
//
// GuardIsObject objId
// GuardToObject objId
// <GuardReceiver objId>
// Call(Scripted|Native)Setter objId
//
// Or a setter on the prototype:
//
// GuardIsObject objId
// GuardToObject objId
// <GuardReceiver objId>
// LoadObject holderId
// GuardShape holderId
@ -1291,7 +1291,7 @@ static bool AddCacheIRSetPropFunction(
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return false;
}
@ -1411,7 +1411,7 @@ static bool GetCacheIRReceiverForProtoReadSlot(ICCacheIR_Monitored* stub,
JSObject** holderResult) {
// We match:
//
// GuardIsObject 0
// GuardToObject 0
// <ReceiverGuard>
// 1: LoadObject holder
// GuardShape 1
@ -1421,7 +1421,7 @@ static bool GetCacheIRReceiverForProtoReadSlot(ICCacheIR_Monitored* stub,
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
if (!reader.matchOp(CacheOp::GuardToObject, objId)) {
return false;
}
@ -1512,10 +1512,10 @@ bool BaselineInspector::maybeInfoForProtoReadSlot(jsbytecode* pc,
static MIRType GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub) {
CacheIRReader reader(stub->stubInfo());
if (reader.matchOp(CacheOp::GuardIsObject, ValOperandId(0))) {
if (reader.matchOp(CacheOp::GuardToObject, ValOperandId(0))) {
return MIRType::Object;
}
if (reader.matchOp(CacheOp::GuardIsString, ValOperandId(0))) {
if (reader.matchOp(CacheOp::GuardToString, ValOperandId(0))) {
return MIRType::String;
}
if (reader.matchOp(CacheOp::GuardIsNumber, ValOperandId(0))) {
@ -1583,7 +1583,7 @@ bool BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape,
ObjOperandId rhsId = ObjOperandId(1);
ObjOperandId resId = ObjOperandId(2);
if (!reader.matchOp(CacheOp::GuardIsObject, rhsId)) {
if (!reader.matchOp(CacheOp::GuardToObject, rhsId)) {
return false;
}

View File

@ -260,7 +260,7 @@ AttachDecision GetPropIRGenerator::tryAttachStub() {
if (val_.isObject()) {
RootedObject obj(cx_, &val_.toObject());
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
if (nameOrSymbol) {
TRY_ATTACH(tryAttachObjectLength(obj, objId, id));
TRY_ATTACH(tryAttachNative(obj, objId, id));
@ -332,7 +332,7 @@ AttachDecision GetPropIRGenerator::tryAttachIdempotentStub() {
RootedId id(cx_, NameToId(idVal_.toString()->asAtom().asPropertyName()));
ValOperandId valId(writer.setInputOperandId(0));
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
TRY_ATTACH(tryAttachNative(obj, objId, id));
@ -1066,7 +1066,7 @@ AttachDecision GetPropIRGenerator::tryAttachNative(HandleObject obj,
// object
MOZ_ASSERT(!idempotent());
ObjOperandId receiverId =
isSuper() ? writer.guardIsObject(getSuperReceiverValueId()) : objId;
isSuper() ? writer.guardToObject(getSuperReceiverValueId()) : objId;
maybeEmitIdGuard(id);
EmitCallGetterResult(writer, obj, holder, shape, objId, receiverId,
mode_);
@ -1445,7 +1445,7 @@ ObjOperandId IRGenerator::guardDOMProxyExpandoObjectAndShape(
}
// Guard the expando is an object and shape guard.
ObjOperandId expandoObjId = writer.guardIsObject(expandoValId);
ObjOperandId expandoObjId = writer.guardToObject(expandoValId);
TestMatchingHolder(writer, expandoObj, expandoObjId);
return expandoObjId;
}
@ -1950,7 +1950,7 @@ AttachDecision GetPropIRGenerator::tryAttachStringLength(ValOperandId valId,
return AttachDecision::NoAction;
}
StringOperandId strId = writer.guardIsString(valId);
StringOperandId strId = writer.guardToString(valId);
maybeEmitIdGuard(id);
writer.loadStringLengthResult(strId);
writer.returnFromIC();
@ -1995,8 +1995,8 @@ AttachDecision GetPropIRGenerator::tryAttachStringChar(ValOperandId valId,
return AttachDecision::NoAction;
}
StringOperandId strId = writer.guardIsString(valId);
Int32OperandId int32IndexId = writer.guardIsInt32Index(indexId);
StringOperandId strId = writer.guardToString(valId);
Int32OperandId int32IndexId = writer.guardToInt32Index(indexId);
writer.loadStringCharResult(strId, int32IndexId);
writer.returnFromIC();
@ -2043,7 +2043,7 @@ AttachDecision GetPropIRGenerator::tryAttachMagicArgument(
writer.guardMagicValue(valId, JS_OPTIMIZED_ARGUMENTS);
writer.guardFrameHasNoArgumentsObject();
Int32OperandId int32IndexId = writer.guardIsInt32Index(indexId);
Int32OperandId int32IndexId = writer.guardToInt32Index(indexId);
writer.loadFrameArgumentResult(int32IndexId);
writer.typeMonitorResult();
@ -2360,11 +2360,11 @@ void GetPropIRGenerator::trackAttached(const char* name) {
void IRGenerator::emitIdGuard(ValOperandId valId, jsid id) {
if (JSID_IS_SYMBOL(id)) {
SymbolOperandId symId = writer.guardIsSymbol(valId);
SymbolOperandId symId = writer.guardToSymbol(valId);
writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
} else {
MOZ_ASSERT(JSID_IS_ATOM(id));
StringOperandId strId = writer.guardIsString(valId);
StringOperandId strId = writer.guardToString(valId);
writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
}
}
@ -3094,7 +3094,7 @@ AttachDecision HasPropIRGenerator::tryAttachStub() {
return AttachDecision::NoAction;
}
RootedObject obj(cx_, &val_.toObject());
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
// Optimize Proxies
TRY_ATTACH(tryAttachProxyElement(obj, objId, keyId));
@ -3158,7 +3158,7 @@ bool IRGenerator::maybeGuardInt32Index(const Value& index, ValOperandId indexId,
}
*int32Index = uint32_t(indexSigned);
*int32IndexId = writer.guardIsInt32Index(indexId);
*int32IndexId = writer.guardToInt32Index(indexId);
return true;
}
@ -3168,7 +3168,7 @@ bool IRGenerator::maybeGuardInt32Index(const Value& index, ValOperandId indexId,
return false;
}
StringOperandId strId = writer.guardIsString(indexId);
StringOperandId strId = writer.guardToString(indexId);
*int32Index = uint32_t(indexSigned);
*int32IndexId = writer.guardAndGetIndexFromString(strId);
return true;
@ -3216,7 +3216,7 @@ AttachDecision SetPropIRGenerator::tryAttachStub() {
if (lhsVal_.isObject()) {
RootedObject obj(cx_, &lhsVal_.toObject());
ObjOperandId objId = writer.guardIsObject(objValId);
ObjOperandId objId = writer.guardToObject(objValId);
if (IsPropertySetOp(JSOp(*pc_))) {
TRY_ATTACH(tryAttachMegamorphicSetElement(obj, objId, rhsValId));
}
@ -4329,7 +4329,7 @@ AttachDecision SetPropIRGenerator::tryAttachAddSlotStub(
return AttachDecision::NoAction;
}
ObjOperandId objId = writer.guardIsObject(objValId);
ObjOperandId objId = writer.guardToObject(objValId);
maybeEmitIdGuard(id);
// In addition to guarding for type barrier, we need this group guard (or
@ -4457,7 +4457,7 @@ AttachDecision InstanceOfIRGenerator::tryAttachStub() {
ValOperandId lhs(writer.setInputOperandId(0));
ValOperandId rhs(writer.setInputOperandId(1));
ObjOperandId rhsId = writer.guardIsObject(rhs);
ObjOperandId rhsId = writer.guardToObject(rhs);
writer.guardShape(rhsId, fun->lastProperty());
// Load prototypeObject into the cache -- consumed twice in the IC
@ -4531,7 +4531,7 @@ AttachDecision TypeOfIRGenerator::tryAttachObject(ValOperandId valId) {
return AttachDecision::NoAction;
}
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
writer.loadTypeOfObjectResult(objId);
writer.returnFromIC();
trackAttached("Object");
@ -4561,7 +4561,7 @@ AttachDecision GetIteratorIRGenerator::tryAttachStub() {
RootedObject obj(cx_, &val_.toObject());
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
TRY_ATTACH(tryAttachNativeIterator(objId, obj));
trackAttached(IRGenerator::NotAttached);
@ -4669,13 +4669,13 @@ AttachDecision CallIRGenerator::tryAttachArrayPush() {
// Guard callee is the |js::array_push| native function.
ValOperandId calleeValId =
writer.loadArgumentFixedSlot(ArgumentKind::Callee, argc_);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
writer.guardSpecificNativeFunction(calleeObjId, js::array_push);
// Guard this is an array object.
ValOperandId thisValId =
writer.loadArgumentFixedSlot(ArgumentKind::This, argc_);
ObjOperandId thisObjId = writer.guardIsObject(thisValId);
ObjOperandId thisObjId = writer.guardToObject(thisValId);
// This is a soft assert, documenting the fact that we pass 'true'
// for needsTypeBarrier when constructing typeCheckInfo_ for CallIRGenerator.
@ -4749,20 +4749,20 @@ AttachDecision CallIRGenerator::tryAttachArrayJoin() {
// Guard callee is the |js::array_join| native function.
ValOperandId calleeValId =
writer.loadArgumentFixedSlot(ArgumentKind::Callee, argc_);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
writer.guardSpecificNativeFunction(calleeObjId, js::array_join);
if (argc_ == 1) {
// If argcount is 1, guard that the argument is a string.
ValOperandId argValId =
writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_);
writer.guardIsString(argValId);
writer.guardToString(argValId);
}
// Guard this is an array object.
ValOperandId thisValId =
writer.loadArgumentFixedSlot(ArgumentKind::This, argc_);
ObjOperandId thisObjId = writer.guardIsObject(thisValId);
ObjOperandId thisObjId = writer.guardToObject(thisValId);
writer.guardClass(thisObjId, GuardClassKind::Array);
// Do the join.
@ -4829,13 +4829,13 @@ AttachDecision CallIRGenerator::tryAttachFunCall() {
// Guard that callee is the |fun_call| native function.
ValOperandId calleeValId =
writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
writer.guardSpecificNativeFunction(calleeObjId, fun_call);
// Guard that |this| is a function.
ValOperandId thisValId =
writer.loadArgumentDynamicSlot(ArgumentKind::This, argcId);
ObjOperandId thisObjId = writer.guardIsObject(thisValId);
ObjOperandId thisObjId = writer.guardToObject(thisValId);
writer.guardClass(thisObjId, GuardClassKind::JSFunction);
// Guard that function is not a class constructor.
@ -4895,13 +4895,13 @@ AttachDecision CallIRGenerator::tryAttachFunApply() {
// Guard that callee is the |fun_apply| native function.
ValOperandId calleeValId =
writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
writer.guardSpecificNativeFunction(calleeObjId, fun_apply);
// Guard that |this| is a function.
ValOperandId thisValId =
writer.loadArgumentDynamicSlot(ArgumentKind::This, argcId);
ObjOperandId thisObjId = writer.guardIsObject(thisValId);
ObjOperandId thisObjId = writer.guardToObject(thisValId);
writer.guardClass(thisObjId, GuardClassKind::JSFunction);
// Guard that function is not a class constructor.
@ -5085,7 +5085,7 @@ AttachDecision CallIRGenerator::tryAttachCallScripted(
// Load the callee and ensure it is an object
ValOperandId calleeValId =
writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId, flags);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
FieldOffset calleeOffset = 0;
if (isSpecialized) {
@ -5254,7 +5254,7 @@ AttachDecision CallIRGenerator::tryAttachCallNative(HandleFunction calleeFunc) {
// Load the callee and ensure it is an object
ValOperandId calleeValId =
writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId, flags);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
FieldOffset calleeOffset = 0;
if (isSpecialized) {
@ -5355,7 +5355,7 @@ AttachDecision CallIRGenerator::tryAttachCallHook(HandleObject calleeObj) {
// Load the callee and ensure it is an object
ValOperandId calleeValId =
writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId, flags);
ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
ObjOperandId calleeObjId = writer.guardToObject(calleeValId);
// Ensure the callee's class matches the one in this stub.
FieldOffset classOffset =
@ -5498,8 +5498,8 @@ AttachDecision CompareIRGenerator::tryAttachString(ValOperandId lhsId,
return AttachDecision::NoAction;
}
StringOperandId lhsStrId = writer.guardIsString(lhsId);
StringOperandId rhsStrId = writer.guardIsString(rhsId);
StringOperandId lhsStrId = writer.guardToString(lhsId);
StringOperandId rhsStrId = writer.guardToString(rhsId);
writer.compareStringResult(op_, lhsStrId, rhsStrId);
writer.returnFromIC();
@ -5515,8 +5515,8 @@ AttachDecision CompareIRGenerator::tryAttachObject(ValOperandId lhsId,
return AttachDecision::NoAction;
}
ObjOperandId lhsObjId = writer.guardIsObject(lhsId);
ObjOperandId rhsObjId = writer.guardIsObject(rhsId);
ObjOperandId lhsObjId = writer.guardToObject(lhsId);
ObjOperandId rhsObjId = writer.guardToObject(rhsId);
writer.compareObjectResult(op_, lhsObjId, rhsObjId);
writer.returnFromIC();
@ -5532,8 +5532,8 @@ AttachDecision CompareIRGenerator::tryAttachSymbol(ValOperandId lhsId,
return AttachDecision::NoAction;
}
SymbolOperandId lhsSymId = writer.guardIsSymbol(lhsId);
SymbolOperandId rhsSymId = writer.guardIsSymbol(rhsId);
SymbolOperandId lhsSymId = writer.guardToSymbol(lhsId);
SymbolOperandId rhsSymId = writer.guardToSymbol(rhsId);
writer.compareSymbolResult(op_, lhsSymId, rhsSymId);
writer.returnFromIC();
@ -5576,10 +5576,10 @@ AttachDecision CompareIRGenerator::tryAttachInt32(ValOperandId lhsId,
return AttachDecision::NoAction;
}
Int32OperandId lhsIntId = lhsVal_.isBoolean() ? writer.guardIsBoolean(lhsId)
: writer.guardIsInt32(lhsId);
Int32OperandId rhsIntId = rhsVal_.isBoolean() ? writer.guardIsBoolean(rhsId)
: writer.guardIsInt32(rhsId);
Int32OperandId lhsIntId = lhsVal_.isBoolean() ? writer.guardToBoolean(lhsId)
: writer.guardToInt32(lhsId);
Int32OperandId rhsIntId = rhsVal_.isBoolean() ? writer.guardToBoolean(rhsId)
: writer.guardToInt32(rhsId);
// Strictly different types should have been handed by
// tryAttachStrictDifferentTypes
@ -5622,7 +5622,7 @@ AttachDecision CompareIRGenerator::tryAttachObjectUndefined(
ValOperandId undefOrNull = rhsVal_.isObject() ? lhsId : rhsId;
writer.guardIsNullOrUndefined(undefOrNull);
ObjOperandId objOperand = writer.guardIsObject(obj);
ObjOperandId objOperand = writer.guardToObject(obj);
writer.compareObjectUndefinedNullResult(op_, objOperand);
writer.returnFromIC();
@ -5676,16 +5676,16 @@ AttachDecision CompareIRGenerator::tryAttachPrimitiveUndefined(
}
switch (v.extractNonDoubleType()) {
case JSVAL_TYPE_BOOLEAN:
writer.guardIsBoolean(id);
writer.guardToBoolean(id);
return;
case JSVAL_TYPE_SYMBOL:
writer.guardIsSymbol(id);
writer.guardToSymbol(id);
return;
case JSVAL_TYPE_BIGINT:
writer.guardIsBigInt(id);
writer.guardToBigInt(id);
return;
case JSVAL_TYPE_STRING:
writer.guardIsString(id);
writer.guardToString(id);
return;
default:
MOZ_CRASH("unexpected type");
@ -5750,7 +5750,7 @@ AttachDecision CompareIRGenerator::tryAttachStringNumber(ValOperandId lhsId,
auto createGuards = [&](HandleValue v, ValOperandId vId) {
if (v.isString()) {
StringOperandId strId = writer.guardIsString(vId);
StringOperandId strId = writer.guardToString(vId);
return writer.guardAndGetNumberFromString(strId);
}
MOZ_ASSERT(v.isNumber());
@ -5906,7 +5906,7 @@ AttachDecision ToBoolIRGenerator::tryAttachString() {
}
ValOperandId valId(writer.setInputOperandId(0));
StringOperandId strId = writer.guardIsString(valId);
StringOperandId strId = writer.guardToString(valId);
writer.loadStringTruthyResult(strId);
writer.returnFromIC();
trackAttached("ToBoolString");
@ -5932,7 +5932,7 @@ AttachDecision ToBoolIRGenerator::tryAttachObject() {
}
ValOperandId valId(writer.setInputOperandId(0));
ObjOperandId objId = writer.guardIsObject(valId);
ObjOperandId objId = writer.guardToObject(valId);
writer.loadObjectTruthyResult(objId);
writer.returnFromIC();
trackAttached("ToBoolObject");
@ -5996,7 +5996,7 @@ AttachDecision UnaryArithIRGenerator::tryAttachInt32() {
ValOperandId valId(writer.setInputOperandId(0));
Int32OperandId intId = writer.guardIsInt32(valId);
Int32OperandId intId = writer.guardToInt32(valId);
switch (op_) {
case JSOP_BITNOT:
writer.int32NotResult(intId);
@ -6125,10 +6125,10 @@ AttachDecision BinaryArithIRGenerator::tryAttachBitwise() {
// Convert type into int32 for the bitwise/shift operands.
auto guardToInt32 = [&](ValOperandId id, HandleValue val) {
if (val.isInt32()) {
return writer.guardIsInt32(id);
return writer.guardToInt32(id);
}
if (val.isBoolean()) {
return writer.guardIsBoolean(id);
return writer.guardToBoolean(id);
}
MOZ_ASSERT(val.isDouble());
writer.guardType(id, ValueType::Double);
@ -6240,10 +6240,10 @@ AttachDecision BinaryArithIRGenerator::tryAttachInt32() {
auto guardToInt32 = [&](ValOperandId id, HandleValue v) {
if (v.isInt32()) {
return writer.guardIsInt32(id);
return writer.guardToInt32(id);
}
MOZ_ASSERT(v.isBoolean());
return writer.guardIsBoolean(id);
return writer.guardToBoolean(id);
};
Int32OperandId lhsIntId = guardToInt32(lhsId, lhs_);
@ -6294,10 +6294,10 @@ AttachDecision BinaryArithIRGenerator::tryAttachStringNumberConcat() {
auto guardToString = [&](ValOperandId id, HandleValue v) {
if (v.isString()) {
return writer.guardIsString(id);
return writer.guardToString(id);
}
if (v.isInt32()) {
Int32OperandId intId = writer.guardIsInt32(id);
Int32OperandId intId = writer.guardToInt32(id);
return writer.callInt32ToString(intId);
}
// At this point we are creating an IC that will handle
@ -6333,10 +6333,10 @@ AttachDecision BinaryArithIRGenerator::tryAttachStringBooleanConcat() {
auto guardToString = [&](ValOperandId id, HandleValue v) {
if (v.isString()) {
return writer.guardIsString(id);
return writer.guardToString(id);
}
MOZ_ASSERT(v.isBoolean());
Int32OperandId intId = writer.guardIsBoolean(id);
Int32OperandId intId = writer.guardToBoolean(id);
return writer.booleanToString(intId);
};
@ -6364,8 +6364,8 @@ AttachDecision BinaryArithIRGenerator::tryAttachStringConcat() {
ValOperandId lhsId(writer.setInputOperandId(0));
ValOperandId rhsId(writer.setInputOperandId(1));
StringOperandId lhsStrId = writer.guardIsString(lhsId);
StringOperandId rhsStrId = writer.guardIsString(rhsId);
StringOperandId lhsStrId = writer.guardToString(lhsId);
StringOperandId rhsStrId = writer.guardToString(rhsId);
writer.callStringConcatResult(lhsStrId, rhsStrId);
@ -6392,11 +6392,11 @@ AttachDecision BinaryArithIRGenerator::tryAttachStringObjectConcat() {
// helper can handle lhs or rhs being a string, so long
// as the other is an object.
if (lhs_.isString()) {
writer.guardIsString(lhsId);
writer.guardIsObject(rhsId);
writer.guardToString(lhsId);
writer.guardToObject(rhsId);
} else {
writer.guardIsObject(lhsId);
writer.guardIsString(rhsId);
writer.guardToObject(lhsId);
writer.guardToString(rhsId);
}
writer.callStringObjectConcatResult(lhsId, rhsId);

View File

@ -198,19 +198,19 @@ extern const uint32_t ArgLengths[];
#endif
#define CACHE_IR_OPS(_) /****************************************************/ \
_(GuardIsObject, Id) \
_(GuardToObject, Id) \
_(GuardIsObjectOrNull, Id) \
_(GuardIsNullOrUndefined, Id) \
_(GuardIsNotNullOrUndefined, Id) \
_(GuardIsNull, Id) \
_(GuardIsUndefined, Id) \
_(GuardIsBoolean, Id, Id) \
_(GuardIsString, Id) \
_(GuardIsSymbol, Id) \
_(GuardIsBigInt, Id) \
_(GuardToBoolean, Id, Id) \
_(GuardToString, Id) \
_(GuardToSymbol, Id) \
_(GuardToBigInt, Id) \
_(GuardIsNumber, Id) \
_(GuardIsInt32, Id, Id) \
_(GuardIsInt32Index, Id, Id) \
_(GuardToInt32, Id, Id) \
_(GuardToInt32Index, Id, Id) \
_(GuardType, Id, Byte) \
_(GuardShape, Id, Field) \
_(GuardGroup, Id, Field) \
@ -802,43 +802,43 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
// shouldn't bake in stub values.
StubField readStubFieldForIon(uint32_t offset, StubField::Type type) const;
ObjOperandId guardIsObject(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsObject, val);
ObjOperandId guardToObject(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardToObject, val);
return ObjOperandId(val.id());
}
Int32OperandId guardIsBoolean(ValOperandId val) {
Int32OperandId guardToBoolean(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsBoolean, val);
writeOpWithOperandId(CacheOp::GuardToBoolean, val);
writeOperandId(res);
return res;
}
StringOperandId guardIsString(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsString, val);
StringOperandId guardToString(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardToString, val);
return StringOperandId(val.id());
}
SymbolOperandId guardIsSymbol(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
SymbolOperandId guardToSymbol(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardToSymbol, val);
return SymbolOperandId(val.id());
}
BigIntOperandId guardIsBigInt(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsBigInt, val);
BigIntOperandId guardToBigInt(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardToBigInt, val);
return BigIntOperandId(val.id());
}
Int32OperandId guardIsInt32(ValOperandId val) {
Int32OperandId guardToInt32(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsInt32, val);
writeOpWithOperandId(CacheOp::GuardToInt32, val);
writeOperandId(res);
return res;
}
Int32OperandId guardIsInt32Index(ValOperandId val) {
Int32OperandId guardToInt32Index(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsInt32Index, val);
writeOpWithOperandId(CacheOp::GuardToInt32Index, val);
writeOperandId(res);
return res;
}

View File

@ -1318,7 +1318,7 @@ bool CacheIRCompiler::emitGuardIsNumber() {
return true;
}
bool CacheIRCompiler::emitGuardIsObject() {
bool CacheIRCompiler::emitGuardToObject() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
if (allocator.knownType(inputId) == JSVAL_TYPE_OBJECT) {
@ -1434,7 +1434,7 @@ bool CacheIRCompiler::emitGuardIsObjectOrNull() {
return true;
}
bool CacheIRCompiler::emitGuardIsBoolean() {
bool CacheIRCompiler::emitGuardToBoolean() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
Register output = allocator.defineRegister(masm, reader.int32OperandId());
@ -1456,7 +1456,7 @@ bool CacheIRCompiler::emitGuardIsBoolean() {
return true;
}
bool CacheIRCompiler::emitGuardIsString() {
bool CacheIRCompiler::emitGuardToString() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
if (allocator.knownType(inputId) == JSVAL_TYPE_STRING) {
@ -1472,7 +1472,7 @@ bool CacheIRCompiler::emitGuardIsString() {
return true;
}
bool CacheIRCompiler::emitGuardIsSymbol() {
bool CacheIRCompiler::emitGuardToSymbol() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
if (allocator.knownType(inputId) == JSVAL_TYPE_SYMBOL) {
@ -1488,7 +1488,7 @@ bool CacheIRCompiler::emitGuardIsSymbol() {
return true;
}
bool CacheIRCompiler::emitGuardIsBigInt() {
bool CacheIRCompiler::emitGuardToBigInt() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
if (allocator.knownType(inputId) == JSVAL_TYPE_BIGINT) {
@ -1504,7 +1504,7 @@ bool CacheIRCompiler::emitGuardIsBigInt() {
return true;
}
bool CacheIRCompiler::emitGuardIsInt32() {
bool CacheIRCompiler::emitGuardToInt32() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
Register output = allocator.defineRegister(masm, reader.int32OperandId());
@ -1526,7 +1526,7 @@ bool CacheIRCompiler::emitGuardIsInt32() {
return true;
}
bool CacheIRCompiler::emitGuardIsInt32Index() {
bool CacheIRCompiler::emitGuardToInt32Index() {
JitSpew(JitSpew_Codegen, __FUNCTION__);
ValOperandId inputId = reader.valOperandId();
Register output = allocator.defineRegister(masm, reader.int32OperandId());

View File

@ -20,19 +20,19 @@ class IonCacheIRCompiler;
// The ops below are defined in CacheIRCompiler and codegen is shared between
// BaselineCacheIRCompiler and IonCacheIRCompiler.
#define CACHE_IR_SHARED_OPS(_) \
_(GuardIsObject) \
_(GuardToObject) \
_(GuardIsNullOrUndefined) \
_(GuardIsNotNullOrUndefined) \
_(GuardIsNull) \
_(GuardIsUndefined) \
_(GuardIsObjectOrNull) \
_(GuardIsBoolean) \
_(GuardIsString) \
_(GuardIsSymbol) \
_(GuardIsBigInt) \
_(GuardToBoolean) \
_(GuardToString) \
_(GuardToSymbol) \
_(GuardToBigInt) \
_(GuardIsNumber) \
_(GuardIsInt32) \
_(GuardIsInt32Index) \
_(GuardToInt32) \
_(GuardToInt32Index) \
_(GuardType) \
_(GuardClass) \
_(GuardGroupHasUnanalyzedNewScript) \

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 0; height: 100px; border: solid green 100px; background-color: green; clip-path: circle(at top 100px center);"></div>
<div style="width: 0; height: 100px; border: solid green 100px; background-color: green; clip-path: circle(at top 100px left 50%);"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 200px; height: 200px; background-color: green; clip-path: circle(at bottom 100px center);"></div>
<div style="width: 200px; height: 200px; background-color: green; clip-path: circle(at bottom 100px left 50%);"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 100px; height: 0; border: solid green 100px; background-color: green; clip-path: circle(at left 100px center);"></div>
<div style="width: 100px; height: 0; border: solid green 100px; background-color: green; clip-path: circle(at left 100px top 50%);"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 200px; height: 200px; background-color: green; clip-path: circle(at right 100px center);"></div>
<div style="width: 200px; height: 200px; background-color: green; clip-path: circle(at right 100px top 50%);"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 200px; height: 200px; padding-left: 200px; background-color: green; clip-path: circle(at left -100px center) content-box;"></div>
<div style="width: 200px; height: 200px; padding-left: 200px; background-color: green; clip-path: circle(at left -100px top 50%) content-box;"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="padding-right: 200px; width: 0; height: 200px; background-color: green; clip-path: circle(at right -100px center) content-box;"></div>
<div style="padding-right: 200px; width: 0; height: 200px; background-color: green; clip-path: circle(at right -100px top 50%) content-box;"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 200px; height: 200px; padding-top: 200px; background-color: green; clip-path: circle(at top -100px center) content-box;"></div>
<div style="width: 200px; height: 200px; padding-top: 200px; background-color: green; clip-path: circle(at top -100px left 50%) content-box;"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green circle.</p>
<div style="width: 200px; height: 200px; padding-bottom: 200px; background-color: green; clip-path: circle(at bottom -100px center) content-box;"></div>
<div style="width: 200px; height: 200px; padding-bottom: 200px; background-color: green; clip-path: circle(at bottom -100px left 50%) content-box;"></div>
</body>
</html>
</html>

View File

@ -16,6 +16,6 @@
</head>
<body>
<p>The test passes if there is a green horizontal ellipse.</p>
<div style="width: 400px; height: 200px; padding-top: 200px; background-color: green; clip-path: ellipse(closest-side closest-side at top -100px center) content-box;"></div>
<div style="width: 400px; height: 200px; padding-top: 200px; background-color: green; clip-path: ellipse(closest-side closest-side at top -100px left 50%) content-box;"></div>
</body>
</html>
</html>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
<script>
function drawImageToCanvases(imageURI) {

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
<script>
function drawImageToCanvases(imageURI) {

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
<script>
function drawImageToCanvases(imageURI) {

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
<script>
function drawImageToCanvases(imageURI) {

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -41,8 +41,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

View File

@ -40,8 +40,8 @@
.tl { object-position: top 25% left 25% }
.br { object-position: bottom 1px right 2px }
.tc { object-position: top 3px center }
.cr { object-position: center right 25% }
.tc { object-position: top 3px left 50% }
.cr { object-position: top 50% right 25% }
</style>
</head>
<body>

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