mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
4b4656bd47
@ -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
|
||||
) {
|
||||
|
@ -103,6 +103,7 @@ let LEGACY_ACTORS = {
|
||||
},
|
||||
messages: [
|
||||
"AboutLogins:AllLogins",
|
||||
"AboutLogins:UpdateBreaches",
|
||||
"AboutLogins:LoginAdded",
|
||||
"AboutLogins:LoginModified",
|
||||
"AboutLogins:LoginRemoved",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
},
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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) \
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user